phpwordpresswoocommercecartpostal-code

Restrict some products to be shipped only to specific postcode/zipcode In WooCommerce


In WooCommerce, there is no Plugin by which I can restrict some products can being delivered in some specific Zip Code/PIN code. It means, suppose I have 100 products in my store. Out of them, 10 products will be delivered in only 1 postcode. The rest of the products will be delivered across the country.

I am very new to coding. Please guide how can we do that in functions.php.

add_filter( 'woocommerce_available_payment_gateways' , 'hide_payment_gateway', 20, 1);
function hide_payment_gateway( $gateways ){
    //change whatever amount you want
    if( WC()->checkout->zipcode ≠ 713102 ){
        // then unset the 'cod' key (cod is the unique id of COD Gateway)
        unset( $gateways['cod'] );
        add_action( 'woocommerce_review_order_before_payment', 'COD_exceed_amount_before_paying_notice' );
    }
    return $gateways;
}

function COD_exceed_amount_before_paying_notice() {
    wc_print_notice( __( 'delivery not available', 'woocommerce' ), 'notice' );
}

I got some errors on this code. I need to hide shipping or payment gateways for some products for some product IDs.


Solution

  • Your code is outdated, unadapted and with some mistakes. Try the following instead:

    // Trigger "update checkout" on postcode change
    add_action( 'woocommerce_checkout_init', 'postcode_field_update_checkout_js' );
    function postcode_field_update_checkout_js() {
        wc_enqueue_js( "
            // On postcode change
            $('form.woocommerce-checkout').on('change', '#billing_postcode, #shipping_postcode', function() {
                $(document.body).trigger('update_checkout')
            });
        ");
    }
    
    add_action( 'woocommerce_calculate_totals', 'check_cart_items_for_customer_postcode' );
    function check_cart_items_for_customer_postcode( $cart ) {
        $targeted_postcodes = array('713102'); // The allowed postcodes
        $targeted_product_ids = array( 15, 16, 17, 18, 25); // The product Ids for that postcode
        $product_names = []; // Initializing
    
        // Get customer postcode
        $postcode = WC()->customer->get_shipping_postcode();
        $postcode = empty($postcode) ? WC()->customer->get_billing_postcode() : $postcode;
        $postcode_match = in_array( $postcode, $targeted_postcodes );
    
        // Exit if postcode is not yet defined or if it match
        if ( empty($postcode) || in_array( $postcode, $targeted_postcodes ) ) return; 
    
        // Loop through cart items to collect targeted products
        foreach($cart->get_cart() as $item ) {
            if( in_array( $item['product_id'], $targeted_product_ids ) ) { 
                $product_names[] = $item['data']->get_name(); // Add the product name
            }
        }
    
        if( count($product_names) > 0 ) {
            if ( is_cart() ) {
                remove_action( 'woocommerce_proceed_to_checkout', 'woocommerce_button_proceed_to_checkout', 20 );
            } elseif ( is_checkout() && ! is_wc_endpoint_url() ) {
                add_filter('woocommerce_order_button_html', 'disabled_place_order_button_html');
            }
            wc_clear_notices(); // Clear other existing notices
            // Avoid checkout displaying an error notice
            wc_add_notice( sprintf( __('The products %s can not be shipped to %s postcode.', 'woocommerce'), 
                implode(', ', $product_names), $postcode ), 'error' );
        }
    }
    
    function disabled_place_order_button_html() {
        $order_button_text = __('Place order', 'woocommerce');
        echo '<button type="button" class="button alt disabled" id="place_order_disabled">' . $order_button_text . '</button>';
    }
    

    Code goes in functions.php file of your child theme (or in a plugin). Tested and works.