How do I add woocommerce endpoint to the state?

Wow! This article is great

I can get all products using custom post types as indicated here,
but to get all the necessary data I need to use this url,

I think I need a handler but it is not clear how to implement it.

Should I do it in frontity.settings.js?
in index.js?
in the component that shows products?

Thank you !!

Hi @vscopise!

I’ll recommend you to create it at the index.js file of the theme you are using. And in case you are planning to use more than one handler you could create a separate folder or file and import them from your index.js. It should look something similar to this:

const productsHandler = {
  name: "products",
  priority: 10,
  pattern: "products/:slug", //Or whatever your pattern is
  func: async () => { 
    ...
  };
}

const marsTheme = {
  name: "@frontity/mars-theme",
  roots: { ... },
  state: { ... },
  actions: { ... },
  libraries: {
    ...
    source: {
      handlers: [productsHandler]
    }
  }
};

export default marsTheme;

You can take a deeper look on handlers at our documentation.

Once you’ve created the handler, if you navigate to an url with the pattern you defined (products/slug/ for example), Frontity will run the function you defined and it should store the data in the state.

After that, you just have to get that data in the component you need it, using something like this:

const Product = ({ state, actions, libraries }) => {
  // Get information about the current URL.
  const data = state.source.get(state.router.link);

  ... //Use the data as you want

}

export default connect(Product);

If you are planning to use a template just for products, you could add something like isProduct equals true in the handler function as well, so you can filter it in your theme:

...
{
  (data.isFetching && <Loading />) ||
  (data.isArchive && <List />) ||
  (data.isProduct && <Product />) ||
  (data.isPostType && <Post />) ||
  (data.is404 && <Page404 />)
}
...

Please, let us know if this helps you and if you have more questions about this we’ll be glad to help :slightly_smiling_face:.

1 Like

Hi SantosGuillamot !

I realize that there’s a problem with the endpoint

when I navigate to /product i get this message:
`

Error: post type from endpoints “posts,pages,media” with slug “product” not found

`
In Postman I can get the data:
https://wp.laotramirada.com.uy/wp-json/wp/v2/product/

in frontity.settings I have:

...
postTypes: [
   {
     type: 'product',
     endpoint: 'product',
   }
]

I’m sorry,
I realized that I was putting the wrong data in frontity.settings,

the correct way is:

...
state: {
   source: {
     api: "https://wp.laotramirada.com.uy/wp-json",
     postTypes: [
       {
         type: 'product',
         endpoint: 'product',
         archive: 'product',
       }
     ]              
   },
 }
...

Should I combine a handler with postTypes to get all the necessary data?

Not sure if combining the handler with postTypes will work. I think the best option is to choose between:

  • Using a custom endpoint and use a handler to point to that data.
  • Using the CPT product and add more info (if necessary) from your WordPress.

Just to clarify it a bit more we have two cases:

If you use the CPT you defined

With that settings, you are telling Frontity to fetch that CPT. As you have defined it:

  • If you access to https://mysite.com/product/first-product (from Frontity) you’ll be getting the info from the endpoint https://wp.mysite.com/wp-json/wp/v2/product?slug=first-product (from your WP).
  • If you access to https://mysite.com/product you’ll be getting a list of all your products, fetched from https://wp.mysite.com/wp-json/wp/v2/product?slug=first-product.

You could add more info to that endpoint from your WP.

If you use your own handler

We usually use handlers to fetch data from a custom endpoint, or to change the way we populate the state.

With the handler you are telling Frontity: if we access the url https://mysite.com/products/slug you are going to run the function defined inside it. Inside this function, we usually fetch data from a new endpoint, and how we populate the frontity.state in order to consume that info later.

If you want to show a lists of your products when you access https://mysite.com/products, you’d need to create a new handler to match that pattern, and fetch all the products from your endpoint.

You’d need a new handler for example if you want to point to woocommerce API instead of wp-json/wp/v2.


In this case, if you’re fetching the data from a CPT, I guess the best option would be to use the CPT without a handler. And if you want to fetch the data from a different endpoint you may want to use a handler.

Let us know if this info helps you :slightly_smiling_face:

Hi Mario,
If I access to /product/polo I get “is404”… :sleepy:

I’ve created a repo to share the code if you have time to see it

thks

I found a handler to get all data:

const homeHandler = {
  name: 'home',
  priority: 20,
  pattern: '/',

  func: async ({ route, params, state, libraries }) => {
    // 1. get products data
    const response = await libraries.source.api.get({
      endpoint: '/wc/v3/products',
    });

    // 2. add product to state
    const productsData = await response.json();

    // 3. add route to data
    Object.assign(state.source.data[route], {
      productsData,
      isHome: true
    });
  }
}

With the products in the state,
I can implement operations such as adding to the cart, generating the order, etc.

I update when I have progress :smiley:

6 Likes

This is great :blush:

I can’t wait to see the final result @vscopise

Do you have a handler for the individual products? Something like this:

const homeHandler = {
  name: 'producto',
  priority: 10,
  pattern: '/producto/:slug',
  func: async ({ route, params, state, libraries }) => {
    // 1. get products data
    const response = await libraries.source.api.get({
      endpoint: '/wc/v3/products',
      params: { slug: params.slug }
    });

    // 2. add product to state
    const [product] = await libraries.source.populate({ state, response });

    // 3. add route to data
    Object.assign(state.source.data[route], {
      id: product.id,
      isProduct: true
    });
  }
}

Then access the data using:

const data = state.source.get(state.router.link);
const product = state.source.product[data.id];

Just curious. We’ve never worked with the woocommerce API :man_shrugging:

Here is the handler to get a product :grinning:

const productHandler = {
  name: 'product',
  priority: 10,
  pattern: '/product/:slug',

  func: async ({ route, params, state, libraries }) => {

    // 1. get product data
    const response = await libraries.source.api.get({
      endpoint: '/wc/v3/products',
      params: { slug: params.slug}
    });

    // 2. add product to state
    const productData = await response.json();        

    // 3. add route to data
    Object.assign(state.source.data[route], {
      productData,
      isProduct: true
    });

  }
}
1 Like

Nice! :slight_smile:

I would like to share the code done so far to see your opinions
https://github.com/vscopise/frontity-wc :slightly_smiling_face:

I would also like to ask you if you recommend Bootstrap, Material-UI or if you prefer another UI-framework to Frontity

Our recommended framework is Chakra UI because it works seamlessly with Emotion :+1:

Looks great so far. Thanks for sharing :smile:

1 Like

2 posts were split to a new topic: Illegal escape sequence in your template literal

I can save and get the cart from the localstorage:

const addToCart = ({ state, actions }) => ({ productId, quantity }) => {
  state.theme.cart.push({ productId, quantity });
  localStorage.setItem(
    'frontity_wc_cart',
    JSON.stringify(state.theme.cart)
  );
  actions.theme.calculateCartTotal();
}


...
actions: {
  theme: {
    afterCSR: ({ state, actions, libraries }) => {
      const cachedCart = window.localStorage.getItem('frontity_wc_cart');
      if (cachedCart && cachedCart.length !== 0) {
        state.theme.cart = JSON.parse(cachedCart);
        state.theme.cart.map(cartItem => {
          //here I need to read the details of the products of the cart 
          //and save them in the state
        });
      }
    }
  }

How can I get the details of the products stored in the cart?

As far as I can tell you should do it in the same way as desribed by @luisherranz in How do I add woocommerce endpoint to the state?

Does it not work? What approaches have you tried? Do you have an errors that occur with your solution?

@luisherranz describes a handler to load a product, which is not necessary now, since I handle products like Custom Post Types.
Now I need to load the products from the shopping cart (which I charge from localStorage) at the start of the app, I have the product id(s) from the localStorage

Thks! :grinning:

Using localStorage now I be able to get the saved cart, in my connected component:

const HeaderCart = ({ state, actions }) => {
  ...

  if (state.frontity.platform === 'client') {
    if ( 0 === state.theme.cart.length ) {
      const storedCart = localStorage.getItem(
        'frontity_wc_cart'
      );

      if (storedCart && storedCart.length !== 0) {
        state.theme.cart = JSON.parse(storedCart);
        state.theme.cart.map(cartItem => {

          // here i need to fetch each product from the api...

        })
      };
    }
  }

Do I need a handler to get each product?