Where should I be hooking in my zip code validation on the cart page in Woocommerce?

I have written custom zip code validation that calls Google Maps API to set the user’s city and state as well as zip code in the user meta when only the zip code input is enabled on the cart page’s shipping calculator. The code works.

However, I am struggling with what hook to add the action. I have used several hooks, including my own custom hook, and I get the following behaviors:

This is what the screen looks like before trying to change the zip code:

This is what the screen looks like entering the new zip code:

If the action is added to the woocommerce_before_shipping_calculator hook (which is triggered in shipping-calculator.php):

After clicking update, the post data in the request with the user-entered zip code is correct, the Google data is retrieved and the meta is updated. BUT the cart’s shipping calculator shows as if no zip code is in the user meta. Here is the image:

BUT we know the meta data is there, because when I force a refresh of the page in the browser right after, the correct zip code from the user meta set in my functions.php function attached to the hook shows up:

This makes some sense to me because the formatted destination is written in cart-shipping.php before the calculator is loaded. So I believe I need to run my custom validation code BEFORE shipping-calculator.php is loaded.

If the action is added to the woocommerce_before_cart hook (which is triggered in cart.php) or the woocommerce_cart_totals_before_shipping hook (which is triggered in cart-totals.php):

I was sure woocommerce_cart_totals_before_shipping was the right hook since it is called right before wc_cart_totals_shipping_html() in cart-totals.php, and that function is where the packages are loaded.

BUT after clicking update in both of these cases, the post data from the request is empty (surprise!), so my function can’t call the Google API (since the entered zip code isn’t passed), and therefore, the user meta does not get changed. More confusingly, the resulting screen shows as if there is no zip code entered, but a refresh of the screen reverts to the original zip code:

If I add a custom action to hook onto at the top of cart-shipping.php

Theoretically, my function will be called and should set the user meta right before the formatted destination is loaded for display on the screen, which I believe is what determines if the screen shows a shipping destination or is awaiting a zip code. (See cart-shipping.php code included at the end of this post so you can see where I put the custom action and the logic of the formatted destination for yourself. Note this is my overridden version of the template because I have other logic in there to show a notice to users who may be from out of town but are visiting and could pickup in store.)

In this case, the post data is also empty, with the same behavior as the woocommerce_before_cart hook.

My bottom line confusion

I can’t seem to find where I should include my custom action and/or hook into an existing action so that I can get the correct post data from the shipping update but before the shipping information is loaded. I am contemplating just forcing a refresh of the screen at the end of my function (if I can do that?) but this seems like a terrible way to solve this problem if it is even possible and doesn’t cause an infinite loop.

I am pretty new to woocommerce and wordpress, so please forgive me for my feeble attempt to explain the problem or if I just missed something obvious. Thanks to anyone who has followed this question to this point and can help suggest how to get my code to run in just the right place so the input can be captured and the user meta can be updated before the shipping section on the cart screen is loaded. Thanks!

cart-shipping.php

defined( 'ABSPATH' ) || exit;

do_action('my_custom_action');

$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 ( ! empty( $available_methods ) && is_array( $available_methods ) ) : ?>
            <ul id="shipping_method" class="woocommerce-shipping-methods">
                <?php $visitor = true; ?>
                <?php foreach ( $available_methods as $method ) : ?>
                    <li>
                        <?php
                        if (str_contains($method->id, 'local_pickup')) :
                            $visitor = false;
                        endif;

                        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; ?>
                <?php if ($visitor) : ?>
                    <li>
                        <?php do_action('fabrix_visitor_bopis'); ?>
                    </li>
                <?php endif; ?>
            </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 destination', '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 contact us if you need any help.', 'woocommerce' ) ) );
        else :
            echo wp_kses_post(
                /**
                 * Provides a means of overriding the default 'no shipping available' HTML string.
                 *
                 * @since 3.0.0
                 *
                 * @param string $html                  HTML message.
                 * @param string $formatted_destination The formatted shipping destination.
                 */
                apply_filters(
                    'woocommerce_cart_no_shipping_available_html',
                    // Translators: $s shipping destination.
                    sprintf( esc_html__( 'No shipping options were found for %s.', 'woocommerce' ) . ' ', '<strong>' . esc_html( $formatted_destination ) . '</strong>' ),
                    $formatted_destination
                )
            );
            $calculator_text = esc_html__( 'Enter a different destination', '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>

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật