0
votes

On Woocommerce, I have enabled 2 shipping methods: Free shipping or Flat rate. I have enabled 2 payment methods: Bank transfer (bacs) and PayPal (paypal).

What I want to achieve: If a customer selects PayPal as payment type he should be forced to select "Flat rate" as shipping method. "Free shipping" should be either hidden or greyed out or something like that.

If bank transfer is chosen then both shipping methods should be available.

Any help is appreciated.

2

2 Answers

2
votes

If anyone is interested, I found a solution:

function alter_payment_gateways( $list ){
    // Retrieve chosen shipping options from all possible packages
    $chosen_rates = ( isset( WC()->session ) ) ? WC()->session->get( 'chosen_shipping_methods' ) : array();
    if( in_array( 'free_shipping:1', $chosen_rates ) ) {
        $array_diff = array('WC_Gateway_Paypal');
        $list = array_diff( $list, $array_diff );
    }
    return $list;
}
add_action('woocommerce_payment_gateways', 'alter_payment_gateways');

This code will deactivate PayPal if a customer selects free shipping.

2
votes

Update 2: The following code will disable "free_shipping" shipping method (method ID) when "paypal" is the chosen payment method:

add_filter( 'woocommerce_package_rates', 'shipping_methods_based_on_chosen_payment', 100, 2 );
function shipping_methods_based_on_chosen_payment( $rates, $package ) {
    // Checking if "paypal" is the chosen payment method
    if ( WC()->session->get( 'chosen_payment_method' ) === 'paypal' ) {
        // Loop through shipping methods rates
        foreach( $rates as $rate_key => $rate ){
            if ( 'free_shipping' === $rate->method_id ) {
                unset($rates[$rate_key]); // Remove 'Free shipping'shipping method
            }
        }
    }
    return $rates;
}

// Enabling, disabling and refreshing session shipping methods data
add_action( 'woocommerce_checkout_update_order_review', 'refresh_shipping_methods', 10, 1 );
function refresh_shipping_methods( $post_data ){
    $bool = true;
    if ( WC()->session->get('chosen_payment_method' ) ) $bool = false;

    // Mandatory to make it work with shipping methods
    foreach ( WC()->cart->get_shipping_packages() as $package_key => $package ){
        WC()->session->set( 'shipping_for_package_' . $package_key, $bool );
    }
    WC()->cart->calculate_shipping();
}

// Jquery script for checkout page
add_action('wp_footer', 'refresh_checkout_on_payment_method_change' );
function refresh_checkout_on_payment_method_change() {
    // Only checkout page
    if( is_checkout() && ! is_wc_endpoint_url() ):
    ?>
    <script type="text/javascript">
    jQuery(function($){
        // On shipping method change
        $('form.checkout').on( 'change', 'input[name^="payment_method"]', function(){
            $('body').trigger('update_checkout'); // Trigger Ajax checkout refresh
        });
    })
    </script>
    <?php
    endif;
}

Code goes in function.php file of your active child theme (or active theme). Tested and works.

To get the related shipping methods rate IDs, something like flat_rate:12, inspect with your browser code inspector each related radio button attribute name like:

enter image description here


Note: Since WooCommerce new versions changes, sorry, the code doesn't work anymore.