Managing the cart using the REST API after WooCommerce 3.6

August 7, 2020

Since WooCommerce 3.6, some front-end functions and classes are no longer loaded for REST API requests. Read on to see how to load these manually in your theme or plugin.

WooCommerce 3.6 (released 7 April 2019) included some fairly significant changes from a development point of view. One of the performance improvements was to remove the cart and other frontend code for REST API requests. From 3.6 they are only loaded for 'frontend' requests, i.e. those displaying an actual page on your website.

This is a worthwhile improvement but there there is a downside: if you have a plugin or some custom code which interacts with the cart or frontend code via the REST API, you'll suddenly find it no longer works.

Our WooCommerce Quick View Pro plugin was affected by this problem. In that plugin, we allow products to be added to the cart from a lightbox, and we use the REST API to facilitate that. Without wishing to rewrite the plugin to use an alternate method (e.g. AJAX) we found a workaround for this, which may be helpful to other plugin developers.

First some good news: the WooCommerce autoloader takes care of including any classes referenced during your REST request. So even though the cart class is no longer included upfront, if you reference WC_Cart in your code, then the autoloader will load it for you.

If you use functions such as wc_add_to_cart_message, you'll need to include the cart functions separately (/woocommerce/includes/wc-cart-functions.php) as this file won't be autoloaded. And since the cart often creates notices (e.g. adding items to the cart), you'll probably want to include those functions too:

include_once WC_ABSPATH . 'includes/wc-cart-functions.php';
include_once WC_ABSPATH . 'includes/wc-notice-functions.php';

You may also need the template hooks file, if your request outputs one of the WooCommerce templates:

include_once WC_ABSPATH . 'includes/wc-template-hooks.php';

Next, we need to initialise the session class:

if ( null === WC()->session ) {
    $session_class = apply_filters( 'woocommerce_session_handler', 'WC_Session_Handler' );
    WC()->session = new $session_class();
    WC()->session->init();
}

This code is basically a straight copy of what WooCommerce itself does during WooCommerce->init().

Next, we need to initialise the customer and cart objects, as these are no longer created for REST requests:

if ( null === WC()->customer ) {
    WC()->customer = new WC_Customer( get_current_user_id(), true );
}
if ( null === WC()->cart ) {
    WC()->cart = new WC_Cart();
}

Finally, we need to load the existing cart from the session. Even though we've created the cart at this point, the cart contents will be empty.

The cart storage is handled by the WC_Cart_Session class. If you look at the code, you'll see that the initial read of the cart is done on the wp_loaded hook. As we are executing a REST request which runs during parse_request, this hook will have already happened.

So we need to force the cart to refresh its contents from the session. The simplest way to do that is to call the get_cart() method:

WC()->cart->get_cart();

That's pretty much it. In our quick view plugin, we put this together inside a check_prerequisites() function which runs right at the start of our REST request. Here's the code we use:

/**
 * Check any prerequisites for our REST request.
 */
private function check_prerequisites() {
	if ( defined( 'WC_ABSPATH' ) ) {
		// WC 3.6+ - Cart and other frontend functions are not included for REST requests.
		include_once WC_ABSPATH . 'includes/wc-cart-functions.php';
		include_once WC_ABSPATH . 'includes/wc-notice-functions.php';
                include_once WC_ABSPATH . 'includes/wc-template-hooks.php';
	}

	if ( null === WC()->session ) {
		$session_class = apply_filters( 'woocommerce_session_handler', 'WC_Session_Handler' );

		WC()->session = new $session_class();
		WC()->session->init();
	}

	if ( null === WC()->customer ) {
		WC()->customer = new WC_Customer( get_current_user_id(), true );
	}

	if ( null === WC()->cart ) {
		WC()->cart = new WC_Cart();

		// We need to force a refresh of the cart contents from session here (cart contents are normally refreshed on wp_loaded, which has already happened by this point).
		WC()->cart->get_cart();
	}
}

I hope you find this useful. I'll try keep this article up to date as new versions of WooCommerce are released. Let me know if you spot any problems or have any improvements to the code in the comments below.

19 Comments

  1. Kornel
    December 26, 2021 Reply

    Hey,
    I know that this is a quite old post, but I came across it and it almost helped me :)
    I am trying to add to cart from outside, namely from Unity I am sending a request to a .php and that should do it.
    The thing is if I run the .php from direct link (browser, probably noob move) it actually works (specific requests and $id taken out), while when I am calling the same file from Unity it doesnt.
    Just to clarify I have been using Unity>>PhP>>Woo back and forth successfully for other things.
    Also I have doublechecked and the .php runs correctly because after the request I echod back the product id which I have been requesting to add to card and I get correct results.
    Do you have any idea why could this happen?

    Thank you in advance!

    • Edge
      December 29, 2021 Reply

      Hey, Kornel. Thanks for your stumbling on our article and for your comment. I'm sorry to hear you're having difficulty with being able to add a product to the WooCommerce cart from Unity (the game engine?). I hope you'll understand we're not familiar with Unity and such a customization. For the best advice and updated information about this, I suggest you contact contact official WooCommerce Support. Alternatively, you could also consider getting developer-level support from Codeable. I hope this helps point you in the right direction for what you'd like to achieve. Best of luck!

  2. Jaswinder Singh
    July 14, 2020 Reply

    Its giving me an empty array
    print_r(WC()->cart);die; //Empty keys in array
    print_r(WC()->cart->get_cart(););die; //Empty array

    • Andy Keith
      July 14, 2020 Reply

      Was your cart empty before doing the REST request?

  3. Bogdan
    June 9, 2020 Reply

    Hey Andy. Thank you, thank you, thank you! Same as Dylan above, your article helped me so much. My plugin has a REST API request that creates an order with subscription product, which uses virtual WC_Cart to process the subscription properly. And was having a nasty error "Call to a member function get() on null in /.../woocommerce/includes/class-wc-cart-session.php on line 73" obviously connected to WC Session not being initialized. And this article helped me realize what I was missing.

  4. Dylan P
    November 13, 2019 Reply

    Thanks for explaining this so concisely, your article helped me immensely!

Please share your thoughts...

Your email address will not be published.