From d44a92c2a5999cc75bf075e7c4a6b21010a3ffc3 Mon Sep 17 00:00:00 2001 From: Tunbosun Ayinla Date: Wed, 10 Jun 2026 18:35:33 +0400 Subject: [PATCH 1/3] Update Paystack dashboard "API Keys & Webhooks" URL --- .../gateway-five/class-wc-gateway-paystack-five.php | 2 +- .../gateway-four/class-wc-gateway-paystack-four.php | 2 +- .../gateway-one/class-wc-gateway-paystack-one.php | 2 +- .../gateway-three/class-wc-gateway-paystack-three.php | 2 +- .../gateway-two/class-wc-gateway-paystack-two.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/includes/custom-gateways/gateway-five/class-wc-gateway-paystack-five.php b/includes/custom-gateways/gateway-five/class-wc-gateway-paystack-five.php index 02e1793..5728db3 100644 --- a/includes/custom-gateways/gateway-five/class-wc-gateway-paystack-five.php +++ b/includes/custom-gateways/gateway-five/class-wc-gateway-paystack-five.php @@ -58,7 +58,7 @@ public function __construct() { $this->method_title = sprintf( __( 'Paystack - %s', 'woo-paystack' ), $gateway_title ); /* Translators: 1: Paystack Website URL. 2: Paystack Developer Dashboard URL. */ - $this->method_description = sprintf( __( 'Paystack provides merchants with the tools and services needed to accept online payments from local and international customers using Mastercard, Visa, Verve Cards and Bank Accounts. Sign up for a Paystack account, and get your API keys.', 'woo-paystack' ), 'https://paystack.com', 'https://dashboard.paystack.com/#/settings/developer' ); + $this->method_description = sprintf( __( 'Paystack provides merchants with the tools and services needed to accept online payments from local and international customers using Mastercard, Visa, Verve Cards and Bank Accounts. Sign up for a Paystack account, and get your API keys.', 'woo-paystack' ), 'https://paystack.com', 'https://dashboard.paystack.com/#/settings/developers' ); $this->payment_page = $this->get_option( 'payment_page' ); diff --git a/includes/custom-gateways/gateway-four/class-wc-gateway-paystack-four.php b/includes/custom-gateways/gateway-four/class-wc-gateway-paystack-four.php index d1d5755..de2c4ba 100644 --- a/includes/custom-gateways/gateway-four/class-wc-gateway-paystack-four.php +++ b/includes/custom-gateways/gateway-four/class-wc-gateway-paystack-four.php @@ -58,7 +58,7 @@ public function __construct() { $this->method_title = sprintf( __( 'Paystack - %s', 'woo-paystack' ), $gateway_title ); /* Translators: 1: Paystack Website URL. 2: Paystack Developer Dashboard URL. */ - $this->method_description = sprintf( __( 'Paystack provides merchants with the tools and services needed to accept online payments from local and international customers using Mastercard, Visa, Verve Cards and Bank Accounts. Sign up for a Paystack account, and get your API keys.', 'woo-paystack' ), 'https://paystack.com', 'https://dashboard.paystack.com/#/settings/developer' ); + $this->method_description = sprintf( __( 'Paystack provides merchants with the tools and services needed to accept online payments from local and international customers using Mastercard, Visa, Verve Cards and Bank Accounts. Sign up for a Paystack account, and get your API keys.', 'woo-paystack' ), 'https://paystack.com', 'https://dashboard.paystack.com/#/settings/developers' ); $this->payment_page = $this->get_option( 'payment_page' ); diff --git a/includes/custom-gateways/gateway-one/class-wc-gateway-paystack-one.php b/includes/custom-gateways/gateway-one/class-wc-gateway-paystack-one.php index eb2fd9d..876e83a 100644 --- a/includes/custom-gateways/gateway-one/class-wc-gateway-paystack-one.php +++ b/includes/custom-gateways/gateway-one/class-wc-gateway-paystack-one.php @@ -58,7 +58,7 @@ public function __construct() { $this->method_title = sprintf( __( 'Paystack - %s', 'woo-paystack' ), $gateway_title ); /* Translators: 1: Paystack Website URL. 2: Paystack Developer Dashboard URL. */ - $this->method_description = sprintf( __( 'Paystack provides merchants with the tools and services needed to accept online payments from local and international customers using Mastercard, Visa, Verve Cards and Bank Accounts. Sign up for a Paystack account, and get your API keys.', 'woo-paystack' ), 'https://paystack.com', 'https://dashboard.paystack.com/#/settings/developer' ); + $this->method_description = sprintf( __( 'Paystack provides merchants with the tools and services needed to accept online payments from local and international customers using Mastercard, Visa, Verve Cards and Bank Accounts. Sign up for a Paystack account, and get your API keys.', 'woo-paystack' ), 'https://paystack.com', 'https://dashboard.paystack.com/#/settings/developers' ); $this->payment_page = $this->get_option( 'payment_page' ); diff --git a/includes/custom-gateways/gateway-three/class-wc-gateway-paystack-three.php b/includes/custom-gateways/gateway-three/class-wc-gateway-paystack-three.php index 60b21cd..f0e08d3 100644 --- a/includes/custom-gateways/gateway-three/class-wc-gateway-paystack-three.php +++ b/includes/custom-gateways/gateway-three/class-wc-gateway-paystack-three.php @@ -58,7 +58,7 @@ public function __construct() { $this->method_title = sprintf( __( 'Paystack - %s', 'woo-paystack' ), $gateway_title ); /* Translators: 1: Paystack Website URL. 2: Paystack Developer Dashboard URL. */ - $this->method_description = sprintf( __( 'Paystack provides merchants with the tools and services needed to accept online payments from local and international customers using Mastercard, Visa, Verve Cards and Bank Accounts. Sign up for a Paystack account, and get your API keys.', 'woo-paystack' ), 'https://paystack.com', 'https://dashboard.paystack.com/#/settings/developer' ); + $this->method_description = sprintf( __( 'Paystack provides merchants with the tools and services needed to accept online payments from local and international customers using Mastercard, Visa, Verve Cards and Bank Accounts. Sign up for a Paystack account, and get your API keys.', 'woo-paystack' ), 'https://paystack.com', 'https://dashboard.paystack.com/#/settings/developers' ); $this->payment_page = $this->get_option( 'payment_page' ); diff --git a/includes/custom-gateways/gateway-two/class-wc-gateway-paystack-two.php b/includes/custom-gateways/gateway-two/class-wc-gateway-paystack-two.php index 6da5fc1..3bf4124 100644 --- a/includes/custom-gateways/gateway-two/class-wc-gateway-paystack-two.php +++ b/includes/custom-gateways/gateway-two/class-wc-gateway-paystack-two.php @@ -58,7 +58,7 @@ public function __construct() { $this->method_title = sprintf( __( 'Paystack - %s', 'woo-paystack' ), $gateway_title ); /* Translators: 1: Paystack Website URL. 2: Paystack Developer Dashboard URL. */ - $this->method_description = sprintf( __( 'Paystack provides merchants with the tools and services needed to accept online payments from local and international customers using Mastercard, Visa, Verve Cards and Bank Accounts. Sign up for a Paystack account, and get your API keys.', 'woo-paystack' ), 'https://paystack.com', 'https://dashboard.paystack.com/#/settings/developer' ); + $this->method_description = sprintf( __( 'Paystack provides merchants with the tools and services needed to accept online payments from local and international customers using Mastercard, Visa, Verve Cards and Bank Accounts. Sign up for a Paystack account, and get your API keys.', 'woo-paystack' ), 'https://paystack.com', 'https://dashboard.paystack.com/#/settings/developers' ); $this->payment_page = $this->get_option( 'payment_page' ); From 1842eb2b128ec05d602d02b8cd2ed61b34e83ca9 Mon Sep 17 00:00:00 2001 From: Tunbosun Ayinla Date: Wed, 10 Jun 2026 19:02:53 +0400 Subject: [PATCH 2/3] Fix all issues reported by Plugin Check (PCP) --- includes/class-wc-gateway-paystack.php | 207 ++++++++++++------ .../class-wc-gateway-custom-paystack.php | 66 ++++-- woo-paystack.php | 19 +- 3 files changed, 208 insertions(+), 84 deletions(-) diff --git a/includes/class-wc-gateway-paystack.php b/includes/class-wc-gateway-paystack.php index ab365d2..dbc4075 100644 --- a/includes/class-wc-gateway-paystack.php +++ b/includes/class-wc-gateway-paystack.php @@ -15,7 +15,7 @@ class WC_Gateway_Paystack extends WC_Payment_Gateway_CC { /** * Should orders be marked as complete after payment? - * + * * @var bool */ public $autocomplete_order; @@ -185,9 +185,10 @@ class WC_Gateway_Paystack extends WC_Payment_Gateway_CC { * Constructor */ public function __construct() { - $this->id = 'paystack'; - $this->method_title = __( 'Paystack', 'woo-paystack' ); - $this->method_description = sprintf( __( 'Paystack provide merchants with the tools and services needed to accept online payments from local and international customers using Mastercard, Visa, Verve Cards and Bank Accounts. Sign up for a Paystack account, and get your API keys.', 'woo-paystack' ), 'https://paystack.com', 'https://dashboard.paystack.com/#/settings/developer' ); + $this->id = 'paystack'; + $this->method_title = __( 'Paystack', 'woo-paystack' ); + /* translators: 1: Paystack signup URL, 2: Paystack API keys URL. */ + $this->method_description = sprintf( __( 'Paystack provide merchants with the tools and services needed to accept online payments from local and international customers using Mastercard, Visa, Verve Cards and Bank Accounts. Sign up for a Paystack account, and get your API keys.', 'woo-paystack' ), esc_url( 'https://paystack.com' ), esc_url( 'https://dashboard.paystack.com/#/settings/developers' ) ); $this->has_fields = true; $this->payment_page = $this->get_option( 'payment_page' ); @@ -283,7 +284,8 @@ public function is_valid_for_use() { if ( ! in_array( get_woocommerce_currency(), apply_filters( 'woocommerce_paystack_supported_currencies', array( 'NGN', 'USD', 'ZAR', 'GHS', 'KES', 'XOF', 'EGP', 'RWF' ) ) ) ) { - $this->msg = sprintf( __( 'Paystack does not support your store currency. Kindly set it to either NGN (₦), GHS (₵), USD ($), KES (KSh), RWF (R₣), ZAR (R), XOF (CFA), or EGP (E£) here', 'woo-paystack' ), admin_url( 'admin.php?page=wc-settings&tab=general' ) ); + /* translators: %s: WooCommerce general settings URL. */ + $this->msg = sprintf( __( 'Paystack does not support your store currency. Kindly set it to either NGN (₦), GHS (₵), USD ($), KES (KSh), RWF (R₣), ZAR (R), XOF (CFA), or EGP (E£) here', 'woo-paystack' ), esc_url( admin_url( 'admin.php?page=wc-settings&tab=general' ) ) ); return false; @@ -321,13 +323,24 @@ public function get_icon() { */ public function admin_notices() { - if ( $this->enabled == 'no' ) { + if ( 'no' === $this->enabled ) { return; } // Check required fields. if ( ! ( $this->public_key && $this->secret_key ) ) { - echo '

' . sprintf( __( 'Please enter your Paystack merchant details here to be able to use the Paystack WooCommerce plugin.', 'woo-paystack' ), admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=paystack' ) ) . '

'; + echo '

' . wp_kses( + sprintf( + /* translators: %s: Paystack gateway settings URL. */ + __( 'Please enter your Paystack merchant details here to be able to use the Paystack WooCommerce plugin.', 'woo-paystack' ), + esc_url( admin_url( 'admin.php?page=wc-settings&tab=checkout§ion=paystack' ) ) + ), + array( + 'a' => array( + 'href' => array(), + ), + ) + ) . '

'; return; } @@ -340,7 +353,7 @@ public function admin_notices() { */ public function is_available() { - if ( 'yes' == $this->enabled ) { + if ( 'yes' === $this->enabled ) { if ( ! ( $this->public_key && $this->secret_key ) ) { @@ -363,18 +376,39 @@ public function admin_options() { ?> -

+

- here to the URL below
%2$s
', 'woo-paystack' ), 'https://dashboard.paystack.co/#/settings/developer', WC()->api_request_url( 'Tbz_WC_Paystack_Webhook' ) ); ?>
+ + here to the URL below', 'woo-paystack' ), + array( + 'a' => array( + 'href' => array(), + 'target' => array(), + 'rel' => array(), + ), + ) + ), + esc_url( 'https://dashboard.paystack.com/#/settings/developers' ) + ); + ?> +

+

+ api_request_url( 'Tbz_WC_Paystack_Webhook' ) ); ?> +

+ is_valid_for_use() ) { @@ -385,7 +419,14 @@ public function admin_options() { } else { ?> -

: msg; ?>

+

: msg, + array( + 'a' => array( + 'href' => array(), + ), + ) + ); ?>

'', 'desc_tip' => false, 'options' => array( - '' => __( 'Select One', 'woo-paystack' ), - 'inline' => __( 'Popup', 'woo-paystack' ), - 'redirect' => __( 'Redirect', 'woo-paystack' ), + '' => __( 'Select One', 'woo-paystack' ), + 'inline' => __( 'Popup', 'woo-paystack' ), + 'redirect' => __( 'Redirect', 'woo-paystack' ), ), ), 'test_secret_key' => array( @@ -632,7 +673,7 @@ public function init_form_fields() { public function payment_fields() { if ( $this->description ) { - echo wpautop( wptexturize( $this->description ) ); + echo wp_kses_post( wpautop( wptexturize( $this->description ) ) ); } if ( ! is_ssl() ) { @@ -652,19 +693,27 @@ public function payment_fields() { */ public function payment_scripts() { - if ( isset( $_GET['pay_for_order'] ) || ! is_checkout_pay_page() ) { + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only WooCommerce checkout query arg. + $pay_for_order = isset( $_GET['pay_for_order'] ); + + if ( $pay_for_order || ! is_checkout_pay_page() ) { return; } - if ( $this->enabled === 'no' ) { + if ( 'no' === $this->enabled ) { return; } - $order_key = urldecode( $_GET['key'] ); + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- WooCommerce validates this order key against the order below. + $order_key = isset( $_GET['key'] ) ? sanitize_text_field( wp_unslash( $_GET['key'] ) ) : ''; $order_id = absint( get_query_var( 'order-pay' ) ); $order = wc_get_order( $order_id ); + if ( ! $order ) { + return; + } + if ( $this->id !== $order->get_payment_method() ) { return; } @@ -690,7 +739,7 @@ public function payment_scripts() { $the_order_key = $order->get_order_key(); $currency = $order->get_currency(); - if ( $the_order_id == $order_id && $the_order_key == $order_key ) { + if ( $the_order_id === $order_id && $the_order_key === $order_key ) { $paystack_params['email'] = $email; $paystack_params['amount'] = absint( $amount ); @@ -845,14 +894,18 @@ public function admin_scripts() { * @return array|void */ public function process_payment( $order_id ) { - $payment_token = 'wc-' . trim( $this->id ) . '-payment-token'; + $payment_token = 'wc-' . trim( $this->id ) . '-payment-token'; + $posted_payment_token = ''; - // phpcs:ignore WordPress.Security.NonceVerification - if ( isset( $_POST[ $payment_token ] ) && 'new' !== wc_clean( $_POST[ $payment_token ] ) ) { + // phpcs:ignore WordPress.Security.NonceVerification.Missing -- WooCommerce checkout processing verifies the checkout nonce. + if ( isset( $_POST[ $payment_token ] ) ) { + // phpcs:ignore WordPress.Security.NonceVerification.Missing -- WooCommerce checkout processing verifies the checkout nonce. + $posted_payment_token = sanitize_text_field( wp_unslash( $_POST[ $payment_token ] ) ); + } + + if ( $posted_payment_token && 'new' !== $posted_payment_token ) { - // phpcs:ignore WordPress.Security.NonceVerification - $token_id = wc_clean( $_POST[ $payment_token ] ); - $token = \WC_Payment_Tokens::get( $token_id ); + $token = \WC_Payment_Tokens::get( $posted_payment_token ); if ( $token->get_user_id() !== get_current_user_id() ) { @@ -954,7 +1007,7 @@ public function process_redirect_payment_option( $order_id ) { $args = array( 'headers' => $headers, 'timeout' => 60, - 'body' => json_encode( $paystack_params ), + 'body' => wp_json_encode( $paystack_params ), ); $request = wp_remote_post( $paystack_url, $args ); @@ -968,12 +1021,9 @@ public function process_redirect_payment_option( $order_id ) { 'redirect' => $paystack_response->data->authorization_url, ); - } else { - wc_add_notice( __( 'Unable to process payment try again', 'woo-paystack' ), 'error' ); - - return; } + wc_add_notice( __( 'Unable to process payment try again', 'woo-paystack' ), 'error' ); } /** @@ -1042,9 +1092,9 @@ public function process_token_payment( $token, $order_id ) { $order = wc_get_order( $order_id ); - if ( in_array( $order->get_status(), array( 'processing', 'completed', 'on-hold' ) ) ) { + if ( in_array( $order->get_status(), array( 'processing', 'completed', 'on-hold' ), true ) ) { - wp_redirect( $this->get_return_url( $order ) ); + wp_safe_redirect( $this->get_return_url( $order ) ); exit; @@ -1065,6 +1115,7 @@ public function process_token_payment( $token, $order_id ) { $order->add_meta_data( '_transaction_id', $paystack_ref, true ); + /* translators: 1: line break, 2: line break, 3: line break. */ $notice = sprintf( __( 'Thank you for shopping with us.%1$sYour payment transaction was successful, but the amount paid is not the same as the total order amount.%2$sYour order is currently on hold.%3$sKindly contact us for more information regarding your order and payment status.', 'woo-paystack' ), '
', '
', '
' ); $notice_type = 'notice'; @@ -1072,6 +1123,7 @@ public function process_token_payment( $token, $order_id ) { $order->add_order_note( $notice, 1 ); // Add Admin Order Note + /* translators: 1: line break, 2: line break, 3: line break, 4: paid currency symbol, 5: amount paid, 6: order currency symbol, 7: order total, 8: line break, 9: Paystack transaction reference. */ $admin_order_note = sprintf( __( 'Look into this order%1$sThis order is currently on hold.%2$sReason: Amount paid is less than the total order amount.%3$sAmount Paid was %4$s (%5$s) while the total order amount is %6$s (%7$s)%8$sPaystack Transaction Reference: %9$s', 'woo-paystack' ), '
', '
', '
', $currency_symbol, $amount_paid, $currency_symbol, $order_total, '
', $paystack_ref ); $order->add_order_note( $admin_order_note ); @@ -1085,6 +1137,7 @@ public function process_token_payment( $token, $order_id ) { $order->update_meta_data( '_transaction_id', $paystack_ref ); + /* translators: 1: line break, 2: line break, 3: line break. */ $notice = sprintf( __( 'Thank you for shopping with us.%1$sYour payment was successful, but the payment currency is different from the order currency.%2$sYour order is currently on-hold.%3$sKindly contact us for more information regarding your order and payment status.', 'woo-paystack' ), '
', '
', '
' ); $notice_type = 'notice'; @@ -1092,6 +1145,7 @@ public function process_token_payment( $token, $order_id ) { $order->add_order_note( $notice, 1 ); // Add Admin Order Note + /* translators: 1: line break, 2: line break, 3: line break, 4: order currency, 5: order currency symbol, 6: payment currency, 7: payment currency symbol, 8: line break, 9: Paystack transaction reference. */ $admin_order_note = sprintf( __( 'Look into this order%1$sThis order is currently on hold.%2$sReason: Order currency is different from the payment currency.%3$sOrder Currency is %4$s (%5$s) while the payment currency is %6$s (%7$s)%8$sPaystack Transaction Reference: %9$s', 'woo-paystack' ), '
', '
', '
', $order_currency, $currency_symbol, $payment_currency, $gateway_symbol, '
', $paystack_ref ); $order->add_order_note( $admin_order_note ); @@ -1103,7 +1157,8 @@ function_exists( 'wc_reduce_stock_levels' ) ? wc_reduce_stock_levels( $order_id $order->payment_complete( $paystack_ref ); - $order->add_order_note( sprintf( 'Payment via Paystack successful (Transaction Reference: %s)', $paystack_ref ) ); + /* translators: %s: Paystack transaction reference. */ + $order->add_order_note( sprintf( __( 'Payment via Paystack successful (Transaction Reference: %s)', 'woo-paystack' ), $paystack_ref ) ); if ( $this->is_autocomplete_order_enabled( $order ) ) { $order->update_status( 'completed' ); @@ -1126,7 +1181,9 @@ function_exists( 'wc_reduce_stock_levels' ) ? wc_reduce_stock_levels( $order_id if ( ! empty( $paystack_response->message ) ) { - $order_notice = sprintf( __( 'Payment was declined by Paystack. Reason: %s.', 'woo-paystack' ), $paystack_response->message ); + /* translators: %s: Paystack decline reason. */ + $order_notice = sprintf( __( 'Payment was declined by Paystack. Reason: %s.', 'woo-paystack' ), $paystack_response->message ); + /* translators: %s: Paystack decline reason. */ $failed_notice = sprintf( __( 'Payment failed using the saved card. Reason: %s. Kindly use another payment option.', 'woo-paystack' ), $paystack_response->message ); } @@ -1156,8 +1213,6 @@ public function add_payment_method() { wc_add_notice( __( 'You can only add a new card when placing an order.', 'woo-paystack' ), 'error' ); - return; - } /** @@ -1171,15 +1226,16 @@ public function receipt_page( $order_id ) { echo '
'; - echo '

' . __( 'Thank you for your order, please click the button below to pay with Paystack.', 'woo-paystack' ) . '

'; + echo '

' . esc_html__( 'Thank you for your order, please click the button below to pay with Paystack.', 'woo-paystack' ) . '

'; - echo '
'; + echo '
'; if ( ! $this->remove_cancel_order_button ) { - echo ' ' . __( 'Cancel order & restore cart', 'woo-paystack' ) . '
'; + echo ' ' . esc_html__( 'Cancel order & restore cart', 'woo-paystack' ) . ''; } echo '
'; + echo '
'; } @@ -1188,31 +1244,33 @@ public function receipt_page( $order_id ) { */ public function verify_paystack_transaction() { + // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Paystack redirects to this callback without a WordPress nonce; the reference is verified against Paystack. if ( isset( $_REQUEST['paystack_txnref'] ) ) { - $paystack_txn_ref = sanitize_text_field( $_REQUEST['paystack_txnref'] ); + $paystack_txn_ref = sanitize_text_field( wp_unslash( $_REQUEST['paystack_txnref'] ) ); } elseif ( isset( $_REQUEST['reference'] ) ) { - $paystack_txn_ref = sanitize_text_field( $_REQUEST['reference'] ); + $paystack_txn_ref = sanitize_text_field( wp_unslash( $_REQUEST['reference'] ) ); } else { $paystack_txn_ref = false; } + // phpcs:enable WordPress.Security.NonceVerification.Recommended @ob_clean(); if ( $paystack_txn_ref ) { - $paystack_response = $this->get_paystack_transaction( $paystack_txn_ref ); + $paystack_response = $this->get_paystack_transaction( $paystack_txn_ref ); if ( false !== $paystack_response ) { - if ( 'success' == $paystack_response->data->status ) { + if ( 'success' === $paystack_response->data->status ) { $order_details = explode( '_', $paystack_response->data->reference ); $order_id = (int) $order_details[0]; $order = wc_get_order( $order_id ); - if ( in_array( $order->get_status(), array( 'processing', 'completed', 'on-hold' ) ) ) { + if ( in_array( $order->get_status(), array( 'processing', 'completed', 'on-hold' ), true ) ) { - wp_redirect( $this->get_return_url( $order ) ); + wp_safe_redirect( $this->get_return_url( $order ) ); exit; @@ -1233,6 +1291,7 @@ public function verify_paystack_transaction() { $order->add_meta_data( '_transaction_id', $paystack_ref, true ); + /* translators: 1: line break, 2: line break, 3: line break. */ $notice = sprintf( __( 'Thank you for shopping with us.%1$sYour payment transaction was successful, but the amount paid is not the same as the total order amount.%2$sYour order is currently on hold.%3$sKindly contact us for more information regarding your order and payment status.', 'woo-paystack' ), '
', '
', '
' ); $notice_type = 'notice'; @@ -1240,6 +1299,7 @@ public function verify_paystack_transaction() { $order->add_order_note( $notice, 1 ); // Add Admin Order Note + /* translators: 1: line break, 2: line break, 3: line break, 4: paid currency symbol, 5: amount paid, 6: order currency symbol, 7: order total, 8: line break, 9: Paystack transaction reference. */ $admin_order_note = sprintf( __( 'Look into this order%1$sThis order is currently on hold.%2$sReason: Amount paid is less than the total order amount.%3$sAmount Paid was %4$s (%5$s) while the total order amount is %6$s (%7$s)%8$sPaystack Transaction Reference: %9$s', 'woo-paystack' ), '
', '
', '
', $currency_symbol, $amount_paid, $currency_symbol, $order_total, '
', $paystack_ref ); $order->add_order_note( $admin_order_note ); @@ -1255,6 +1315,7 @@ function_exists( 'wc_reduce_stock_levels' ) ? wc_reduce_stock_levels( $order_id $order->update_meta_data( '_transaction_id', $paystack_ref ); + /* translators: 1: line break, 2: line break, 3: line break. */ $notice = sprintf( __( 'Thank you for shopping with us.%1$sYour payment was successful, but the payment currency is different from the order currency.%2$sYour order is currently on-hold.%3$sKindly contact us for more information regarding your order and payment status.', 'woo-paystack' ), '
', '
', '
' ); $notice_type = 'notice'; @@ -1262,6 +1323,7 @@ function_exists( 'wc_reduce_stock_levels' ) ? wc_reduce_stock_levels( $order_id $order->add_order_note( $notice, 1 ); // Add Admin Order Note + /* translators: 1: line break, 2: line break, 3: line break, 4: order currency, 5: order currency symbol, 6: payment currency, 7: payment currency symbol, 8: line break, 9: Paystack transaction reference. */ $admin_order_note = sprintf( __( 'Look into this order%1$sThis order is currently on hold.%2$sReason: Order currency is different from the payment currency.%3$sOrder Currency is %4$s (%5$s) while the payment currency is %6$s (%7$s)%8$sPaystack Transaction Reference: %9$s', 'woo-paystack' ), '
', '
', '
', $order_currency, $currency_symbol, $payment_currency, $gateway_symbol, '
', $paystack_ref ); $order->add_order_note( $admin_order_note ); @@ -1272,6 +1334,7 @@ function_exists( 'wc_reduce_stock_levels' ) ? wc_reduce_stock_levels( $order_id } else { $order->payment_complete( $paystack_ref ); + /* translators: %s: Paystack transaction reference. */ $order->add_order_note( sprintf( __( 'Payment via Paystack successful (Transaction Reference: %s)', 'woo-paystack' ), $paystack_ref ) ); if ( $this->is_autocomplete_order_enabled( $order ) ) { @@ -1288,7 +1351,7 @@ function_exists( 'wc_reduce_stock_levels' ) ? wc_reduce_stock_levels( $order_id } else { - $order_details = explode( '_', $_REQUEST['paystack_txnref'] ); + $order_details = explode( '_', $paystack_txn_ref ); $order_id = (int) $order_details[0]; @@ -1299,12 +1362,12 @@ function_exists( 'wc_reduce_stock_levels' ) ? wc_reduce_stock_levels( $order_id } } - wp_redirect( $this->get_return_url( $order ) ); + wp_safe_redirect( $this->get_return_url( $order ) ); exit; } - wp_redirect( wc_get_page_permalink( 'cart' ) ); + wp_safe_redirect( wc_get_page_permalink( 'cart' ) ); exit; @@ -1315,14 +1378,17 @@ function_exists( 'wc_reduce_stock_levels' ) ? wc_reduce_stock_levels( $order_id */ public function process_webhooks() { - if ( ! array_key_exists( 'HTTP_X_PAYSTACK_SIGNATURE', $_SERVER ) || ( strtoupper( $_SERVER['REQUEST_METHOD'] ) !== 'POST' ) ) { + $request_method = isset( $_SERVER['REQUEST_METHOD'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_METHOD'] ) ) : ''; + $paystack_signature = isset( $_SERVER['HTTP_X_PAYSTACK_SIGNATURE'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_PAYSTACK_SIGNATURE'] ) ) : ''; + + if ( empty( $paystack_signature ) || ( 'POST' !== strtoupper( $request_method ) ) ) { exit; } $json = file_get_contents( 'php://input' ); // validate event do all at once to avoid timing attack. - if ( $_SERVER['HTTP_X_PAYSTACK_SIGNATURE'] !== hash_hmac( 'sha512', $json, $this->secret_key ) ) { + if ( $paystack_signature !== hash_hmac( 'sha512', $json, $this->secret_key ) ) { exit; } @@ -1352,13 +1418,13 @@ public function process_webhooks() { $paystack_txn_ref = $order->get_meta( '_paystack_txn_ref' ); - if ( $paystack_response->data->reference != $paystack_txn_ref ) { + if ( $paystack_response->data->reference !== $paystack_txn_ref ) { exit; } http_response_code( 200 ); - if ( in_array( strtolower( $order->get_status() ), array( 'processing', 'completed', 'on-hold' ), true ) ) { + if ( in_array( $order->get_status(), array( 'processing', 'completed', 'on-hold' ), true ) ) { exit; } @@ -1383,6 +1449,7 @@ public function process_webhooks() { $order->add_meta_data( '_transaction_id', $paystack_ref, true ); + /* translators: 1: line break, 2: line break, 3: line break. */ $notice = sprintf( __( 'Thank you for shopping with us.%1$sYour payment transaction was successful, but the amount paid is not the same as the total order amount.%2$sYour order is currently on hold.%3$sKindly contact us for more information regarding your order and payment status.', 'woo-paystack' ), '
', '
', '
' ); $notice_type = 'notice'; @@ -1390,6 +1457,7 @@ public function process_webhooks() { $order->add_order_note( $notice, 1 ); // Add Admin Order Note. + /* translators: 1: line break, 2: line break, 3: line break, 4: paid currency symbol, 5: amount paid, 6: order currency symbol, 7: order total, 8: line break, 9: Paystack transaction reference. */ $admin_order_note = sprintf( __( 'Look into this order%1$sThis order is currently on hold.%2$sReason: Amount paid is less than the total order amount.%3$sAmount Paid was %4$s (%5$s) while the total order amount is %6$s (%7$s)%8$sPaystack Transaction Reference: %9$s', 'woo-paystack' ), '
', '
', '
', $currency_symbol, $amount_paid, $currency_symbol, $order_total, '
', $paystack_ref ); $order->add_order_note( $admin_order_note ); @@ -1407,6 +1475,7 @@ function_exists( 'wc_reduce_stock_levels' ) ? wc_reduce_stock_levels( $order_id $order->update_meta_data( '_transaction_id', $paystack_ref ); + /* translators: 1: line break, 2: line break, 3: line break. */ $notice = sprintf( __( 'Thank you for shopping with us.%1$sYour payment was successful, but the payment currency is different from the order currency.%2$sYour order is currently on-hold.%3$sKindly contact us for more information regarding your order and payment status.', 'woo-paystack' ), '
', '
', '
' ); $notice_type = 'notice'; @@ -1414,6 +1483,7 @@ function_exists( 'wc_reduce_stock_levels' ) ? wc_reduce_stock_levels( $order_id $order->add_order_note( $notice, 1 ); // Add Admin Order Note. + /* translators: 1: line break, 2: line break, 3: line break, 4: order currency, 5: order currency symbol, 6: payment currency, 7: payment currency symbol, 8: line break, 9: Paystack transaction reference. */ $admin_order_note = sprintf( __( 'Look into this order%1$sThis order is currently on hold.%2$sReason: Order currency is different from the payment currency.%3$sOrder Currency is %4$s (%5$s) while the payment currency is %6$s (%7$s)%8$sPaystack Transaction Reference: %9$s', 'woo-paystack' ), '
', '
', '
', $order_currency, $currency_symbol, $payment_currency, $gateway_symbol, '
', $paystack_ref ); $order->add_order_note( $admin_order_note ); @@ -1425,6 +1495,7 @@ function_exists( 'wc_reduce_stock_levels' ) ? wc_reduce_stock_levels( $order_id $order->payment_complete( $paystack_ref ); + /* translators: %s: Paystack transaction reference. */ $order->add_order_note( sprintf( __( 'Payment via Paystack successful (Transaction Reference: %s)', 'woo-paystack' ), $paystack_ref ) ); WC()->cart->empty_cart(); @@ -1457,7 +1528,7 @@ public function save_card_details( $paystack_response, $user_id, $order_id ) { $save_card = $order->get_meta( '_wc_paystack_save_card' ); - if ( $user_id && $this->saved_cards && $save_card && $paystack_response->data->authorization->reusable && 'card' == $paystack_response->data->authorization->channel ) { + if ( $user_id && $this->saved_cards && $save_card && $paystack_response->data->authorization->reusable && 'card' === $paystack_response->data->authorization->channel ) { $gateway_id = $order->get_payment_method(); @@ -1497,7 +1568,7 @@ public function save_subscription_payment_token( $order_id, $paystack_response ) return; } - if ( $this->order_contains_subscription( $order_id ) && $paystack_response->data->authorization->reusable && 'card' == $paystack_response->data->authorization->channel ) { + if ( $this->order_contains_subscription( $order_id ) && $paystack_response->data->authorization->reusable && 'card' === (string) $paystack_response->data->authorization->channel ) { $auth_code = $paystack_response->data->authorization->authorization_code; $customer_email = $paystack_response->data->customer->email; @@ -1549,7 +1620,7 @@ public function get_custom_fields( $order_id ) { 'variable_name' => 'plugin', 'value' => 'woo-paystack', ); - + if ( $this->custom_metadata ) { if ( $this->meta_order_id ) { @@ -1599,8 +1670,8 @@ public function get_custom_fields( $order_id ) { $products = ''; foreach ( $line_items as $item_id => $item ) { - $name = $item['name']; - $quantity = $item['qty']; + $name = $item['name']; + $quantity = $item['qty']; $products .= $name . ' (Qty: ' . $quantity . ')'; $products .= ' | '; } @@ -1648,7 +1719,6 @@ public function get_custom_fields( $order_id ) { ); } - } return $custom_fields; @@ -1678,12 +1748,13 @@ public function process_refund( $order_id, $amount = null, $reason = '' ) { $order_currency = $order->get_currency(); $transaction_id = $order->get_transaction_id(); - $paystack_response = $this->get_paystack_transaction( $transaction_id ); + $paystack_response = $this->get_paystack_transaction( $transaction_id ); if ( false !== $paystack_response ) { - if ( 'success' == $paystack_response->data->status ) { + if ( 'success' === strtolower( $paystack_response->data->status ) ) { + /* translators: 1: WooCommerce order ID, 2: Site URL. */ $merchant_note = sprintf( __( 'Refund for Order ID: #%1$s on %2$s', 'woo-paystack' ), $order_id, get_site_url() ); $body = array( @@ -1713,27 +1784,25 @@ public function process_refund( $order_id, $amount = null, $reason = '' ) { $refund_response = json_decode( wp_remote_retrieve_body( $refund_request ) ); if ( $refund_response->status ) { - $amount = wc_price( $amount, array( 'currency' => $order_currency ) ); - $refund_id = $refund_response->data->id; + $amount = wc_price( $amount, array( 'currency' => $order_currency ) ); + $refund_id = $refund_response->data->id; + /* translators: 1: Refunded amount, 2: Paystack refund ID, 3: Refund reason. */ $refund_message = sprintf( __( 'Refunded %1$s. Refund ID: %2$s. Reason: %3$s', 'woo-paystack' ), $amount, $refund_id, $reason ); $order->add_order_note( $refund_message ); return true; } - } else { $refund_response = json_decode( wp_remote_retrieve_body( $refund_request ) ); if ( isset( $refund_response->message ) ) { return new WP_Error( 'error', $refund_response->message ); - } else { - return new WP_Error( 'error', __( 'Can't process refund at the moment. Try again later.', 'woo-paystack' ) ); } - } + return new WP_Error( 'error', __( 'Can't process refund at the moment. Try again later.', 'woo-paystack' ) ); + } } - } } @@ -1761,7 +1830,7 @@ protected function is_autocomplete_order_enabled( $order ) { $payment_method = $order->get_payment_method(); - $paystack_settings = get_option('woocommerce_' . $payment_method . '_settings'); + $paystack_settings = get_option( 'woocommerce_' . $payment_method . '_settings' ); if ( isset( $paystack_settings['autocomplete_order'] ) && 'yes' === $paystack_settings['autocomplete_order'] ) { $autocomplete_order = true; diff --git a/includes/custom-gateways/class-wc-gateway-custom-paystack.php b/includes/custom-gateways/class-wc-gateway-custom-paystack.php index 0aeacfd..5cd0ceb 100644 --- a/includes/custom-gateways/class-wc-gateway-custom-paystack.php +++ b/includes/custom-gateways/class-wc-gateway-custom-paystack.php @@ -247,7 +247,7 @@ public function admin_options() {

title ) ); + printf( esc_html__( 'Paystack - %s', 'woo-paystack' ), esc_html( $this->title ) ); ?> here to the URL below', 'woo-paystack' ), 'https://dashboard.paystack.co/#/settings/developer' ); + printf( + wp_kses( + /* translators: %s: Paystack dashboard developer settings URL. */ + __( 'Important: To avoid situations where bad network makes it impossible to verify transactions, set your webhook URL here to the URL below', 'woo-paystack' ), + array( + 'a' => array( + 'href' => array(), + 'target' => array(), + 'rel' => array(), + ), + ) + ), + esc_url( 'https://dashboard.paystack.com/#/settings/developers' ) + ); ?>

@@ -269,8 +281,18 @@ public function admin_options() {

here', 'woo-paystack' ), esc_url( $paystack_settings_url ) ); + printf( + wp_kses( + /* translators: %s: Paystack WooCommerce settings URL. */ + __( 'To configure your Paystack API keys and enable/disable test mode, do that here', 'woo-paystack' ), + array( + 'a' => array( + 'href' => array(), + ), + ) + ), + esc_url( $paystack_settings_url ) + ); ?>

@@ -284,8 +306,18 @@ public function admin_options() { } else { - /* translators: disabled message */ - echo '

' . sprintf( __( 'Paystack Payment Gateway Disabled: %s', 'woo-paystack' ), esc_attr( $this->msg ) ) . '

'; + echo '

' . wp_kses( + sprintf( + /* translators: %s: gateway disabled message. */ + __( 'Paystack Payment Gateway Disabled: %s', 'woo-paystack' ), + $this->msg + ), + array( + 'a' => array( + 'href' => array(), + ), + ) + ) . '

'; } @@ -428,19 +460,27 @@ public function get_icon() { */ public function payment_scripts() { - if ( isset( $_GET['pay_for_order'] ) || ! is_checkout_pay_page() ) { + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only WooCommerce checkout query arg. + $pay_for_order = isset( $_GET['pay_for_order'] ); + + if ( $pay_for_order || ! is_checkout_pay_page() ) { return; } - if ( $this->enabled === 'no' ) { + if ( 'no' === $this->enabled ) { return; } - $order_key = urldecode( $_GET['key'] ); + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- WooCommerce validates this order key against the order below. + $order_key = isset( $_GET['key'] ) ? sanitize_text_field( wp_unslash( $_GET['key'] ) ) : ''; $order_id = absint( get_query_var( 'order-pay' ) ); $order = wc_get_order( $order_id ); + if ( ! $order ) { + return; + } + if ( $this->id !== $order->get_payment_method() ) { return; } @@ -469,7 +509,7 @@ public function payment_scripts() { $the_order_key = $order->get_order_key(); $currency = $order->get_currency(); - if ( $the_order_id == $order_id && $the_order_key == $order_key ) { + if ( $the_order_id === $order_id && $the_order_key === $order_key ) { $paystack_params['email'] = $email; $paystack_params['amount'] = absint( $amount ); @@ -611,7 +651,7 @@ public function payment_scripts() { */ public function add_gateway_to_checkout( $available_gateways ) { - if ( $this->enabled == 'no' ) { + if ( 'no' === $this->enabled ) { unset( $available_gateways[ $this->id ] ); } @@ -626,7 +666,7 @@ public function add_gateway_to_checkout( $available_gateways ) { */ public function is_available() { - if ( 'yes' == $this->enabled ) { + if ( 'yes' === $this->enabled ) { if ( ! ( $this->public_key && $this->secret_key ) ) { diff --git a/woo-paystack.php b/woo-paystack.php index 1ac0f2b..2e644d2 100644 --- a/woo-paystack.php +++ b/woo-paystack.php @@ -70,7 +70,7 @@ function tbz_wc_paystack_init() { function tbz_woo_paystack_plugin_action_links( $links ) { $settings_link = array( - 'settings' => '' . __( 'Settings', 'woo-paystack' ) . '', + 'settings' => '' . esc_html__( 'Settings', 'woo-paystack' ) . '', ); return array_merge( $settings_link, $links ); @@ -141,7 +141,22 @@ function tbz_wc_add_paystack_gateway( $methods ) { * Display a notice if WooCommerce is not installed */ function tbz_wc_paystack_wc_missing_notice() { - echo '

' . sprintf( __( 'Paystack requires WooCommerce to be installed and active. Click %s to install WooCommerce.', 'woo-paystack' ), 'here' ) . '

'; + $install_url = admin_url( 'plugin-install.php?tab=plugin-information&plugin=woocommerce&TB_iframe=true&width=772&height=539' ); + $install_link = '' . esc_html__( 'here', 'woo-paystack' ) . ''; + + echo '

' . wp_kses( + sprintf( + /* translators: %s: WooCommerce plugin install link. */ + __( 'Paystack requires WooCommerce to be installed and active. Click %s to install WooCommerce.', 'woo-paystack' ), + $install_link + ), + array( + 'a' => array( + 'href' => array(), + 'class' => array(), + ), + ) + ) . '

'; } /** From 4a8e564fd9f15351ced0d0dd7ba1836c2ea38696 Mon Sep 17 00:00:00 2001 From: Tunbosun Ayinla Date: Wed, 10 Jun 2026 19:29:31 +0400 Subject: [PATCH 3/3] Update WC_Gateway_Paystack class --- includes/class-wc-gateway-paystack.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/class-wc-gateway-paystack.php b/includes/class-wc-gateway-paystack.php index dbc4075..b3d7dda 100644 --- a/includes/class-wc-gateway-paystack.php +++ b/includes/class-wc-gateway-paystack.php @@ -1568,7 +1568,7 @@ public function save_subscription_payment_token( $order_id, $paystack_response ) return; } - if ( $this->order_contains_subscription( $order_id ) && $paystack_response->data->authorization->reusable && 'card' === (string) $paystack_response->data->authorization->channel ) { + if ( $this->order_contains_subscription( $order_id ) && $paystack_response->data->authorization->reusable && 'card' === $paystack_response->data->authorization->channel ) { $auth_code = $paystack_response->data->authorization->authorization_code; $customer_email = $paystack_response->data->customer->email; @@ -1752,7 +1752,7 @@ public function process_refund( $order_id, $amount = null, $reason = '' ) { if ( false !== $paystack_response ) { - if ( 'success' === strtolower( $paystack_response->data->status ) ) { + if ( 'success' === $paystack_response->data->status ) { /* translators: 1: WooCommerce order ID, 2: Site URL. */ $merchant_note = sprintf( __( 'Refund for Order ID: #%1$s on %2$s', 'woo-paystack' ), $order_id, get_site_url() );