Using WooCommerce Dynamic Cart and WP Rocket

At Elephant, we’re using WP Rocket to cache our WordPress websites. Simple to set up, full of features and good compatibility with most of the commonly used plugins (ACF, WPML, etc) in the WordPress realm.

WP Rocket uses all kinds of different ways to speed up your site, from saving static pages in wp-content/cache/wp-rocket (gzipped for faster download), combining and concatenating JS and CSS (if you want it to), to adding headers to your .htaccess.

This makes the whole loading process of your site very quick, though with webshops, this might be a bit problematic, since you need them to show some new stuff every now and then, right?

WP Rocket allows you to exclude any page(s) from the cache, but when you’re using WooCommerce, Easy Digital Download, iThemes Exchange, Jigoshop or WP-Shop, you’ll be fine since cart and checkout pages will be auto-excluded from those plugins automatically.

Recently, however, I ran into a little problem with the mini cart that WooCommerce offers and that you can use, for example, in your webshop header. The mini cart was not Ajax-ed, so the content was being cached and sometimes made it look like you didn’t have any items in your cart even when you did. By reaching out via Twitter I found out that the only way to solve this correctly was by retrieving this mini cart via WP AJAX. Since I promised the helpful team at WP Rocket a write up, I’ll tell you how I did this.

Schermafbeelding 2015-06-17 om 09.18.29

The mini cart over at jaloezieenverkoop.nl has only one dynamic part: {x} product(s) {total_price}. You can generate a mini cart using the Woo function woocommerce_mini_cart(), but for me, this proved to be a bit too much information.

So, my mini cart looks like this:

<?php global $woocommerce; ?>

<div id="shop-cart">
    <span class="cart-title"><?php _e( 'Winkelwagen', ' your-textdomain ' ); ?></span>
    <span class="cart-products">
    
        <span class="cart-result"></span>

    </span>
    <div class="cart-links">
        <ul>
            <li><a href="<?php echo $woocommerce->cart->get_cart_url(); ?>" title="<?php _e( 'Bekijken', ' your-textdomain ' ); ?>"><?php _e( 'Bekijken', 'your-textdomain' ); ?></a></li>
            <li><a href="<?php echo $woocommerce->cart->get_checkout_url() ?>" title="<?php _e( 'Checkout' ) ?>"><?php _e( 'Afrekenen', 'your-textdomain' ); ?></a></li>
        </ul>
    </div>
</div><!-- #shop-cart -->

Please note the span .cart-result – that’s the span we’re going to use for our mini cart data. The rest of our mini cart is always going to be the same (checkout button, go to cart button), so we can easily have those elements cached.

We setup the AJAX call next. I’m using regular jQuery, obviously there are other ways to do this, but I suspect that most of you out there are comfortable with this way of doing things.

So first, the JS initializing the call:

/*------------------------------------------------------------------------*/
/* Load cart by Ajax
/*------------------------------------------------------------------------*/

if( 1 == jQuery( '.cart-result' ).length ) {

	var data = {
		'action': 'load_woo_cart'
	};
	
	jQuery.post( woocommerce_params.ajax_url, data, function( response ) {
		jQuery( '.cart-result' ).append( response );
	});

}

As you can see we’re checking to see if .cart-result is there, we create the $_POST data (our only data being the call we want to make) and we re-use the WooCommerce AJAX URL so we don’t have to enqueue it ourselved.

With the data returned, we fill up .cart-result. Nothing more, nothing less.

Next step, let’s see what our PHP looks like…

/**
* Ajax functions to retrieve cart
**/

add_action( 'wp_ajax_nopriv_load_woo_cart', 'load_woo_cart' );
add_action( 'wp_ajax_load_woo_cart', 'load_woo_cart' );

function load_woo_cart(){
	echo get_template_part( 'parts/header/cart-ajax' );
	die();
}

We add some actions here that receive the calls made by our Javascript. I’m not diving in on how that works (you could check that yourselves in the WordPress codex, but it basically only returns the template part with the cart data we need: {x} product(s) {total_price}. I’m working with template parts here and I think you should to – it’s best practice not having your markup tangled up with your code, of course (if I did, I’d have some evil front end devs harassing me in no time).

The part looks like this:

<?php global $woocommerce;
if ( $woocommerce->cart->cart_contents_count > 0 ) : ?>
    
    <?php $producten = ($woocommerce->cart->cart_contents_count > 1 ? __(' Producten ') : __(' Product ') ); ?>
    <?php echo $woocommerce->cart->cart_contents_count . $producten . $woocommerce->cart->get_cart_total(); ?>

<?php else : ?>
    
    <?php _e( 'Geen producten', 'your-textdomain); ?>

<?php endif; ?>

I’m using Woo’s global to retrieve the data I need and only that, not the total mini cart you get from woocommerce_mini_cart() – though that might be nice to retrieve here as well, if you need that kind of data.

And that’s it! Your cart will always contain the right data and WP Rocket will only cache the parts it needs to cache. Now, there is one little catch here, if you’re on a slower webserver; and that is the AJAX delay in loading that bit of data. I always find myself using jQuery Block UI to provide a loading message until the data is returned to provide an optimal user experience – but that is a bit out of the scope of this blog.

Good luck!

About

Subscribe to our newsletter Latest news of the rocket, at the speed of light!

10 comments

Comment

Is there some way WP Rocket can implement dynamic parts in the configuration.
We’ve build a website for one of our clients that is showing random users on the homepage and the members page (http://www.netoo.nl).

Only one dynamic part forced us to disable the caching for 2 pages of the website.

Your solution above is great but i think it’s too hard to use! There should be a more easy way!

Great write up. I’ve been looking to achieve something similar for a while now and this has given me an idea on how I can actually get it working.

@Jurgen: I’m afraid there is no such thing as an easier way to do it then via ajax (at the moment). WP Rocket creates static cached pages (check wp-content/cache/wp-rocket/) and is not able to distinguish what parts to cache – it just does your output. I’m not sure about feature requests or a roadmap since I’m just a guest author, but I cannot imagine the guys at WP Rocket haven’t thought about it. Maybe @jb_ma can elaborate on this a bit further?

@Luke: Great, curious to see what you come up with.

@Tommy: Thanks for your reply.
I know how WP Rocket works.

I have experience with Lesti FPC in Magento which used dynamic blocks. In WooCommerce the minicart is a custom action so i think there must be someway to get this done.

See: http://www.magentocommerce.com/magento-connect/lesti-fpc-simple-fullpagecache.html (Dynamic blocks)

The Magento example is pretty nice, I do some Magento work myself as well and that extension looks promising. I know Magento refreshes the cache for minicarts by itself already by the way.

But, let’s not get off topic: of course I should’ve answered that you could add it to the WP Rocket Roadmap 🙂 https://trello.com/b/CrUcz6Jy/wp-rocket-roadmap. I’m all for it too!

thanks for the solution x

I’ve hired someone on fivver.com to fix this issue on my shop. Somehow i still get notifications that products are added to the cart. At least since the fix they aren’t actually added to cart anymore but visitors i still get the messages.

See Screenshot: https://snag.gy/Xwa5qd.jpg

Someone willing to help me out for a small fee?

Actually we combined WP Rocket with Disable Cart Fragments for super speed on Woocommerce… fastest thing we’ve seen besides removing page builder plugins helps a lot too.

https://wordpress.org/plugins/disable-cart-fragments-littlebizzy/

I’m not familiar with WordPress/Woocommerce. In which file do you write the “Load cart by Ajax” code? In the functions.php file located in my own child theme?

Leave a Reply

Your email address will not be published. Required fields are indicated by *

[i]
[i]