phpwordpresswoocommercecheckoutcountry

Disable place order button and display message if XX country NOT selected and cart on checkout page contains particular product in WooCommerce


Does anybody have any idea how to handle such scenario? I want to display an notice message and disable place order button in the checkout page when non XX country has been selected and cart contains a particular product (not deliverable to foreign country).

I could do with the Jquery, but cannot access the Place order button as its form is being refreshed via AJAX everytime I change billing address. This is what I have come so far:

add_action( 'woocommerce_checkout_before_customer_details', 'display_shipping_notice' );
function display_shipping_notice() {
    echo '<div class="shipping-notice woocommerce-error" role="alert" style="display:none">We cannot ship this product to your country. Please remove it from the cart to continue!</div>';
    
}


add_action( 'woocommerce_after_checkout_form', 'show_shipping_notice_js' );
function show_shipping_notice_js(){
    ?>
    <script>
        jQuery(function($){
            var countryCode  = 'LV', // Set the country code (That will display the message)
                countryField = 'select#billing_country'; // The Field selector to target
            
            function showHideShippingNotice( countryCode, countryField ){
                if( $(countryField).val() !== countryCode && $('.shop_table tr').hasClass('id-27733')){
                    $('.shipping-notice').show();                   
                    $('.woocommerce-checkout-payment').hide();
                    
                }
                else {
                    $('.shipping-notice').hide();
                    $('.woocommerce-checkout-payment').show();
                }
            }

            // On Ready (after DOM is loaded)
            showHideShippingNotice( countryCode, countryField );

            // On billing country change (Live event)
            $('form.checkout').on('change', countryField, function() {
                showHideShippingNotice( countryCode, countryField );
            });
        });
    </script>
    <?php
}

function cart_item_class( $class, $values, $values_key ) {
    if ( isset( $values[ 'product_id' ] ) ) {
        $class .= ' id-' . $values[ 'product_id' ];
    }
    return $class;
}
add_filter( 'woocommerce_cart_item_class', 'cart_item_class', 10, 3 );

Solution

  • There is no need to use jQuery or AJAX, also displaying a custom message via a HTML div is not necessary, as this can be done via wc_add_notice() and WooCommerce hook(s).

    In other words, take advantage of WooCommerce functionalities opposite to create it yourself.


    If you want to perform this check only on the checkout page, you can use the woocommerce_order_button_html hook:

    function filter_woocommerce_order_button_text( $button ) {        
        // The targeted product ids
        $targeted_ids = array( 30, 815 );
    
        // Flag
        $found = false;
    
        // Loop through cart items
        foreach ( WC()->cart->get_cart() as $cart_item ) {
            if ( array_intersect( $targeted_ids, array( $cart_item['product_id'], $cart_item['variation_id'] ) ) ) {
                $found = true;
                break;
            }
        }
    
        // True
        if ( $found ) {
            // Get billing country
            $billing_country = WC()->customer->get_billing_country();
        
            // Multiple country codes can be added, separated by a comma
            $countries = array( 'BE', 'LV' );
        
            // Checks if a value NOT exists in an array
            if ( ! in_array( $billing_country, $countries ) ) {
                $style  = 'style="background:Silver !important; color:white !important; cursor: not-allowed !important; text-align:center;"';
                $text   = apply_filters( 'woocommerce_order_button_text', __( 'Place order', 'woocommerce' ) );
                $button = '<a class="button"' . $style . '>' . $text . '</a>';
                
                // Clear all other notices          
                wc_clear_notices();
                
                // Notice
                wc_add_notice( __( 'We cannot ship this product to your country. Please remove it from the cart to continue!', 'woocommerce' ), 'error' ); 
            }
        }
        
        return $button;
    }
    add_filter( 'woocommerce_order_button_html', 'filter_woocommerce_order_button_text', 10, 1 );
    

    Or for a combination of the cart and checkout page you can use the woocommerce_check_cart_items hook:

    function action_woocommerce_check_cart_items() {        
        // The targeted product ids
        $targeted_ids = array( 30, 815 );
    
        // Flag
        $found = false;
    
        // Loop through cart items
        foreach ( WC()->cart->get_cart() as $cart_item ) {
            if ( array_intersect( $targeted_ids, array( $cart_item['product_id'], $cart_item['variation_id'] ) ) ) {
                $found = true;
                break;
            }
        }
    
        // True
        if ( $found ) {
            // Get billing country
            $billing_country = WC()->customer->get_billing_country();
            
            // Multiple country codes can be added, separated by a comma
            $countries = array( 'BE', 'LV' );
        
            // Checks if a value NOT exists in an array
            if ( ! in_array( $billing_country, $countries ) ) {
                // Notice
                wc_add_notice( __( 'We cannot ship this product to your country. Please remove it from the cart to continue!', 'woocommerce' ), 'error' ); 
                
                // Remove proceed to checkout button
                remove_action( 'woocommerce_proceed_to_checkout', 'woocommerce_button_proceed_to_checkout', 20 );
            }
        }
    }   
    add_action( 'woocommerce_check_cart_items' , 'action_woocommerce_check_cart_items', 10, 0 );