Search code examples
phpwordpresswoocommercepayment-gatewayhook-woocommerce

woocommerce_available_payment_gateways filter hook triggered multiple times


For some reason when I run the woocommerce_available_payment_gateways filter it runs twice on the checkout page

as a test I make it echo 123123 on the checkout page and it shows 1231235555 (which is in the else statement) <- meaning its running twice and somehow bypassing / meeting both condition

how do I prevent this behavior ?

function selected_custom_checkout_gateways( $available_gateways ) {

    global $woocommerce;

    if(
        
        isset( $_GET[ 'checkoutid' ] ) &&
        $_GET[ 'checkoutid' ] == '50'
    
    ){

        echo 123123;
        unset( $available_gateways[ 'cod' ] ) ;
        unset( $available_gateways[ 'cheque' ] ) ;

        return $available_gateways;
        exit;

    }else{
    
        echo 5555;
    return $available_gateways;
    
    }
}

Condition to filter and see which `IF` statement logic is hitting.

Solution

  • The filter hook woocommerce_available_payment_gateways is triggered multiple times when checkout is loading and on Ajax events too (where $_GET is bypassed). So you need to save early the URL variable in a WC Session variable.

    Try the following:

    // Save the url variable in a WC Session variable
    add_action( 'template_redirect', 'save_checkoutid_as_wc_session_variable' );
    function save_checkoutid_as_wc_session_variable() {
        if( is_checkout() && isset($_GET[ 'checkoutid']) && $_GET['checkoutid' ] == '50' ){
            WC()->session->set('checkout_id', esc_attr($_GET['checkoutid']));
        }
    }
    
    add_filter( 'woocommerce_available_payment_gateways', 'selected_custom_checkout_gateways' );
    function selected_custom_checkout_gateways( $available_gateways ) {
        // Not in backend (admin)
        if( ! is_admin() && isset(WC()->session) ) {
            $checkout_id = WC()->session->get('checkout_id');
    
            if( $checkout_id  == '50' ){
                $code = 123123; // For testing
                unset( $available_gateways[ 'cod' ], $available_gateways[ 'cheque' ] ) ;
            }
            else{
                $code = 5555; // for testing
            }
            
            $debug = "code: {$code} | checkout_id: {$checkout_id}"; // for testing
            error_log($debug); // for testing
        }
        return $available_gateways;
    }
    
    // Remove the WC Session variable once the order is created
    add_action( 'woocommerce_checkout_order_created', 'remove_checkout_id_wc_session_variable' );
    function remove_checkout_id_wc_session_variable() {
        if ( WC()->session->__isset('checkout_id') ){ 
            WC()->session->__unset('checkout_id');
        }
    }
    

    Code goes in functions.php file of your child theme (or in a plugin). It should work now.