Support » Plugin: WooCommerce » WC()->cart is null in custom REST API

  • Resolved tbrmilesson

    (@tbrmilesson)


    Hey guys! WC()->cart is null in 3.6.1 if running in a method callable by a custom REST API route.

    Check below code. Why has a _minor_ release led to so many issues?

    /**
     * Routes helper
     */
    class Routes {
        /**
         * Adds some actions
         */
        public function __construct() {
            add_action( 'rest_api_init', array( $this, 'register' ) );
        }
    
        /**
         * Registers the routes
         */
        public function register() {
            $namespace = 'nch';
            register_rest_route(
                $namespace,
                '/add_to_cart',
                array(
                    array(
                        'methods'             => 'POST',
                        'callback'            => array( $this, 'add_to_cart' ),
                    ),
                )
            );
        }
    
        /**
         * Creates the actual cart
         *
         * @param Any $request The current request.
         */
        public function add_to_cart( $request ) {
            /**
             * [REDACTED]
             */
    
            // Empty existing cart.
            WC()->cart->empty_cart( true ); // THIS CRASHES IN 3.6.1
            WC()->session->set( 'cart', array() );
    
            /**
             * [REDACTED]
             */
        }
    }
Viewing 10 replies - 1 through 10 (of 10 total)
  • Plugin Author Mike Jolley

    (@mikejolley)

    I think the issue here is the cart is supposed to be enqueued on frontend requests only. The check to detect frontend requests were fixed in 3.6 (for performance reasons) so that frontend !== rest API requests. Frontend classes should not be loaded during the execution of the REST API.

    I’m not sure what the best solution would be to this; either tricking it into thinking your REST endpoint is a frontend request, or including frontend classes manually.

    Was this change documented? This is a breaking change as far as I’m concerned.

    It’s not possible to move my logic to admin-post.php either. It results in the same issue. This is ridiculous.

    Plugin Author Mike Jolley

    (@mikejolley)

    * Performance – Prevent frontend code from being loaded during REST API. #21090

    It’s not really possible to document every unknown side effect. Loading all the theme code, frontend classes etc have a massive impact on the loading time of the REST API so simply reverting this would have negative consequences.

    You could trying calling wc()->frontend_includes() so the classes are included, and run this code to init cart/session/customer before usage:

    
    WC()->session = new WC_Session_Handler();
    WC()->session->init();
    WC()->customer = new WC_Customer( get_current_user_id(), true );
    WC()->cart = new WC_Cart();
    

    If you can think of a better approach to this without needing to load these classes for all users you could contribute via GitHub.

    Thanks

    This fix works great, but you can not get the Sub Total using this code and a few other cart properties are still returning 0, when the data should be pulling the current cart data.

    Same issue, in my case the fix has worked (number of items and total).

    wc()->frontend_includes()

    Thanks God!!! This save my life.

    The solution proposed above does not work in all cases. Here’s the correct solution for anyone needing this: https://github.com/woocommerce/woocommerce/issues/23584

    add_filter( 'woocommerce_is_rest_api_request', [ $this, 'simulate_as_not_rest' ] );
    /**
     * We have to tell WC that this should not be handled as a REST request.
     * Otherwise we can't use the product loop template contents properly.
     * Since WooCommerce 3.6
     *
     * @param bool $is_rest_api_request
     * @return bool
     */
    public function simulate_as_not_rest( $is_rest_api_request ) {
    	if ( empty( $_SERVER['REQUEST_URI'] ) ) {
    			return $is_rest_api_request;
    	}
    
    	// Bail early if this is not our request.
    	if ( false === strpos( $_SERVER['REQUEST_URI'], $this->namespace ) ) {
    		return $is_rest_api_request;
    	}
    
    	return false;
    }

    @vasikgreif , where to put this ?

    @french5000 This should go to the class or file where you have your custom REST routes defined.

Viewing 10 replies - 1 through 10 (of 10 total)
  • You must be logged in to reply to this topic.