DEV Community

admond
admond

Posted on • Edited on

Using Headless Woo commerce store api v1 in nextjs : issue faced and solutions

Must read note:
If you want only solution scroll directly to solution section

The blog is about the integrating WooCommerce Store API. Integrating it was very hard because the documentation was lacking. The documents looked simple but didn't have enough information. This blog talks about integrating WooCommerce with a Headless API for Nextjs or React applications, but it can be used for other client-side applications too.

Issue: Nonce
The first problem was I didn't know what a nonce was. WordPress uses a nonce to make requests more secure. At first, I didn't know what it was. After researching for a while, I found out it was for security purposes. The documentation said the nonce should be retrieved using a PSP code in function.pho. However, they didn’t mention the function.psb part clearly. They only provided the code to generate the token, which frustrated me because there wasn't enough information.

After deep research on how to generate the nonce, I created an endpoint to generate it. Then, I faced another issue. It wasn’t about the nonce this time; it was about something else. They were using a nonce from the cart list API, and I was shocked to find out that I had created a separate route for something already present in the cart list API.

Solution: nonce was present in cart items api

Image description

OR

Also you can create your custom route by editing in functions.php
which is located in your applied
wp-content/themes/[your_theme]/functions.php


/**********************/
// Api to generate nonce
/**********************/
function get_wc_api_nonce() {
    // Generate WooCommerce nonce
    $nonce = wp_create_nonce( 'wc_store_api' );

    // Return the nonce in a JSON response
    return rest_ensure_response( array( 'nonce' => $nonce ) );
}

add_action( 'rest_api_init', function() {
    register_rest_route( 'secure/v1', '/wc-nonce', array(
        'methods' => 'GET',
        'callback' => 'get_wc_api_nonce',
    ));
});
Enter fullscreen mode Exit fullscreen mode

Issue: Cart Token
I found a problem with the user trying to add items to the cart multiple times. The user wanted the cart to merge when they logged in. They provided a workflow example, and I noticed a cart token in the response error. I decoded it and found it stored the user ID and some other minor details, but nothing important, so I ignored it.

After not finding anything helpful, I dug into the source code and implementation. After a long time, I discovered that only two headers were allowed: the cart token and nonce. I realized the cart token was used in previous issues. So, I tried using the JWT token from the response header in our application, and it worked.

If this had been mentioned in the documentation, it would have been easier for me.

Image description

Solution: First use add to cart api, get the cart-token from response header and add header Cart-token :YOUR_JWT token, to access this in client side you need to create an serverside endpoint so that you can access the Cart-token as it is not exposed for cors config., then your are go to go. Sample endpoint for nextjs

import { storeApi } from '@/lib/api';

const CART_TOKEN_HEADER_KEY = 'cart-token';

/**
 * info: this route is used to get the cart data from the store api by appending the cart token to the body
 * @param request
 * @returns
 */
export async function GET(request: Request) {
  const headers = request.headers;

  const savedCartToken = headers.get(CART_TOKEN_HEADER_KEY);

  const res = await storeApi.get('/cart', {
    headers: {
      ...(savedCartToken ? { [CART_TOKEN_HEADER_KEY]: savedCartToken } : {}),
    },
  });

  const responseData = {
    data: res.data,
    cartToken: res.headers[CART_TOKEN_HEADER_KEY],
  };

  return Response.json(responseData);
}

Enter fullscreen mode Exit fullscreen mode

Docs
https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/StoreApi/docs/cart-tokens.md

Payment Issue

Coming soon

Top comments (2)

Collapse
 
gsavvidis96 profile image
Giannis Savvidis

how can I get cart-token from response header? its not present in access-control-expose-headers resulting to be null when trying to access it from the browser.

Collapse
 
admondtamang profile image
admond

yup.. you will not be able to access cart-token from the client side because of security reasons. If you are using next js then create a route like this:

import { storeApi } from '@/lib/api';

const CART_TOKEN_HEADER_KEY = 'cart-token';

/**
 * info: this route is used to get the cart data from the store api by appending the cart token to the body
 * @param request
 * @returns
 */
export async function GET(request: Request) {
  const headers = request.headers;

  const savedCartToken = headers.get(CART_TOKEN_HEADER_KEY);

  const res = await storeApi.get('/cart', {
    headers: {
      ...(savedCartToken ? { [CART_TOKEN_HEADER_KEY]: savedCartToken } : {}),
    },
  });

  const responseData = {
    data: res.data,
    cartToken: res.headers[CART_TOKEN_HEADER_KEY],
  };

  return Response.json(responseData);
}

Enter fullscreen mode Exit fullscreen mode

or

you can set config to allow cart-token header, in your applied theme function.php file.

/**********************/
// start of cors config
/**********************/

function add_cors_http_header() {
    $allowed_origins = [
        'http://localhost:3000',
        'https://localhost:3000',
        'http://127.0.0.1:3000',
    ];

    // Check if the Origin is set and if it's in the allowed origins array
    if (isset($_SERVER['HTTP_ORIGIN']) && in_array($_SERVER['HTTP_ORIGIN'], $allowed_origins)) { header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}"); }

    // Define other CORS headers
    header("Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT, DELETE");
    header("Access-Control-Allow-Credentials: true");
    header("Access-Control-Expose-Headers: Cart-Token");
    header("Access-Control-Allow-Headers: X-Requested-With, Content-Type, Authorization, X-WP-Nonce, Nonce, Cookie, Cache-Control, Cart-Token, Origin, User-Agent, Set-Cookie");
//, Set-Cookie
      // Handle preflight requests
    if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
        header("Access-Control-Max-Age: 86400"); // Cache preflight for 24 hours
        exit(0); // Terminate preflight request
    }
}
Enter fullscreen mode Exit fullscreen mode