Felix Hagspiel
Felix Hagspiel

Reputation: 2937

woocommerce 3: removing cart items for logged in users does not work

we are using wordpress JSON API to signon a user and to add / update / remove cart-items. We are doing this with the register_rest_route function.

We use this code to remove a cart item:

function remove_from_cart(WP_REST_Request $req)
{
    $resp = null;

    $cart_item = $req['cart_item'];
    try {
        WC()->cart->remove_cart_item($cart_item);
    } catch (Exception $e) {
        $resp = $e;
    }
    return rest_ensure_response(new CartResponse());
}

This is working perfectly fine for guests. but as soon as a logged in user tries it, the cart is back to its normal state after a page reload. The response created by new CartResponse() is correctly showing the cart without the removed item. however, after a page reload the item is still there. As this only happens for logged in users and not for guests I think it is a session issue. Also, updating the cart with the following method works for logged in users:

function update_cart_item(WP_REST_Request $req)
{
    $resp = null;

    $cart_item = $req['cart_item'];
    try {
        if ($cart_item && $cart_item['quantity']) {
            WC()->cart->set_quantity($cart_item['key'], $cart_item['quantity']);
        }
    } catch (Exception $e) {
        $resp = $e;
    }
    return rest_ensure_response(new CartResponse());
}

Unfortunately, setting the quantity to 0 is also not working.

This is how we signon users:

function login_customer(WP_REST_Request $req)
{

    $body = $req->get_body();
    $input = json_decode($body, TRUE);
    $credentials = ['user_login' => $input['email'], 'user_password' => $input['password']];

    $user = wp_signon($credentials, false);
    if (is_a($user, 'WP_Error') || !$user) {
        // if an error occurs, return null
        return rest_ensure_response(null);
    }
    $resp = new CustomerResponse($user->ID);
    return rest_ensure_response($resp);
}

And we are not using any caching plugins. What is wrong here?

Here is a list of all session cookies: enter image description here

EDIT:

I just inspected the cookies while beeing logged in and removing a cart item.

  1. Cart Hash before deleting: bb35785a228a17ceb85f8ed2dc522b16
  2. Cart Hash directly after deleting: d32e22e278d42022e04b6992b7d65816
  3. Cart Hash after page reload: bb35785a228a17ceb85f8ed2dc522b16 again

So it seems like the cart hash is stored somewhere and restored on a reload, but not correctly updated on deleting a cart item

Upvotes: 1

Views: 1278

Answers (1)

Felix Hagspiel
Felix Hagspiel

Reputation: 2937

It seems like you need nonces to authenticate DELETE requests.

Now I am adding nonces to each response in a header:

function add_cors_http_header(){
    header("X-WP-Nonce: ".wp_create_nonce('wp_rest'));
}
add_action('init','add_cors_http_header');

And in the frontend I set it:

let nonce: string = null;
export const fetchNoAuth = (endpoint: string, method: string = 'GET', data: any = null): Promise<any> => {
  let headers: any = {'Content-Type': 'application/json'};
  if (nonce) {
    headers['X-WP-Nonce'] = nonce;
  }
  return fetch('http://' + apiUrl + apiPath + endpoint + '?' + debugQuery, {
    method,
    credentials: 'include',
    headers,
    body: data ? JSON.stringify(data) : null
  })
    .then((data) => {
      const nonceFromResponse = data.headers.get('X-WP-Nonce');
      if (nonceFromResponse) {
        nonce = nonceFromResponse;
      } else {
        nonce = null;
      }
      return data;
    })
};

Make sure that the header in the request is named X-WP-Nonce

Upvotes: 1

Related Questions