WOOT - WooCommerce Active Products Tables

WooCommerce product table mini cart not updating after add to cart

The WooCommerce mini cart not updating after Add to cart in a product table is a display problem, not a cart problem. The table shows Product added to cart!, the cart page lists the product, but the counter in the header, the theme's mini cart or the side cart still shows the old state until the page is reloaded. The product is in the cart; the theme's cart simply did not hear about it. Below is what the table does when a product is added, how to find out in a few minutes why your cart does not react, and a footer script that updates it and opens side carts the way WooCommerce's own buttons do.

What happens when a product is added from the table

The table's Add to cart button uses WooCommerce's own endpoint, the same one the AJAX buttons on the shop page use:

  1. The browser sends a POST request to ?wc-ajax=add_to_cart with the product ID and the quantity. WooCommerce adds the product and answers with fresh cart fragments: pieces of HTML for every cart element on the page, keyed by their CSS selector, plus a cart_hash.
  2. The table shows its message and fires the JavaScript event woot-added-to-cart on document.
  3. It reloads its own cart information (the table cart panel, the counters on the buttons) and fires woot-woo-cart-refreshed.
  4. It triggers WooCommerce's wc_fragment_refresh event, which asks WooCommerce's cart fragments script to fetch the fragments again and replace the cart elements on the page.

The add selected button in the column header adds all checked products in one request to admin-ajax.php and then does steps 3 and 4.

The difference from the shop page buttons is in the last step. Those buttons take the fragments from the answer, replace the cart elements directly and announce the purchase with WooCommerce's standard added_to_cart event, which side cart plugins and WooCommerce's Mini-Cart block listen to. The table relies on wc_fragment_refresh instead, and that event does something only when the cart fragments script (wc-cart-fragments) is on the page. Current WooCommerce versions load that script only where it is needed, for example with the classic Cart widget; many themes with their own header cart load it themselves, some do not. So the mini cart stays unchanged in four situations:

  • the theme's cart is updated through fragments, but the cart fragments script is not loaded on the table page;
  • the side cart or mini cart reacts only to added_to_cart: it opens and updates after a shop button, never after the table;
  • the theme's counter is not a fragment at all, so only a page reload changes it;
  • a page cache serves HTML with an old cart, so even a reload shows the old count.

Find the reason in five minutes

Open the table page in a private window, where you are logged out, and open the developer tools (F12, or Cmd+Option+I on a Mac).

  1. Network. Add a product from the table and click the ?wc-ajax=add_to_cart request. If its response contains "error":true, the product was not added and the problem is the product (stock, quantity limits), not the mini cart. Otherwise expand fragments: its keys, such as div.widget_shopping_cart_content, are the cart elements WooCommerce and your theme can refresh.
  2. Your cart element. Right-click the header counter or mini cart, choose Inspect, and compare its tag and class with those keys. If nothing matches, the element is not a fragment: see the PHP filter section below.
  3. Console. Type typeof wc_cart_fragments_params and press Enter. "undefined" means the cart fragments script is not on the page, so wc_fragment_refresh does nothing.
  4. Compare with the shop. On the shop page, add a product with WooCommerce's own button. If the mini cart updates or the side cart opens there but not after the table, your cart listens to added_to_cart, which the footer script below provides.
  5. Reload. If the counter is still wrong after a reload while the cart page shows the product, the page comes from a cache; see the caching section.

Update the mini cart and open the side cart from the table

This script does what the shop page buttons do. Whenever the table cart has been refreshed, it fetches the fragments from WooCommerce and replaces the cart elements on the page, so it does not depend on the cart fragments script. After an Add to cart or add selected click it also fires added_to_cart with the real fragments, so side carts and the Mini-Cart block update and open as they are configured to.

/*
 * Products tables: update the theme mini cart and side cart after products are
 * added from a table. Add it to the site footer: a JavaScript snippet in a code
 * snippets plugin, or the footer scripts field of your theme.
 */
(function ($) {
    var announce = false;

    function fragmentsUrl() {
        if (typeof wc_add_to_cart_params !== 'undefined') {
            return wc_add_to_cart_params.wc_ajax_url.toString().replace('%%endpoint%%', 'get_refreshed_fragments');
        }
        return '?wc-ajax=get_refreshed_fragments';
    }

    // One product added with a table's Add to cart button
    document.addEventListener('woot-added-to-cart', function () {
        announce = true;
    });

    // Several products added with the "add selected" button
    document.addEventListener('click', function (e) {
        var button = e.target.closest('.woot-add-to-cart-all-btn');
        var table = button ? button.closest('table') : null;
        if (table && table.querySelector('.woot-add-to-cart-check:checked')) {
            announce = true;
        }
    }, true);

    // The table cart was refreshed: on page load, after adding, removing or changing quantities
    document.addEventListener('woot-woo-cart-refreshed', function () {
        var opened = announce;
        announce = false;

        $.post(fragmentsUrl(), function (data) {
            if (!data || !data.fragments) {
                return;
            }
            $.each(data.fragments, function (selector, html) {
                $(selector).replaceWith(html);
            });
            $(document.body).trigger('wc_fragments_refreshed');

            if (opened) {
                $(document.body).trigger('added_to_cart', [data.fragments, data.cart_hash, $()]);
            }
        });
    });
})(jQuery);

How it behaves:

  • The cart elements are refreshed on every change made through the table, removals and quantity changes in the table cart popup included. The added_to_cart event, and with it an opening side cart, comes only after products were added.
  • The table cart is also refreshed once when the page loads, so the script makes one extra fragments request per page with a table. It keeps the mini cart right on pages that come from a cache.
  • Some side carts open only through their own function, not through added_to_cart. If yours stays closed while its contents update, call that function inside the if (opened) block; the side cart's documentation or developer can tell you its name.

If you would rather send the shopper to the cart, the table's Options tab has After to cart adding with Redirect to the cart page and Redirect to the checkout page. The table can also show its own cart, which always stays in sync: switch on Show shop cart in the same tab, or place [woot_cart] anywhere on the page.

When the theme's cart counter is not a fragment

A counter that is not in the fragments list cannot be refreshed by any script, because WooCommerce never sends new HTML for it. Register it with WooCommerce's woocommerce_add_to_cart_fragments filter. Replace span.my-cart-count with the tag and class of your theme's counter, and keep the same class in the returned HTML so the element can be found again next time:

/*
 * Make the theme's cart counter a WooCommerce fragment, so it is refreshed
 * after AJAX add to cart. Child theme functions.php or a code snippets plugin.
 */
add_filter('woocommerce_add_to_cart_fragments', function ($fragments) {
    $fragments['span.my-cart-count'] = '<span class="my-cart-count">'
        . esc_html(WC()->cart->get_cart_contents_count())
        . '</span>';
    return $fragments;
});

This helps the shop page buttons as much as the table. Themes and page builders with a complex mini cart usually register it already; if theirs is missing from the list, ask the theme developer which element to use.

Page caching and script optimization

A page cache stores the HTML of a page, header cart included. If the theme prints its cart into the HTML and the cache keeps serving the version made for an empty cart, the counter is wrong after every reload, while the cart page, which caching plugins exclude by default, is right. Two things fix it, and caches for WooCommerce shops need both:

  • Do not serve cached pages to visitors with items in their cart. WooCommerce sets the cookies woocommerce_items_in_cart and woocommerce_cart_hash for them; most caching plugins and hosts can bypass the cache when these exist. WooCommerce lists the pages and cookies to exclude in Configuring caching plugins.
  • Never cache the ?wc-ajax= requests or admin-ajax.php. A cached fragments answer puts the same cart on every visitor's page.

Optimization features that delay, defer or combine JavaScript can also break the chain above: if the theme's cart script or WooCommerce's cart scripts run late or not at all, nothing updates the cart. Exclude jQuery, WooCommerce's add-to-cart and cart-fragments scripts, your theme's cart script and the folder /wp-content/plugins/profit-products-tables-for-woocommerce/, then clear every cache. If deactivating the caching or optimization plugin (WP Rocket or a similar one) fixes the mini cart, go through its cache and JavaScript options one by one to find the setting responsible rather than leaving the plugin off.

Checklist

  • The ?wc-ajax=add_to_cart request answers with fragments, not "error":true.
  • Your header cart or counter matches one of the fragment keys, or is registered with woocommerce_add_to_cart_fragments.
  • The footer script is on the table page, and the browser console shows no errors.
  • Pages are not served from cache to visitors with items in the cart; wc-ajax requests are never cached.
  • WooCommerce's cart scripts, the theme's cart script and the plugin folder are excluded from JavaScript delay, defer and combine.

If the cart still does not update, open a topic on the WOOT support forum with the page link, the name of your theme or side cart plugin and the fragment keys from the add_to_cart response, and we will look at it.