In the WooCommerce plugin, the PayPal gateway has recently been updated to capture payment on status change TO either “Processing” or “Completed”.

We want to ONLY allow capture after order status has been updated to COMPLETED.

In order to do this, I have identified that I need to remove an action. The action is location in class-wc-gateway-paypal.php and the code is below:

class WC_Gateway_Paypal extends WC_Payment_Gateway {

/** @var bool Whether or not logging is enabled */
public static $log_enabled = false;

/** @var WC_Logger Logger instance */
public static $log = false;

/**
 * Constructor for the gateway.
 */
public function __construct() {
    $this->id                 = 'paypal';
    $this->has_fields         = false;
    $this->order_button_text  = __( 'Proceed to PayPal', 'woocommerce' );
    $this->method_title       = __( 'PayPal', 'woocommerce' );
    $this->method_description = sprintf( __( 'PayPal Standard sends customers to PayPal to enter their payment information. PayPal IPN requires fsockopen/cURL support to update order statuses after payment. Check the <a href="https://wordpress.stackexchange.com/questions/289769/%s">system status</a> page for more details.', 'woocommerce' ), admin_url( 'admin.php?page=wc-status' ) );
    $this->supports           = array(
        'products',
        'refunds',
    );

    // Load the settings.
    $this->init_form_fields();
    $this->init_settings();

    // Define user set variables.
    $this->title          = $this->get_option( 'title' );
    $this->description    = $this->get_option( 'description' );
    $this->testmode="yes" === $this->get_option( 'testmode', 'no' );
    $this->debug          = 'yes' === $this->get_option( 'debug', 'no' );
    $this->email          = $this->get_option( 'email' );
    $this->receiver_email = $this->get_option( 'receiver_email', $this->email );
    $this->identity_token = $this->get_option( 'identity_token' );

    self::$log_enabled    = $this->debug;

    add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
    add_action( 'woocommerce_order_status_on-hold_to_processing', array( $this, 'capture_payment' ) );

The final line is the action I want to remove.

add_action( 'woocommerce_order_status_on-hold_to_processing', array( $this, 'capture_payment' ) ); 

I have my own plugin that I use to call various functions with. Before I screw something up, I am hoping someone can validate (or correct) the code I plan to use:

add_action( 'woocommerce_order_status_on-hold_to_completed','remove_PaypalCapture_action' );
function remove_PaypalCapture_action(){ 
global $WC_Gateway_Paypal; //get access to the class object instance
remove_action('woocommerce_order_status_on-hold_to_processing', array($WC_Gateway_Paypal, 'capture_payment' )); //DO NOT capture payment upon order change to processing
} 

Will this work, or am I missing something?

2 Answers
2

There are two things that you’ll need in order to remove the action.

  1. The exact instance of WC_Gateway_Paypal
  2. Knowing when the action is added and when it is executed

Without these, it will be difficult, but impossible to remove the action. Getting the instance of WC_Gateway_Paypal should be straightforward.

//* Make sure class-wc-payment-gateways.php is included once
include_once PATH_TO . class-wc-payment-gateways.php;

//* Get the gateways
$gateways = \WC_Payment_Gateways::instance();

//* The class instances are located in the payment_gateways property
$gateways->payment_gateways

The Paypal gateway instance should be in this array. I don’t have WooCommerce installed on this machine right now, so I don’t know exactly how it’s stored. But you should be able to figure it out.

[Added: Thanks to @willington-vega for finding out how WC stores the payment gateways in the array. I’ve updated the get_wc_paypal_payment_gateway() function below with this.]

Fortunately, the action is added at priority 10 to the woocommerce_order_status_on-hold_to_completed hook. What we can do is hook in at an earlier priority and remove the hook.

add_action( 'woocommerce_order_status_on-hold_to_completed', 'remove_PaypalCapture_action', 9 );
function remove_PaypalCapture_action() {
  //* This is where we'll remove the action

  //* Get the instance
  $WC_Paypal_Payment_Gateway = get_wc_paypal_payment_gateway();
  remove_action( 'woocommerce_order_status_on-hold_to_completed', [ $WC_Paypal_Payment_Gateway , 'capture_payment' ] );
}
function get_wc_paypal_payment_gateway() {

  //* Make sure class-wc-payment-gateways.php is included once
  include_once PATH_TO . class-wc-payment-gateways.php;

  //* Return the paypal gateway
  return \WC_Payment_Gateways::instance()->payment_gateways[ 'paypal' ];
}

Leave a Reply

Your email address will not be published. Required fields are marked *