David Mood
David Mood

Reputation: 63

Change "no shipping available" message based on selected available shipping country

I'm currently adding the below code in woocommerce/cart/cart-shipping.php to change the no shipping method message for a country that is not in the shipping country list of WooCommerce.

<?php

add_filter( 'woocommerce_cart_no_shipping_available_html', 'custom_no_shipping_available_html' );
add_filter( 'woocommerce_no_shipping_available_html', 'custom_no_shipping_available_html' );

function custom_no_shipping_available_html( $message ) {
    $country = WC()->customer->get_shipping_country();
    if ( !empty( $country ) ) {
        $all_countries  = WC()->countries->get_countries(); 
        return sprintf( "Unfortunately, we don't ship to %s. Please contact our Support if you need any help.", $all_countries[ $country ] );
    }
    return sprintf( "Unfortunately, we don't ship to this location. Please contact our Support if you need any help.", $all_countries[ $country ] );
}
?>

After this piece of code the default code in cart-shipping.php is:

$formatted_destination = isset($formatted_destination) ? $formatted_destination : WC()->countries->get_formatted_address($package['destination'], ', ');
$has_calculated_shipping = !empty($has_calculated_shipping);
$show_shipping_calculator = !empty($show_shipping_calculator);
$calculator_text = '';
?>
<tr class="woocommerce-shipping-totals shipping">
    <th><?php echo wp_kses_post($package_name); ?></th>
    <td data-title="<?php echo esc_attr($package_name); ?>">
        <?php if ($available_methods) : ?>
            <ul id="shipping_method" class="woocommerce-shipping-methods">
                <?php foreach ($available_methods as $method) : ?>
                    <li>
                        <?php
                        if (1 < count($available_methods)) {
                            printf('<input type="radio" name="shipping_method[%1$d]" data-index="%1$d" id="shipping_method_%1$d_%2$s" value="%3$s" class="shipping_method" %4$s />', $index, esc_attr(sanitize_title($method->id)), esc_attr($method->id), checked($method->id, $chosen_method, false)); // WPCS: XSS ok.
                        } else {
                            printf('<input type="hidden" name="shipping_method[%1$d]" data-index="%1$d" id="shipping_method_%1$d_%2$s" value="%3$s" class="shipping_method" />', $index, esc_attr(sanitize_title($method->id)), esc_attr($method->id)); // WPCS: XSS ok.
                        }
                        printf('<label for="shipping_method_%1$s_%2$s">%3$s</label>', $index, esc_attr(sanitize_title($method->id)), wc_cart_totals_shipping_method_label($method)); // WPCS: XSS ok.
                        do_action('woocommerce_after_shipping_rate', $method, $index);
                        ?>
                    </li>
                <?php endforeach; ?>
            </ul>
            <?php if (is_cart()) : ?>
                <p class="woocommerce-shipping-destination">
                    <?php
                    if ($formatted_destination) {
                        // Translators: $s shipping destination.
                        printf(esc_html__('Shipping to %s.', 'woocommerce') . ' ', '<strong>' . esc_html($formatted_destination) . '</strong>');
                        $calculator_text = esc_html__('Change address', 'woocommerce');
                    } else {
                        echo wp_kses_post(apply_filters('woocommerce_shipping_estimate_html', __('Shipping options will be updated during checkout.', 'woocommerce')));
                    }
                    ?>
                </p>
            <?php endif; ?>
            <?php
        elseif (!$has_calculated_shipping || !$formatted_destination) :
            if (is_cart() && 'no' === get_option('woocommerce_enable_shipping_calc')) {
                echo wp_kses_post(apply_filters('woocommerce_shipping_not_enabled_on_cart_html', __('Shipping costs are calculated during checkout.', 'woocommerce')));
            } else {
                echo wp_kses_post(apply_filters('woocommerce_shipping_may_be_available_html', __('Enter your address to view shipping options.', 'woocommerce')));
            }
        elseif (!is_cart()) :
            echo wp_kses_post(apply_filters('woocommerce_no_shipping_available_html', __('There are no shipping options available. Please ensure that your address has been entered correctly, or Please contact our Support if you need any help.', 'woocommerce')));
        else :
            // Translators: $s shipping destination.
            echo wp_kses_post(apply_filters('woocommerce_cart_no_shipping_available_html', sprintf(esc_html__('No shipping options were found for %s.', 'woocommerce') . ' ', '<strong>' . esc_html($formatted_destination) . '</strong>')));
            $calculator_text = esc_html__('Enter a different address', 'woocommerce');
        endif;
        ?>

        <?php if ($show_package_details) : ?>
            <?php echo '<p class="woocommerce-shipping-contents"><small>' . esc_html($package_details) . '</small></p>'; ?>
        <?php endif; ?>

        <?php if ($show_shipping_calculator) : ?>
            <?php woocommerce_shipping_calculator($calculator_text); ?>
        <?php endif; ?>
    </td>
</tr>

But the problem is that I have to complete all the billing address fields including phone and zip code to get my message that the selected country is not supported.

I think this happens because by default WooCommerce is checking the $formatted_destination variable set in the same PHP file.

My question is how can I have the message in a way that is directly shown once the country is selected and it is not part of the shipping country?

Upvotes: 3

Views: 2854

Answers (1)

7uc1f3r
7uc1f3r

Reputation: 29650

To answer your question, first some explanation. I copied a piece of code from templates/cart/cart-shipping.php line 66 - 72 @version 3.6.0

elseif ( ! is_cart() ) :
    echo wp_kses_post( apply_filters( 'woocommerce_no_shipping_available_html', __( 'There are no shipping options available. Please ensure that your address has been entered correctly, or contact us if you need any help.', 'woocommerce' ) ) );
else :
    // Translators: $s shipping destination.
    echo wp_kses_post( apply_filters( 'woocommerce_cart_no_shipping_available_html', sprintf( esc_html__( 'No shipping options were found for %s.', 'woocommerce' ) . ' ', '<strong>' . esc_html( $formatted_destination ) . '</strong>' ) ) );
    $calculator_text = esc_html__( 'Enter a different address', 'woocommerce' );
endif;

As you can see this contains 2 filters hook, namely:

  • woocommerce_no_shipping_available_html
  • woocommerce_cart_no_shipping_available_html

While the second hook, in the message shows $formatted_destination, the first one doesn't.


So to answer your question, you can use the hooks like this:

The message displayed on the cart page

function filter_woocommerce_cart_no_shipping_available_html( $sprintf ) {
    // Get packages
    $packages = WC()->shipping()->get_packages();
    
    // Loop through
    foreach ( $packages as $i => $package ) {
        $formatted_destination = WC()->countries->get_formatted_address( $package['destination'], ', ' );
    }

    // Message
    $sprintf = sprintf( esc_html__( 'Unfortunately, we don\'t ship to %s. Please contact our Support if you need any help.', 'woocommerce' ) . ' ', '<strong>' . esc_html( $formatted_destination ) . '</strong>' );

    return $sprintf;
}
add_filter( 'woocommerce_cart_no_shipping_available_html', 'filter_woocommerce_cart_no_shipping_available_html', 10, 1 );

The message displayed on the checkout page

function filter_woocommerce_no_shipping_available_html( $html ) {
    // Message
    $html = __( 'My new message', 'woocommerce' ) 
    
    return $html;
}
add_filter( 'woocommerce_no_shipping_available_html', 'filter_woocommerce_no_shipping_available_html', 10, 1 );

With both answers there is no need to modify/overwrite template files, code goes in functions.php file of the active child theme (or active theme).

Upvotes: 3

Related Questions