Adding a NowPayments plugin (troubleshooting)
-
So I am trying to make a plugin that adds another gateway for NowPayments payment with xmr (monero) cryptocurrency.
https://imgur.com/a/yttNviK some screens from the menus for the plugin. The problem is when I am trying to checkout I get no redirection to the nowpayments site and I get to the confirmation page saying I paid with 0 dollars and the payment method is blank. I get no specific errors either so I definitely need help to get this plugin working. Maybe you can help me?
Here is my code for the ipn handler and I know this works cause I have tested it with postman app and with a curl command.<?php
// Enable error reporting for debugging
error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('log_errors', 1);
ini_set('error_log', '/path/to/php-error.log'); // Update this path
error_log('IPN Handler Started');
// Retrieve the secret key
$secret = 'your-secret-key'; // Ensure this is correct
// Get the raw POST data
$payload = file_get_contents('php://input');
error_log('Received Payload: ' . $payload);
// Get the signature from the headers
$signature = isset($_SERVER['HTTP_X_NOWPAYMENTS_SIG']) ? $_SERVER['HTTP_X_NOWPAYMENTS_SIG'] : '';
error_log('Received Signature: ' . $signature);
// Calculate the expected signature
$calculated_signature = hash_hmac('sha512', $payload, $secret);
error_log('Calculated Signature: ' . $calculated_signature);
// Verify the signature
if ($calculated_signature === $signature) {
error_log('Signature verified successfully.');
// Decode the payload
$data = json_decode($payload, true);
if ($data === null) {
error_log('JSON Decode Error: ' . json_last_error_msg());
} else {
error_log('Decoded Data: ' . print_r($data, true));
// Process the payment status
if (isset($data['status']) && $data['status'] === 'paid') {
error_log('Payment confirmed for order: ' . $data['order_id']);
// Handle the payment logic here
} else {
error_log('Invalid status: ' . $data['status']);
}
}
} else {
error_log('Signature verification failed');
error_log('Received Signature: ' . $signature);
error_log('Calculated Signature: ' . $calculated_signature);
}
// Send response
http_response_code(200);
exit();
?>and here is the main plugin code that probably needs some revising:
<?php
/*
Plugin Name: Paid Memberships Pro - Add NowPayments
Plugin URI: https://example.com
Description: Add NowPayments as a Payment Option for Monero and other cryptocurrencies.
Version: 0.2
Author: Your Name
Author URI: https://example.com
Text Domain: pmpro-add-nowpayments
Domain Path: /languages
*/
// Load plugin text domain
function pmpro_add_nowpayments_i18n() {
load_plugin_textdomain('pmpro-add-nowpayments', false, basename(dirname(__FILE__)) . '/languages');
}
add_action('plugins_loaded', 'pmpro_add_nowpayments_i18n', 10);
// Register plugin styles
function pmpro_add_nowpayments_register_styles() {
wp_register_style('pmpro-add-nowpayments-styles', plugins_url('css/pmpro-add-nowpayments.css', __FILE__));
wp_enqueue_style('pmpro-add-nowpayments-styles');
}
add_action('wp_enqueue_scripts', 'pmpro_add_nowpayments_register_styles');
// Add NowPayments to gateways
function pmproaddnowpayments_pmpro_gateways($gateways) {
$gateways['nowpayments'] = __('NowPayments (Cryptocurrency)', 'pmpro-add-nowpayments');
return $gateways;
}
add_filter('pmpro_gateways', 'pmproaddnowpayments_pmpro_gateways');
add_action('pmpro_checkout_before_payment_information_fields', function() {
global $pmpro_requirebilling;
});
// Log the current billing requirement at checkout
function log_billing_requirement_in_checkout() {
global $pmpro_requirebilling;
error_log('Billing requirement during checkout (before filter): ' . (isset($pmpro_requirebilling) ? $pmpro_requirebilling : 'Not set'));
}
add_action('pmpro_checkout_boxes', 'log_billing_requirement_in_checkout');
// Log billing requirement after filter is applied
function log_billing_requirement($require_billing) {
return $require_billing;
}
add_filter('pmpro_require_billing', 'log_billing_requirement', 15);
function pmproaddnowpayments_disable_billing($require_billing) {
global $gateway, $pmpro_requirebilling;
if ($gateway === 'nowpayments') {
$pmpro_requirebilling = false; // Force it globally here
error_log('Billing requirement set to false for NowPayments.');
return false;
}
return $require_billing;
}
add_filter('pmpro_require_billing', 'pmproaddnowpayments_disable_billing', 50);
function pmproaddnowpayments_set_gateway() {
global $gateway;
// Explicitly retrieve the selected gateway in case it's not set
if (!isset($gateway) || empty($gateway)) {
$gateway = pmpro_getOption("gateway"); // Or another way to retrieve the selected gateway
error_log('Gateway not previously set, retrieved: ' . $gateway);
error_log('Price passed to NowPayments: ' . $amount_to_pay);
error_log('NowPayments data sent: ' . print_r($nowpayments_request, true));
}
}
add_action('pmpro_checkout_before_processing', 'pmproaddnowpayments_set_gateway');
// Force NowPayments gateway to process payment (bypass billing requirement)
function pmproaddnowpayments_checkout_display() {
global $gateway, $pmpro_requirebilling;
error_log('pmproaddnowpayments_checkout_display hook fired, gateway: ' . $gateway);
if ($gateway === 'nowpayments') {
// Force billing to be false here just before rendering checkout
$pmpro_requirebilling = false;
error_log('Billing requirement forced to false during checkout display for NowPayments.');
?>
<fieldset id="pmpro_payment_method" class="<?php echo esc_attr(pmpro_get_element_class('pmpro_form_fieldset', 'pmpro_payment_method')); ?>">
<div class="<?php echo esc_attr(pmpro_get_element_class('pmpro_card')); ?>">
<div class="<?php echo esc_attr(pmpro_get_element_class('pmpro_card_content')); ?>">
<legend class="<?php echo esc_attr(pmpro_get_element_class('pmpro_form_legend')); ?>">
<h2 class="<?php echo esc_attr(pmpro_get_element_class('pmpro_form_heading pmpro_font-large')); ?>">
<?php esc_html_e('Cryptocurrency Payment via NowPayments', 'pmpro-add-nowpayments'); ?>
</h2>
</legend>
<p><?php esc_html_e('You will be redirected to NowPayments to complete the payment.', 'pmpro-add-nowpayments'); ?></p>
</div>
</div>
</fieldset>
<?php
}
}
add_action('pmpro_checkout_boxes', 'pmproaddnowpayments_checkout_display', 10);
// Process the payment with NowPayments
function pmproaddnowpayments_process_payment($order) {
global $gateway;
error_log('Processing payment through NowPayments, gateway: ' . $gateway);
if ($gateway === 'nowpayments') {
error_log('NowPayments gateway detected, processing...');
// Check if the order has a valid ID and total
if (!$order->id) {
$order->code = $order->getRandomCode(); // Generate a new code
$order->saveOrder(); // Save the new order
error_log('Created new order with ID: ' . $order->id);
}
// Validate total
if ($order->total == 0) {
$order->total = pmpro_calculate_membership_cost($order->membership_id);
error_log('Calculated Membership Cost: ' . $order->total);
}
// Save again if necessary
if ($order->id > 0) {
error_log('Order is now valid and being processed. ID: ' . $order->id);
// NowPayments API credentials
$options = get_option('pmpro_add_nowpayments_options');
$api_key = isset($options['api_key']) ? $options['api_key'] : '';
$sandbox_mode = isset($options['sandbox_mode']) ? (bool) $options['sandbox_mode'] : false;
$webhook_url = isset($options['webhook_url']) ? $options['webhook_url'] : '';
error_log('NowPayments API Response: ' . print_r($response, true));
if (empty($api_key)) {
error_log('NowPayments API Key is missing.');
return;
}
$endpoint = $sandbox_mode ? 'https://api-sandbox.nowpayments.io/v1/payment' : 'https://api.nowpayments.io/v1/payment';
// Prepare the request body
$body = array(
'price_amount' => $order->total,
'price_currency' => $order->currency,
'pay_currency' => 'xmr',
'ipn_callback_url' => $webhook_url,
'order_id' => $order->id,
'order_description' => 'Membership Payment',
);
error_log('Request Body: ' . json_encode($body));
$response = wp_remote_post($endpoint, array(
'body' => json_encode($body),
'headers' => array(
'Content-Type' => 'application/json',
'x-api-key' => $api_key
),
));
error_log('Response status: ' . wp_remote_retrieve_response_code($response));
error_log('Response body: ' . wp_remote_retrieve_body($response));
if (is_wp_error($response)) {
error_log('Error response from NowPayments: ' . $response->get_error_message());
return false;
}
$data = json_decode(wp_remote_retrieve_body($response), true);
error_log('API Response: ' . print_r($data, true));
if (isset($data['payment_url'])) {
error_log('Redirecting to NowPayments: ' . $data['payment_url']);
wp_redirect($data['payment_url']); // Redirect to NowPayments
exit; // Ensure script stops here after redirect
} else {
error_log('Failed to retrieve payment URL from NowPayments.');
return false;
}
} else {
error_log('Not NowPayments gateway, skipping.');
}
}
add_action('pmpro_checkout_order', 'pmproaddnowpayments_process_payment', 10);
error_log('pmpro_checkout_order Hook Fired');
}
// Add IPN handler to WordPress
add_action('init', 'pmproaddnowpayments_handle_ipn');
function pmproaddnowpayments_handle_ipn() {
if (isset($_GET['action']) && $_GET['action'] === 'nowpayments_ipn') {
error_log('Received IPN handler request');
$payload = file_get_contents('php://input');
error_log('Raw payload: ' . $payload);
$data = json_decode($payload, true);
error_log('Decoded data: ' . print_r($data, true));
// Get raw POST data
$payload = file_get_contents('php://input');
error_log('Raw payload: ' . $payload);
// Check if payload is empty
if (empty($payload)) {
error_log('Received empty payload');
http_response_code(400); // Bad Request
exit();
}
// Decode JSON payload
$data = json_decode($payload, true);
if (json_last_error() !== JSON_ERROR_NONE) {
error_log('JSON decode error: ' . json_last_error_msg());
http_response_code(400); // Bad Request
exit();
}
// Log headers for debugging
$headers = getallheaders();
error_log('Headers: ' . print_r($headers, true));
// Get secret and signature from headers
$options = get_option('pmpro_add_nowpayments_options');
$secret = isset($options['ipn_token']) ? $options['ipn_token'] : '';
$signature = isset($_SERVER['HTTP_X_NOWPAYMENTS_SIG']) ? $_SERVER['HTTP_X_NOWPAYMENTS_SIG'] : '';
// Log received signature
error_log('Received signature: ' . $signature);
// Sort parameters and generate the expected signature
ksort($data);
$sorted_request_json = json_encode($data);
$calculated_signature = hash_hmac('sha512', $sorted_request_json, $secret);
error_log('Calculated signature: ' . $calculated_signature);
// Verify the IPN request
if ($calculated_signature === $signature) {
if (isset($data['status']) && $data['status'] === 'paid') {
$order_id = $data['order_id'];
// Fetch order and update status
$order = new MemberOrder($order_id);
if ($order) {
$order->status = 'success';
$order->saveOrder();
// Update membership level
pmpro_changeMembershipLevel($order->membership_id, $order->user_id);
error_log('Order marked as success: ' . $order_id);
} else {
error_log('Order not found: ' . $order_id);
}
} else {
error_log('Invalid IPN status: ' . print_r($data, true));
}
} else {
error_log('IPN signature verification failed');
}
// Send acknowledgment
http_response_code(200);
exit();
}
}
// Add menu item for plugin settings
function pmpro_add_nowpayments_menu() {
add_options_page(
'NowPayments Settings',
'NowPayments',
'manage_options',
'pmpro-add-nowpayments',
'pmpro_add_nowpayments_settings_page'
);
}
add_action('admin_menu', 'pmpro_add_nowpayments_menu');
// Display settings page
function pmpro_add_nowpayments_settings_page() {
?>
<div class="wrap">
<h1>NowPayments Settings</h1>
<form method="post" action="options.php">
<?php
settings_fields('pmpro_add_nowpayments_options');
do_settings_sections('pmpro-add-nowpayments');
submit_button();
?>
</form>
</div>
<?php
}
// Register settings
function pmpro_add_nowpayments_settings_init() {
register_setting('pmpro_add_nowpayments_options', 'pmpro_add_nowpayments_options');
add_settings_section(
'pmpro_add_nowpayments_section',
'NowPayments Payment Settings',
null,
'pmpro-add-nowpayments'
);
add_settings_field(
'pmpro_add_nowpayments_api_key',
'NowPayments API Key',
'pmpro_add_nowpayments_api_key_field',
'pmpro-add-nowpayments',
'pmpro_add_nowpayments_section'
);
add_settings_field(
'pmpro_add_nowpayments_ipn_token',
'NowPayments IPN Token',
'pmpro_add_nowpayments_ipn_token_field',
'pmpro-add-nowpayments',
'pmpro_add_nowpayments_section'
);
add_settings_field(
'pmpro_add_nowpayments_webhook_url',
'NowPayments Webhook URL',
'pmpro_add_nowpayments_webhook_url_field',
'pmpro-add-nowpayments',
'pmpro_add_nowpayments_section'
);
}
add_action('admin_init', 'pmpro_add_nowpayments_settings_init');
// Settings fields callback functions
function pmpro_add_nowpayments_api_key_field() {
$options = get_option('pmpro_add_nowpayments_options');
?>
<input type="text" name="pmpro_add_nowpayments_options[api_key]" value="<?php echo isset($options['api_key']) ? esc_attr($options['api_key']) : ''; ?>">
<?php
}
function pmpro_add_nowpayments_ipn_token_field() {
$options = get_option('pmpro_add_nowpayments_options');
?>
<input type="text" name="pmpro_add_nowpayments_options[ipn_token]" value="<?php echo isset($options['ipn_token']) ? esc_attr($options['ipn_token']) : ''; ?>">
<?php
}
function pmpro_add_nowpayments_webhook_url_field() {
$options = get_option('pmpro_add_nowpayments_options');
?>
<input type="text" name="pmpro_add_nowpayments_options[webhook_url]" value="<?php echo isset($options['webhook_url']) ? esc_attr($options['webhook_url']) : ''; ?>">
<?php
}
?>
- You must be logged in to reply to this topic.