Okay
  Public Ticket #1143223
Cache-powered site problems
Open

Comments

  •  2
    Noor started the conversation

    Hi again.

    Because a WordPress theme is the part of the system that shows the final UI to the user, it's particularly important that theme developers understand that users will use caching plugins to speed up their websites.

    So due to that, the cart count will not reflect the true contents of the cart because the count is generated on the server-side (by PHP) and that's cached by WordPress caching plugin.

    Instead, the count should be populated on client-side (via a JS AJAX call) so it always reflects the correct count. To make the UI smooth, the place where the count appears should be empty on load (not 0) and populate itself via AJAX.

    I could see that you tried fixing this in certain situations because I noticed a cached page show with (1) in the count, and then the count changed to (3) after loading. Not only this is a bad UX (for those of us who see the transition between 1 and 3) but the cached page should not include the (1) anyway. That count should be fed on client-side.

    Thoughts?

  •  2
    Noor replied

    I implemented the following on my website, working nicely. Provided without warranty of any kind.

    Step 1: Create a new PHP file in the theme directory.

    <?php
      // WordPress root directory.
      define('WP_ROOT_DIR', realpath(dirname(__FILE__) . '/../../../'));
      // Load minimal WordPress environment, but without loading the template.
      require_once( WP_ROOT_DIR . '/wp-load.php' );
      wp();
      // This script handles two situations regarding HTTP method: POST and non-POST
      // POST requests will show the cart's items count.
      if('POST' === $_SERVER['REQUEST_METHOD']) {
        if(!empty($GLOBALS['woocommerce'])) {
          echo $GLOBALS['woocommerce']->cart->cart_contents_count;
        }
        // Exit at this point.
        die();
      }
      // non-POST requests just spits out the JavaScript code.
      header('Content-Type: application/x-javascript');
    ?>
    (function($, $count) {
      // Run on load.
      $(function() {
        $.ajax({
          method: 'post',
          url: "<?php echo get_template_directory_uri(); ?>/<?php echo basename(__FILE__); ?>"
        }).done(function(response) {
          $count = $('.ql_cart-btn span.count');
          $count.text('' + response);
          $count.addClass('count-updated');
        });
      });
    })(jQuery);
    

    Step 2: Change functions.php to enqueue a script to load after jQuery:

    // Show number of items in cart using AJAX.
    function theme_woocommerce_show_cart_items_count() {
      wp_register_script( 
        'update-cart-count', 
        get_template_directory_uri() . '/update-cart-count.php', 
        array( 'jquery' )
      );
      wp_enqueue_script( 'update-cart-count' );
    }
    add_action( 'wp_enqueue_scripts', 'theme_woocommerce_show_cart_items_count' );
    

    Step 3: Remove the PHP code that shows the cart's count since that'll be cached and we don't want that, and add the following to the style:

    /* Hide until count can be calculated client-side. */
    .ql_cart-btn .count {
      visibility: hidden;
    }
    .ql_cart-btn .count.count-updated {
      visibility: visible;
    }
  •  107
    Nico replied

    Thank you Noor for sharing!

  •  2
    Noor replied

    A pleasure :)