Managing the cart using the REST API after WooCommerce 3.6

By Updated: September 18, 2019 13

WooCommerce 3.6 lands on 17 April, and with it come some fairly significant changes from a development point of view.

One of the performance improvements included in this update is to remove the loading of the cart and other frontend code for REST requests. Without going into all the details, the previous checks for loading cart functions meant they were loaded for all request types (including the REST API). From the 3.6 release, the cart and associated functions will only load on the frontend.

This is a worthwhile improvement in and of itself, and hats off to the WooCommerce team for all the great work they’ve done on this release. However, there is a downside – if you have a plugin which interacts with the cart in any way via the REST API, you’ll suddenly find your code no longer works in 3.6!

Our WooCommerce quick view plugin does just that. We allow all product types to be added to the cart from a modal window, 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 post 3.6, which may be helpful to other plugin developers.

First the 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.

However, you’ll probably also need the cart functions under /woocommerce/includes/wc-cart-functions.php. This won’t be autoloaded, so we’ll need to include that:

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

Since the cart often writes notices (e.g. when adding to the cart), you should include those too:

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

Next we need to initialise the session, as this is now only done on the frontend:

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 will also be null 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 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();

In our plugin, we put all this together inside a check_prerequisites function which runs right at the start of our ‘Add to cart’ REST request. Here’s the full code:

/**
 * Check any prerequisites required for our add to cart request.
 */
private function check_prerequisites() {
	if ( defined( 'WC_ABSPATH' ) ) {
		// WC 3.6+ - Cart and notice functions are not included during a REST request.
		include_once WC_ABSPATH . 'includes/wc-cart-functions.php';
		include_once WC_ABSPATH . 'includes/wc-notice-functions.php';
	}

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

		//Prefix session class with global namespace if not already namespaced
		if ( false === strpos( $session_class, '' ) ) {
			$session_class = '' . $session_class;
		}

		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();
	}
}
Filed under: WordPress Development

Andy Keith

Technical Director @Barn2 Media. With over 15 years in the industry, Andy is a WordPress and software developer with a keen interest in object-oriented design. A: always, B: be, C: coding.

13 Comments

  1. raj
    July 12, 2019 Reply

    hello,I need help for creating add to cart api . This api use for android application

    • EJ
      July 15, 2019 Reply

      Hi, Raj. I'm sorry to hear you're having difficulty with that. Our article is meant to be only a guide for a specific use case. Have you tried looking in the almighty Stack Overflow?

  2. Henrik
    July 8, 2019 Reply

    Thank you for sharing your solution to this WooCommerce update, got my REST endpoints up and running again. Life saver. <3

  3. Václav Greif
    May 26, 2019 Reply

    Hello again, the proper solution can be found here: https://github.com/woocommerce/woocommerce/issues/23584 . Just exclude your endpoint from WooCommerce Rest API calls..:)

    • Andy Keith
      June 3, 2019 Reply

      Yes, you can also use that filter. Bear in mind this will load the whole WooCommerce front-end which you may not need. Also the function which contains that filter is slated for removal once WP resolves the trac ticket mentioned in the comments.

  4. Václav Greif
    May 26, 2019 Reply

    Hello,
    thanks for this. I'm trying to add products to cart using the Rest API. For some reason, it works only for the first time. When I call the API second time, the WC()->cart->add_to_cart() function returns the new cart item key, but the item is not added to cart.

    Any idea how to fix this?

    Thanks!
    Václav

Please share your thoughts...

Your email address will not be published.