woocommerce / woocommerce

A customizable, open-source ecommerce platform built on WordPress. Build any commerce solution you can imagine.
https://woocommerce.com
9.42k stars 10.77k forks source link

Cart and Session not working in REST API event with woocommerce_is_rest_api_request #27160

Closed vaclavgreif closed 4 years ago

vaclavgreif commented 4 years ago

I've been using woocommerce_is_rest_api_request filter without any issues, but after updating from 4.2 to 4.3.0 this suddenly stopped working, Cart and Session are no longer defined.

Did anything change? I tried this:

I need to have all the frontend functions available in the REST API as it was before 3.6, as I use the API for adding items to cart, saving customer data to session etc. Is there a preffered way to have all the frontend methods available in REST requests?

Thanks Václav

mejta commented 4 years ago

I have the same issue, I need to work with WC session in my custom Rest API and suddenly, it doesn't work with the new WordPress version. Is there any workaround, please?

tammullen commented 4 years ago

Hi @vasikgreif

Thank you for submitting the issue, to help us evaluate this issue can you please provide a copy of your WooCommerce System Status Report The System Status Report is found in your WordPress admin under WooCommerce > Status. Please select “Get system report”, then “Copy for support”, and then paste it here.

vedanshujain commented 4 years ago

@vasikgreif @mejta Based on your error description seems like your code is trying to get something from the cart before its loaded. Note that woocommerce_is_rest_api_request is a general filter which is called by method is_rest_api_request, and there is no guarantee that it will be called after cart is loaded. My guess is, somewhere we or some other plugin is now calling this function before initializing of cart or session, and that's valid usage.

I would recommend that instead of woocommerce_is_rest_api_request, you use the woocommerce_init action to hook your function and use is_rest_api_request inside an if statement to return early. Code could be something like:

add_action( 'woocommerce_init', 'my_function' );

function my_function() {
    if ( ! WC()->is_rest_api_request() ) {
        return;
    }

    WC()->frontend_includes();

    if ( null === WC()->cart && function_exists( 'wc_load_cart') ) {
        wc_load_cart();
    }

    /**
     * My custom logic.
     */
}

Feel free to write back if there is any issues.

vaclavgreif commented 4 years ago

I think this solves only part of the problem.

First, the frontend functions seem to not to be loaded in the REST API, which I somehow fixed by calling WC()->frontend_includes();.

The session still does not seem to persist the data.

In any case, something had to change, because this was working perfectly fine before. There really should be an easy way to enable the frontend functions in the REST API's, as the solutions provided seem more like a hack than a proper solution.

EDIT: I had the filter originally hooked on init, after it stopped working, I moved that directly to the main plugin file, because the filter was not called at all when it was on init.

vedanshujain commented 4 years ago

The session still does not seem to persist the data.

I tested by adding the following in above snippet:

echo "\n Previous session: " . WC()->session->get( 'some_key' );
WC()->session->set( 'some_key', rand(0, 999) );

and seems to be working fine for me.

We save the session data in save_data method in includes/class-wc-session-handler.php, can you help debug by modifying this function to add some print statements and see if this method is being called at all.

vaclavgreif commented 4 years ago

@vedanshujain Thanks. To make it easier to debug for me, as the app is really complex, can you please tell me what exactly do I need to have all the frontend functions (cart, session, customer) included in the REST API? Does the wc_load_cart function load everything?

Thanks

seb86 commented 4 years ago

I'm curious what/why you all need to do custom REST API for the cart when CoCart is available and works. I'm always looking to improve so please let me know. You can even submit an enhanced issue on the repository. Thanks.

vaclavgreif commented 4 years ago

@seb86 I need only a very small portion of the functionality for the React wizard- I need to be able to add item to cart with custom data, add some customer info to session. CoCart is great for sure, but it's an overkill for what I need.

justanotherco commented 4 years ago

Same here.

Latest WooCommerce v4.3.1 Using a very bog standard WP REST API to remove an item from cart results in undefined cart functions.

What happened? Is this a bug or on purpose? Because it would be a backward compatibility nightmare to not allow standard WP REST API to access Cart and session...

vedanshujain commented 4 years ago

what exactly do I need to have all the frontend functions (cart, session, customer) included in the REST API? Does the wc_load_cart function load everything?

You would also need to do WC()->frontend_includes but that's it. (I am contemplating adding it inside wc_load_cart itself).

vedanshujain commented 4 years ago

@justanotherco We do not load Cart, customer and sessions in REST API unless we need to for performance reasons. WooCommerce has generally supported API in the backend but not in the frontend (although this can change in future) and that's why there is no standard documented API for Cart yet. Technically speaking, if we were infact loading cart for normal API requests, then that's a bug. If an extension is writing a frontend API then they need to include whatever they need, because as you can see, loading things that API won't need is a performance problem. (This was initially added in #23792 #23102)

justanotherco commented 4 years ago

But this was working before v4.3, meaning you guys changed something.

Considering the change, is there official documentation on this topic? I'm sure it's very common use for themes/plugins to want to add ajax functionality to a site. All I'm trying to do is remove an item from a cart via a WP REST API call with a bog standard call with a simple PHP that uses WC() to identify, remove the item from the cart and then in the ajax success call, the wc_fragment_refresh is triggered.

Is there an official way to load cart only for a specific WP REST API call? That would be ideal.

seb86 commented 4 years ago

@justanotherco You might find the answer your looking for with CoCart.

lostpebble commented 4 years ago

@seb86 does CoCart allow us to define our own custom plugin wp-json/ Rest APIs and access the WooCommerce cart? It seems to just be an advanced Rest API for manipulating your cart, which is clearly not what the issue at hand is about.

seb86 commented 4 years ago

@lostpebble No it does not let you define your own plugin. I clearly miss read the issue and thought users were trying to build something that was already available and working.

naghman-ali commented 4 years ago

@vasikgreif @mejta Based on your error description seems like your code is trying to get something from the cart before its loaded. Note that woocommerce_is_rest_api_request is a general filter which is called by method is_rest_api_request, and there is no guarantee that it will be called after cart is loaded. My guess is, somewhere we or some other plugin is now calling this function before initializing of cart or session, and that's valid usage.

I would recommend that instead of woocommerce_is_rest_api_request, you use the woocommerce_init action to hook your function and use is_rest_api_request inside an if statement to return early. Code could be something like:

add_action( 'woocommerce_init', 'my_function' );

function my_function() {
  if ( ! WC()->is_rest_api_request() ) {
      return;
  }

  WC()->frontend_includes();

  if ( null === WC()->cart && function_exists( 'wc_load_cart') ) {
      wc_load_cart();
  }

  /**
   * My custom logic.
   */
}

Feel free to write back if there is any issues. @vedanshujain Thankyou soo much, its working fine.

Jazz-Man commented 4 years ago

@vasikgreif Yes, it's just awful that the session has stopped working for the REST API. I also had problems after the update. But here in this topic there was a very simple solution. In my case, this helped me:

<?php

namespace IconicJew\RestAPI;

/**
 * Class RestApi.
 */
class RestApi implements AutoloadInterface
{

    public function load()
    {
        // ...
        add_action('rest_api_init', [$this, 'create_rest_routes']);
        // ...
    }

    public function create_rest_routes()
    {
        // ...
        if ( null === WC()->cart && function_exists( 'wc_load_cart') ) {
            wc_load_cart();
        }

        // ...
    }

    /**
     * ...
     */

}

that is it is simple enough to call wc_load_cart function on a hook rest_api_init. I hope this helps:)

vedanshujain commented 4 years ago

I am closing this issue because it does not look like there is a bug that needs to be fixed. But please feel free to write for any suggestions.