WooCommerce: Add to Cart Without Page Reload Using AJAX

WooCommerce supports AJAX add-to-cart natively for simple products via the add_to_cart button class. For custom cart widgets that need to reflect the updated cart total and item count without a page reload, use the woocommerce_add_to_cart_fragments filter.

Problem: WooCommerce variable and simple product pages redirect to the cart on every "Add to Cart" click, interrupting the user's browsing flow and making it difficult to add multiple items.

Solution: Enable the built-in AJAX add-to-cart option for archive pages in WooCommerce → Settings → Products. For single product pages, register a custom wp_ajax_nopriv_ action — enqueue a script that posts the product ID and variation data, receives the updated cart count in the JSON response, and updates the cart widget without a page reload.

First, enable AJAX add-to-cart for single product pages:

// Ensure AJAX add-to-cart is enabled for single products
add_filter( 'woocommerce_product_single_add_to_cart_text', function() {
    return __( 'Add to cart', 'woocommerce' );
} );

// Optionally enable the AJAX refresh on the shop/archive pages
// (already enabled by default in WooCommerce settings)

Place a dynamic cart link anywhere in your template (header, sidebar, etc.):

// In your template file
?><a class="cart-contents" href="<?php echo esc_url( wc_get_cart_url() ); ?>"
   title="<?php esc_attr_e( 'View your shopping cart', 'woocommerce' ); ?>">
    <?php
    printf(
        _n( '%d item', '%d items', WC()->cart->get_cart_contents_count(), 'woocommerce' ),
        WC()->cart->get_cart_contents_count()
    );
    echo ' — ' . WC()->cart->get_cart_total();
    ?>
</a><?php

Register the fragment so WooCommerce replaces the HTML after every AJAX cart event:

add_filter( 'woocommerce_add_to_cart_fragments', 'refresh_cart_contents_fragment' );

function refresh_cart_contents_fragment( $fragments ) {
    ob_start();
    ?>
    <a class="cart-contents" href="<?php echo esc_url( wc_get_cart_url() ); ?>"
       title="<?php esc_attr_e( 'View your shopping cart', 'woocommerce' ); ?>">
        <?php
        printf(
            _n( '%d item', '%d items', WC()->cart->get_cart_contents_count(), 'woocommerce' ),
            WC()->cart->get_cart_contents_count()
        );
        echo ' — ' . WC()->cart->get_cart_total();
        ?>
    </a>
    <?php
    $fragments['a.cart-contents'] = ob_get_clean();
    return $fragments;
}

NOTE: The CSS selector key in the $fragments array (a.cart-contents) must exactly match the selector of the element in the template. If you change the HTML tag or class name, update the fragment key to match — otherwise WooCommerce will not find the element to replace and the cart widget will appear stuck after adding items.