# Product entity

In Vue Storefront there is a defined Product type you're to use in your TypeScript code. It contains many optional fields. Please check sample-data/products.json to be sure which fields are critical for Storefront API to work.

Here we present the core purpose of the product properties:

    "id": 1769,

This is a unique product identifier:; it's numeric and it's defined as an integer in the elastic.schema.product.json. However, nowhere in the code is it used as intval. That means when you need to have product IDs presented as GUID's or strings, please just feel free to modify the schema and run yarn db rebuild. Should be fine!

    "name": "Chloe Compete Tank",

This is just a product name 😃

    "image": "/w/t/wt06-blue_main.jpg",

Product image - by deafult, it's relative because vue-storefront-api/img endpoint uses this relative URL against the base platform images URL/CDN to generate the thumbnail.

Note: If you want to use absolute urls, that's not a problem. Please put the absolute URL in this field and then make sure the vue-storefront knows about it by setting the config.images.useExactUrlsNoProxy option. It will use the exact image URLs without the resizer. You can also perform a trick to use the resizer with absolute URLS, by setting the config.images.baseUrl to the URL address containing the placeholder. Something like: https://demo.vuestorefront.io/img/?url=. The magic happens here.

    "sku": "WT06",

The Stock Keeping Unit is a unique string. The format is not restricted to any form. It's used as a cache key for products. It's also used for figuring out the selected configurable variant of a configurable product.

    "url_key": "chloe-compete-tank",
    "url_path": "women/tops-women/tanks-women/bras-and-tanks-26/chloe-compete-tank-1769.html",

As of Vue Storefront 1.9, the url_key is no longer used for URL routing. It's just a string and well, it's optional. The urlo_path, however, is a must. It must be unique across all routable URL addresses, because it's used by the Url Dispatcher to map the URL to a specific product for PDP.

    "type_id": "configurable",

Storefront API supports the following product types:

  • simple - simple products with no configurable options,
  • configurable - products with variants - they're assigned in the configurable_children and the options used to select the proper variant (like color and size) are defined in the configurable_options,
  • bundle - products that consist other products under a single virtual SKU. The sub-products can be configured / checked / unchecked.
  • grouped - products grouping different products that were added to the cart as separate items,
  • virtual - virtual products are partially supported (Vue Storefront does not ask the user for shipping information if there are just virtuals in the cart, that's it).

The routes in the Vue Storefront are customizable to specific product types so you can create a different PDP for specific types of products.

    "price": 39,

This is the price that Vue Storefront treats as Net price (not including tax). The thing is that by default Vue Storefront takes the prices from the Elastic/Backend, but you can switch the config.tax.calculateServerSide=false to start calculating taxes in the frontend app (for example based on the current address).

    "special_price": 0,

This is a special price (if set, the price will be crossed over in the UI) - also Net.

    "price_incl_tax": null,
    "special_price_incl_tax": null,

If these fields are set, Vue Storefront shows these prices as default, end-user prices in the store. They should include all the taxes.

    "special_to_date": null,
    "special_from_date": null,

The special price field is limited in time by these dates (should be ISO date format). See how.

    "status": 1,

Product status:

  • <=1 - product is enabledd,
  • 2 - product is disabled,
  • 3 - product is out of stock (however VSF checks the stock.is_in_stock property).
   "visibility": 4,

Visibility status:

  • 1 - not visible (won't be displayed in the listings),
  • 2 - visible in catalog,
  • 3 - visible in search,
  • 4 - visible in both.
    "size": null,
    "color": null,

Color, size - typically numerical indexes. Vue Storefront for all non system properties loads the attribute definitions.

If the definition exists then, if the type is select or multiselect the value of the property is used as the index in the attribute values dictionary. Read more on attributes. Otherwise, it's being used as text.

So you can put any color name you like in this field and it still could be used for product browsing. This is, for example, how the bigcommerce2vuestorefront integration works. It doesn't use the attribute metadata at all because, for some platforms using a kind of Wordpress like semantics, it's very hard to create an attribute dictionary.

    "size_options": [
      167,
      168,
      169,
      170,
      171
    ],
    "color_options": [
      50,
      58,
      60
    ],

For any property (color and sizes are just an examples) you might want to create a propertyName + "_options" helper which is used for product filtering. In this case, it consist of all configurable_children colors and sizes.

    "category_ids": [
      "26"
    ],

Category IDs (don't have to be numerical but usually are 😃). This field is used for product filtering on the Category.vue page in Vue Storefront.

    "category": [
      {
        "category_id": 26,
        "name": "Bras & Tanks",
        "slug": "bras-and-tanks-26",
        "path": "women/tops-women/tanks-women/bras-and-tanks-26"
      }
    ],

In addition to category_ids, we have a category collection which is a denormalized set of categories assigned to this product. It is used in the SearchPanel for generating the output categories in the search results and .. probably that's all. So if you disable this feature, the category property is no longer needed.

    "media_gallery": [
      {
        "image": "/w/t/wt06-blue_main.jpg",
        "pos": 1,
        "typ": "image",
        "lab": null,
        "vid": null
      },
      {
        "image": "/w/t/wt06-blue_back.jpg",
        "pos": 2,
        "typ": "image",
        "lab": null,
        "vid": null
      }
    ],

This is just a list of images used by the ProductGallery component. Paths can be relative or absolute - exactly the same as with product.image.

    "configurable_options": [
      {
        "id": 300,
        "attribute_id": "93",
        "label": "Color",
        "position": 1,
        "values": [
          {
            "value_index": 50,
            "label": "Blue"
          },
          {
            "value_index": 58,
            "label": "Red"
          },
          {
            "value_index": 60,
            "label": "Yellow"
          }
        ],
        "product_id": 1769,
        "attribute_code": "color"
      },
      {
        "id": 301,
        "attribute_id": "142",
        "label": "Size",
        "position": 0,
        "values": [
          {
            "value_index": 167,
            "label": "XS"
          },
          {
            "value_index": 168,
            "label": "S"
          },
          {
            "value_index": 169,
            "label": "M"
          },
          {
            "value_index": 170,
            "label": "L"
          },
          {
            "value_index": 171,
            "label": "XL"
          }
        ],
        "product_id": 1769,
        "attribute_code": "size"
      }
    ],

This collection contains all configurable options that can be used to identify a simple product, assigned in the configurable_children collection. Usually, it's a set of available colors and sizes. It is used to construct the Color/Size switcher on the Product.vue page. If you set the proper label's then the attribute_id is not required. It means you don't have to have the attribute defined in the dictionary. It's a pretty usefull option for platforms that don't support attribute dictionaries like BigCommerce.

    "stock": [
      {
        "is_in_stock": true,
        "qty": 0
      }
    ],

Stock is used to check if a product is available or not. There is also an api/stock endpoint (to be implemented dynamically) to make sure Vue Storefront is up to date with the data. This Elastic based stock is used mostly for filtering out unavailable products (and not as a source of truth for adding to the cart).

    "configurable_children": [
      {
        "type_id": null,
        "sku": "WT06-XS-Blue",
        "special_price": 0,
        "special_to_date": null,
        "special_from_date": null,
        "name": "Chloe Compete Tank-XS-Blue - tier price",
        "price": 39,
        "price_incl_tax": null,
        "special_price_incl_tax": null,
        "id": 1754,
        "image": "/w/t/wt06-blue_main.jpg",
        "url_key": "chloe-compete-tank-xs-blue",
        "url_path": null,
        "status": 1,
        "size": "167",
        "color": "50"
      },
      {
        "type_id": null,
        "sku": "WT06-XS-Red",
        "special_price": 0,
        "special_to_date": null,
        "special_from_date": null,
        "name": "Chloe Compete Tank-XS-Red",
        "price": 39,
        "price_incl_tax": null,
        "special_price_incl_tax": null,
        "id": 1755,
        "image": "/w/t/wt06-red_main.jpg",
        "url_key": "chloe-compete-tank-xs-red",
        "url_path": null,
        "status": 1,
        "size": "167",
        "color": "58"
      }
    ]
  },

All configurable products consist of simple products assigned to the configurable_childdren collection. Those are the ones finally ordered. The important feature of the configurable_children collection is that it should consist of only the properties that differentiate these products from the main configurable one. You could probably skip the name. It's because each product is merged with its configurable_children - well, selected configurable children when the user switches the color and sizes. There is a Vuex action product/confgure which performs exactly this merge operation.

# What was skipped?

We haven't described the Bundle and Grouped products yet. It's on our TODO 😃