diff --git a/gateway-payfast.php b/gateway-payfast.php index 5e835a4..6939080 100644 --- a/gateway-payfast.php +++ b/gateway-payfast.php @@ -11,7 +11,10 @@ * WC tested up to: 8.3 * WC requires at least: 8.1 * Requires PHP: 7.3 + * + * @package WooCommerce Gateway Payfast */ + use Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry; defined( 'ABSPATH' ) || exit; @@ -22,6 +25,7 @@ /** * Initialize the gateway. + * * @since 1.0.0 */ function woocommerce_payfast_init() { @@ -29,18 +33,26 @@ function woocommerce_payfast_init() { return; } - require_once( plugin_basename( 'includes/class-wc-gateway-payfast.php' ) ); - require_once( plugin_basename( 'includes/class-wc-gateway-payfast-privacy.php' ) ); + require_once plugin_basename( 'includes/class-wc-gateway-payfast.php' ); + require_once plugin_basename( 'includes/class-wc-gateway-payfast-privacy.php' ); load_plugin_textdomain( 'woocommerce-gateway-payfast', false, trailingslashit( dirname( plugin_basename( __FILE__ ) ) ) ); add_filter( 'woocommerce_payment_gateways', 'woocommerce_payfast_add_gateway' ); } add_action( 'plugins_loaded', 'woocommerce_payfast_init', 0 ); +/** + * Add links to the plugin action links. + * + * @since 1.4.13 + * + * @param array $links Plugin action links. + * @return array Modified plugin action links. + */ function woocommerce_payfast_plugin_links( $links ) { $settings_url = add_query_arg( array( - 'page' => 'wc-settings', - 'tab' => 'checkout', + 'page' => 'wc-settings', + 'tab' => 'checkout', 'section' => 'wc_gateway_payfast', ), admin_url( 'admin.php' ) @@ -59,7 +71,11 @@ function woocommerce_payfast_plugin_links( $links ) { /** * Add the gateway to WooCommerce + * * @since 1.0.0 + * + * @param string[] $methods WooCommerce payment methods. + * @return string[] Modified payment methods to include Payfast. */ function woocommerce_payfast_add_gateway( $methods ) { $methods[] = 'WC_Gateway_PayFast'; @@ -68,13 +84,18 @@ function woocommerce_payfast_add_gateway( $methods ) { add_action( 'woocommerce_blocks_loaded', 'woocommerce_payfast_woocommerce_blocks_support' ); +/** + * Add the gateway to WooCommerce Blocks. + * + * @since 1.4.19 + */ function woocommerce_payfast_woocommerce_blocks_support() { if ( class_exists( 'Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType' ) ) { require_once dirname( __FILE__ ) . '/includes/class-wc-gateway-payfast-blocks-support.php'; add_action( 'woocommerce_blocks_payment_method_type_registration', function( Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry $payment_method_registry ) { - $payment_method_registry->register( new WC_PayFast_Blocks_Support ); + $payment_method_registry->register( new WC_PayFast_Blocks_Support() ); } ); } diff --git a/includes/class-wc-gateway-payfast-blocks-support.php b/includes/class-wc-gateway-payfast-blocks-support.php index 6469d32..a627935 100644 --- a/includes/class-wc-gateway-payfast-blocks-support.php +++ b/includes/class-wc-gateway-payfast-blocks-support.php @@ -1,4 +1,10 @@ settings = get_option( 'woocommerce_payfast_settings', [] ); + $this->settings = get_option( 'woocommerce_payfast_settings', array() ); } /** @@ -27,8 +33,8 @@ public function initialize() { * @return boolean */ public function is_active() { - $payment_gateways_class = WC()->payment_gateways(); - $payment_gateways = $payment_gateways_class->payment_gateways(); + $payment_gateways_class = WC()->payment_gateways(); + $payment_gateways = $payment_gateways_class->payment_gateways(); return $payment_gateways['payfast']->is_available(); } @@ -41,7 +47,7 @@ public function is_active() { public function get_payment_method_script_handles() { $asset_path = WC_GATEWAY_PAYFAST_PATH . '/build/index.asset.php'; $version = WC_GATEWAY_PAYFAST_VERSION; - $dependencies = []; + $dependencies = array(); if ( file_exists( $asset_path ) ) { $asset = require $asset_path; $version = is_array( $asset ) && isset( $asset['version'] ) @@ -62,7 +68,7 @@ public function get_payment_method_script_handles() { 'wc-payfast-blocks-integration', 'woocommerce-gateway-payfast' ); - return [ 'wc-payfast-blocks-integration' ]; + return array( 'wc-payfast-blocks-integration' ); } /** @@ -71,12 +77,12 @@ public function get_payment_method_script_handles() { * @return array */ public function get_payment_method_data() { - return [ + return array( 'title' => $this->get_setting( 'title' ), 'description' => $this->get_setting( 'description' ), 'supports' => $this->get_supported_features(), 'logo_url' => WC_GATEWAY_PAYFAST_URL . '/assets/images/icon.png', - ]; + ); } /** diff --git a/includes/class-wc-gateway-payfast-privacy.php b/includes/class-wc-gateway-payfast-privacy.php index 67c76c4..0ed8540 100644 --- a/includes/class-wc-gateway-payfast-privacy.php +++ b/includes/class-wc-gateway-payfast-privacy.php @@ -1,12 +1,20 @@ 'payfast', 'limit' => 10, 'page' => $page, @@ -48,15 +57,16 @@ protected function get_payfast_orders( $email_address, $page ) { /** * Gets the message of the privacy to display. - * */ public function get_privacy_message() { - return wpautop( sprintf( + return wpautop( + sprintf( /* translators: 1: anchor tag 2: closing anchor tag */ - esc_html__( 'By using this extension, you may be storing personal data or sharing data with an external service. %1$sLearn more about how this works, including what you may want to include in your privacy policy.%2$s', 'woocommerce-gateway-payfast' ), + esc_html__( 'By using this extension, you may be storing personal data or sharing data with an external service. %1$sLearn more about how this works, including what you may want to include in your privacy policy.%2$s', 'woocommerce-gateway-payfast' ), '', '' - ) ); + ) + ); } /** @@ -113,7 +123,7 @@ public function subscriptions_data_exporter( $email_address, $page = 1 ) { $data_to_export = array(); $meta_query = array( - 'relation' => 'AND', + 'relation' => 'AND', array( 'key' => '_payment_method', 'value' => 'payfast', @@ -126,10 +136,11 @@ public function subscriptions_data_exporter( $email_address, $page = 1 ) { ), ); - $subscription_query = array( - 'posts_per_page' => 10, - 'page' => $page, - 'meta_query' => $meta_query, + $subscription_query = array( + 'posts_per_page' => 10, + 'page' => $page, + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query + 'meta_query' => $meta_query, ); $subscriptions = wcs_get_subscriptions( $subscription_query ); @@ -179,17 +190,17 @@ public function order_data_eraser( $email_address, $page ) { $order = wc_get_order( $order->get_id() ); list( $removed, $retained, $msgs ) = $this->maybe_handle_order( $order ); - $items_removed |= $removed; - $items_retained |= $retained; - $messages = array_merge( $messages, $msgs ); + $items_removed |= $removed; + $items_retained |= $retained; + $messages = array_merge( $messages, $msgs ); list( $removed, $retained, $msgs ) = $this->maybe_handle_subscription( $order ); - $items_removed |= $removed; - $items_retained |= $retained; - $messages = array_merge( $messages, $msgs ); + $items_removed |= $removed; + $items_retained |= $retained; + $messages = array_merge( $messages, $msgs ); } - // Tell core if we have more orders to work on still + // Tell core if we have more orders to work on still. $done = count( $orders ) < 10; return array( @@ -203,7 +214,7 @@ public function order_data_eraser( $email_address, $page ) { /** * Handle eraser of data tied to Subscriptions * - * @param WC_Order $order + * @param WC_Order $order Order object. * @return array */ protected function maybe_handle_subscription( $order ) { @@ -223,8 +234,27 @@ protected function maybe_handle_subscription( $order ) { return array( false, false, array() ); } + /** + * Filter privacy eraser subscription statuses. + * + * Modify the subscription statuses that are considered active and should be retained. + * + * @since 1.4.13 + * + * @param string[] $statuses Array of subscription statuses considered active. + */ if ( $subscription->has_status( apply_filters( 'wc_payfast_privacy_eraser_subs_statuses', array( 'on-hold', 'active' ) ) ) ) { - return array( false, true, array( sprintf( esc_html__( 'Order ID %d contains an active Subscription' ), $order->get_id() ) ) ); + return array( + false, + true, + array( + sprintf( + /* translators: %d: Order ID */ + esc_html__( 'Order ID %d contains an active Subscription' ), + $order->get_id() + ), + ), + ); } $renewal_orders = WC_Subscriptions_Renewal_Order::get_renewal_orders( $order->get_id(), 'WC_Order' ); @@ -243,7 +273,9 @@ protected function maybe_handle_subscription( $order ) { /** * Handle eraser of data tied to Orders * - * @param WC_Order $order + * @since 1.4.13 + * + * @param WC_Order $order The order object. * @return array */ protected function maybe_handle_order( $order ) { diff --git a/includes/class-wc-gateway-payfast.php b/includes/class-wc-gateway-payfast.php index 1b2eab2..4c0118d 100644 --- a/includes/class-wc-gateway-payfast.php +++ b/includes/class-wc-gateway-payfast.php @@ -1,16 +1,17 @@ version = WC_GATEWAY_PAYFAST_VERSION; - $this->id = 'payfast'; - $this->method_title = __( 'Payfast', 'woocommerce-gateway-payfast' ); + $this->version = WC_GATEWAY_PAYFAST_VERSION; + $this->id = 'payfast'; + $this->method_title = __( 'Payfast', 'woocommerce-gateway-payfast' ); /* translators: 1: a href link 2: closing href */ - $this->method_description = sprintf( __( 'Payfast works by sending the user to %1$sPayfast%2$s to enter their payment information.', 'woocommerce-gateway-payfast' ), '', '' ); - $this->icon = WP_PLUGIN_URL . '/' . plugin_basename( dirname( dirname( __FILE__ ) ) ) . '/assets/images/icon.png'; - $this->debug_email = get_option( 'admin_email' ); - $this->available_countries = array( 'ZA' ); - $this->available_currencies = (array)apply_filters('woocommerce_gateway_payfast_available_currencies', array( 'ZAR' ) ); + $this->method_description = sprintf( __( 'Payfast works by sending the user to %1$sPayfast%2$s to enter their payment information.', 'woocommerce-gateway-payfast' ), '', '' ); + $this->icon = WP_PLUGIN_URL . '/' . plugin_basename( dirname( __DIR__ ) ) . '/assets/images/icon.png'; + $this->debug_email = get_option( 'admin_email' ); + $this->available_countries = array( 'ZA' ); - // Supported functionality + /** + * Filter available countries for Payfast Gateway. + * + * @since 1.4.13 + * + * @param string[] $available_countries Array of available countries. + */ + $this->available_currencies = (array) apply_filters( 'woocommerce_gateway_payfast_available_currencies', array( 'ZAR' ) ); + + // Supported functionality. $this->supports = array( 'products', 'pre-orders', @@ -50,7 +60,7 @@ public function __construct() { 'subscription_reactivation', 'subscription_amount_changes', 'subscription_date_changes', - 'subscription_payment_method_change', // Subs 1.x support + 'subscription_payment_method_change', // Subs 1.x support. 'subscription_payment_method_change_customer', // Enabled for https://github.com/woocommerce/woocommerce-gateway-payfast/issues/32. ); @@ -68,7 +78,7 @@ public function __construct() { $this->url = 'https://www.payfast.co.za/eng/process?aff=woo-free'; $this->validate_url = 'https://www.payfast.co.za/eng/query/validate'; $this->title = $this->get_option( 'title' ); - $this->response_url = add_query_arg( 'wc-api', 'WC_Gateway_PayFast', home_url( '/' ) ); + $this->response_url = add_query_arg( 'wc-api', 'WC_Gateway_PayFast', home_url( '/' ) ); $this->send_debug_email = 'yes' === $this->get_option( 'send_debug_email' ); $this->description = $this->get_option( 'description' ); $this->enabled = 'yes' === $this->get_option( 'enabled' ) ? 'yes' : 'no'; @@ -92,8 +102,8 @@ public function __construct() { add_action( 'admin_notices', array( $this, 'admin_notices' ) ); // Add fees to order. - add_action( 'woocommerce_admin_order_totals_after_total', array( $this, 'display_order_fee') ); - add_action( 'woocommerce_admin_order_totals_after_total', array( $this, 'display_order_net'), 20 ); + add_action( 'woocommerce_admin_order_totals_after_total', array( $this, 'display_order_fee' ) ); + add_action( 'woocommerce_admin_order_totals_after_total', array( $this, 'display_order_net' ), 20 ); // Change Payment Method actions. add_action( 'woocommerce_subscription_payment_method_updated_from_' . $this->id, array( $this, 'maybe_cancel_subscription_token' ), 10, 2 ); @@ -106,47 +116,47 @@ public function __construct() { */ public function init_form_fields() { $this->form_fields = array( - 'enabled' => array( + 'enabled' => array( 'title' => __( 'Enable/Disable', 'woocommerce-gateway-payfast' ), 'label' => __( 'Enable Payfast', 'woocommerce-gateway-payfast' ), 'type' => 'checkbox', 'description' => __( 'This controls whether or not this gateway is enabled within WooCommerce.', 'woocommerce-gateway-payfast' ), - 'default' => 'no', // User should enter the required information before enabling the gateway. + 'default' => 'no', // User should enter the required information before enabling the gateway. 'desc_tip' => true, ), - 'title' => array( + 'title' => array( 'title' => __( 'Title', 'woocommerce-gateway-payfast' ), 'type' => 'text', 'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce-gateway-payfast' ), 'default' => __( 'Payfast', 'woocommerce-gateway-payfast' ), 'desc_tip' => true, ), - 'description' => array( + 'description' => array( 'title' => __( 'Description', 'woocommerce-gateway-payfast' ), 'type' => 'text', 'description' => __( 'This controls the description which the user sees during checkout.', 'woocommerce-gateway-payfast' ), 'default' => '', 'desc_tip' => true, ), - 'testmode' => array( + 'testmode' => array( 'title' => __( 'Payfast Sandbox', 'woocommerce-gateway-payfast' ), 'type' => 'checkbox', 'description' => __( 'Place the payment gateway in development mode.', 'woocommerce-gateway-payfast' ), 'default' => 'yes', ), - 'merchant_id' => array( + 'merchant_id' => array( 'title' => __( 'Merchant ID', 'woocommerce-gateway-payfast' ), 'type' => 'text', 'description' => __( 'This is the merchant ID, received from Payfast.', 'woocommerce-gateway-payfast' ), 'default' => '', ), - 'merchant_key' => array( + 'merchant_key' => array( 'title' => __( 'Merchant Key', 'woocommerce-gateway-payfast' ), 'type' => 'text', 'description' => __( 'This is the merchant key, received from Payfast.', 'woocommerce-gateway-payfast' ), 'default' => '', ), - 'pass_phrase' => array( + 'pass_phrase' => array( 'title' => __( 'Passphrase', 'woocommerce-gateway-payfast' ), 'type' => 'text', 'description' => __( '* Required. Needed to ensure the data passed through is secure.', 'woocommerce-gateway-payfast' ), @@ -158,13 +168,13 @@ public function init_form_fields() { 'label' => __( 'Send debug e-mails for transactions through the Payfast gateway (sends on successful transaction as well).', 'woocommerce-gateway-payfast' ), 'default' => 'yes', ), - 'debug_email' => array( + 'debug_email' => array( 'title' => __( 'Who Receives Debug E-mails?', 'woocommerce-gateway-payfast' ), 'type' => 'text', 'description' => __( 'The e-mail address to which debugging error e-mails are sent when in test mode.', 'woocommerce-gateway-payfast' ), 'default' => get_option( 'admin_email' ), ), - 'enable_logging' => array( + 'enable_logging' => array( 'title' => __( 'Enable Logging', 'woocommerce-gateway-payfast' ), 'type' => 'checkbox', 'label' => __( 'Enable transaction logging for gateway.', 'woocommerce-gateway-payfast' ), @@ -182,7 +192,7 @@ public function get_required_settings_keys() { return array( 'merchant_id', 'merchant_key', - 'pass_phrase' + 'pass_phrase', ); } @@ -196,7 +206,6 @@ public function needs_setup() { } /** - * add_testmode_admin_settings_notice() * Add a notice to the merchant_key and merchant_id fields when in test mode. * * @since 1.0.0 @@ -207,8 +216,6 @@ public function add_testmode_admin_settings_notice() { } /** - * check_requirements() - * * Check if this gateway is enabled and available in the base currency being traded with. * * @since 1.0.0 @@ -216,16 +223,16 @@ public function add_testmode_admin_settings_notice() { */ public function check_requirements() { - $errors = [ - // Check if the store currency is supported by Payfast - ! in_array( get_woocommerce_currency(), $this->available_currencies ) ? 'wc-gateway-payfast-error-invalid-currency' : null, - // Check if user entered the merchant ID - 'yes' !== $this->get_option( 'testmode' ) && empty( $this->get_option( 'merchant_id' ) ) ? 'wc-gateway-payfast-error-missing-merchant-id' : null, - // Check if user entered the merchant key + $errors = array( + // Check if the store currency is supported by Payfast. + ! in_array( get_woocommerce_currency(), $this->available_currencies, true ) ? 'wc-gateway-payfast-error-invalid-currency' : null, + // Check if user entered the merchant ID. + 'yes' !== $this->get_option( 'testmode' ) && empty( $this->get_option( 'merchant_id' ) ) ? 'wc-gateway-payfast-error-missing-merchant-id' : null, + // Check if user entered the merchant key. 'yes' !== $this->get_option( 'testmode' ) && empty( $this->get_option( 'merchant_key' ) ) ? 'wc-gateway-payfast-error-missing-merchant-key' : null, - // Check if user entered a pass phrase - 'yes' !== $this->get_option( 'testmode' ) && empty( $this->get_option( 'pass_phrase' ) ) ? 'wc-gateway-payfast-error-missing-pass-phrase' : null - ]; + // Check if user entered a pass phrase. + 'yes' !== $this->get_option( 'testmode' ) && empty( $this->get_option( 'pass_phrase' ) ) ? 'wc-gateway-payfast-error-missing-pass-phrase' : null, + ); return array_filter( $errors ); } @@ -274,38 +281,41 @@ public function admin_options() { * Generate the Payfast button link. * * @since 1.0.0 + * + * @param int $order_id Order ID. + * @return void */ public function generate_payfast_form( $order_id ) { - $order = wc_get_order( $order_id ); - // Construct variables for post + $order = wc_get_order( $order_id ); + // Construct variables for post. $this->data_to_send = array( - // Merchant details + // Merchant details. 'merchant_id' => $this->merchant_id, 'merchant_key' => $this->merchant_key, 'return_url' => esc_url_raw( add_query_arg( 'utm_nooverride', '1', $this->get_return_url( $order ) ) ), 'cancel_url' => $order->get_cancel_order_url(), 'notify_url' => $this->response_url, - // Billing details + // Billing details. 'name_first' => self::get_order_prop( $order, 'billing_first_name' ), 'name_last' => self::get_order_prop( $order, 'billing_last_name' ), 'email_address' => self::get_order_prop( $order, 'billing_email' ), - // Item details + // Item details. 'm_payment_id' => ltrim( $order->get_order_number(), _x( '#', 'hash before order number', 'woocommerce-gateway-payfast' ) ), 'amount' => $order->get_total(), 'item_name' => get_bloginfo( 'name' ) . ' - ' . $order->get_order_number(), /* translators: 1: blog info name */ 'item_description' => sprintf( esc_html__( 'New order from %s', 'woocommerce-gateway-payfast' ), get_bloginfo( 'name' ) ), - // Custom strings + // Custom strings. 'custom_str1' => self::get_order_prop( $order, 'order_key' ), 'custom_str2' => 'WooCommerce/' . WC_VERSION . '; ' . get_site_url(), 'custom_str3' => self::get_order_prop( $order, 'id' ), 'source' => 'WooCommerce-Free-Plugin', ); - /** + /* * Check If changing payment method. * We have to generate Tokenization (ad-hoc) token to charge future payments. */ @@ -314,7 +324,7 @@ public function generate_payfast_form( $order_id ) { $this->data_to_send['subscription_type'] = '2'; } - // add subscription parameters + // Add subscription parameters. if ( $this->order_contains_subscription( $order_id ) ) { // 2 == ad-hoc subscription type see Payfast API docs $this->data_to_send['subscription_type'] = '2'; @@ -324,7 +334,7 @@ public function generate_payfast_form( $order_id ) { $subscriptions = wcs_get_subscriptions_for_renewal_order( $order_id ); $current = reset( $subscriptions ); // For renewal orders that have subscriptions with renewal flag OR - // For renew orders which are failed to pay by other payment gateway buy now payinh using Payfast. + // For renew orders which are failed to pay by other payment gateway buy now paying using Payfast. // we will create a new subscription in Payfast and link it to the existing ones in WC. // The old subscriptions in Payfast will be cancelled once we handle the itn request. if ( count( $subscriptions ) > 0 && ( $this->_has_renewal_flag( $current ) || $this->id !== $current->get_payment_method() ) ) { @@ -336,8 +346,10 @@ public function generate_payfast_form( $order_id ) { // pre-order: add the subscription type for pre order that require tokenization // at this point we assume that the order pre order fee and that // we should only charge that on the order. The rest will be charged later. - if ( $this->order_contains_pre_order( $order_id ) - && $this->order_requires_payment_tokenization( $order_id ) ) { + if ( + $this->order_contains_pre_order( $order_id ) + && $this->order_requires_payment_tokenization( $order_id ) + ) { $this->data_to_send['amount'] = $this->get_pre_order_fee( $order_id ); $this->data_to_send['subscription_type'] = '2'; } @@ -353,33 +365,37 @@ public function generate_payfast_form( $order_id ) { $this->data_to_send = apply_filters( 'woocommerce_gateway_payfast_payment_data_to_send', $this->data_to_send, $order_id ); $payfast_args_array = array(); - $sign_strings = []; + $sign_strings = array(); foreach ( $this->data_to_send as $key => $value ) { - if ($key !== 'source') { - $sign_strings[] = esc_attr( $key ) . '=' . urlencode(str_replace('&', '&', trim( $value ))); + if ( 'source' !== $key ) { + // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.urlencode_urlencode -- legacy code, validation required prior to switching to rawurlencode. + $sign_strings[] = esc_attr( $key ) . '=' . urlencode( str_replace( '&', '&', trim( $value ) ) ); } $payfast_args_array[] = ''; } - if (!empty($this->pass_phrase)) { - $payfast_args_array[] = ''; + if ( ! empty( $this->pass_phrase ) ) { + // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.urlencode_urlencode -- legacy code, validation required prior to switching to rawurlencode. + $payfast_args_array[] = ''; } else { - $payfast_args_array[] = ''; + $payfast_args_array[] = ''; } - echo '
- ' . implode( '', $payfast_args_array ) . ' - - '; + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped in foreach loop above. + echo implode( '', $payfast_args_array ); + echo ' + + ' . - esc_html__( 'Cancel order & restore cart', 'woocommerce-gateway-payfast' ) . + esc_html__( 'Cancel order & restore cart', 'woocommerce-gateway-payfast' ) . '