docs: add documentation for v1.8 (#3669)

This commit is contained in:
Shahed Nasser authored and GitHub committed 2023-04-03 13:50:59 +02:00
1 parent 0cca13779d
commit c6bfad14d8
123 files changed
+7610 -2697

No files matched your search

@@ -20,11 +20,7 @@ Using Medusa’s [Batch Job Admin APIs](/api/admin/#tag/Batch-Job), you can impo
### Medusa Components
It is assumed that you already have a Medusa backend installed and set up. If not, you can follow the [quickstart guide](../../../development/backend/install.mdx) to get started.
### Redis
Redis is required for batch jobs to work. Make sure you [install Redis](../../../development/backend/prepare-environment.mdx#redis) and [configure it with the Medusa backend](../../../development/backend/configurations.md#redis).
It is assumed that you already have a Medusa backend installed and set up. If not, you can follow the [quickstart guide](../../../development/backend/install.mdx) to get started. The Medusa backend must also have an event bus module installed, which is available when using the default Medusa backend starter.
### File Service Plugin
@@ -0,0 +1,678 @@
---
description: 'Learn how to how to manage product categories using the admin REST APIs. Learn how to create, update, and delete categories, and how to manage products in a category.'
addHowToData: true
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
# How to Manage Product Categories
In this document, you’ll learn how to manage product categories using the admin REST APIs.
## Overview
Using the product category admin REST APIs, you can manage the categories in your commerce application.
### Scenario
You want to add or use the following admin functionalities:
- Manage categories including list, create, edit, and delete categories.
- Manage products in a category, including adding or removing products from a category.
---
## Prerequisites
### Medusa Components
It is assumed that you already have a Medusa backend installed and set up. If not, you can follow the [quickstart guide](../../../development/backend/install.mdx) to get started.
### JS Client
This guide includes code snippets to send requests to your Medusa backend using Medusa’s JS Client, among other methods.
If you follow the JS Client code blocks, it’s assumed you already have [Medusa’s JS Client](../../../js-client/overview.md) installed and have [created an instance of the client](../../../js-client/overview.md#configuration).
### Medusa React
This guide also includes code snippets to send requests to your Medusa backend using Medusa React, among other methods.
If you follow the Medusa React code blocks, it's assumed you already have [Medusa React installed](../../../medusa-react/overview.md) and have [used MedusaProvider higher in your component tree](../../../medusa-react/overview.md#usage).
### Authenticated Admin User
You must be an authenticated admin user before following along with the steps in the tutorial.
You can learn more about [authenticating as an admin user in the API reference](/api/admin/#section/Authentication).
---
## List Categories
You can retrieve available categories by sending a request to the [List Categories](/api/admin#tag/Product-Category/operation/GetProductCategories) endpoint:
<Tabs groupId="request-type" wrapperClassName="code-tabs">
<TabItem value="client" label="Medusa JS Client" default>
```ts
medusa.admin.productCategories.list()
.then(({ product_categories, limit, offset, count }) => {
console.log(product_categories.length)
// display categories
})
```
</TabItem>
<TabItem value="medusa-react" label="Medusa React">
```tsx
import { useAdminProductCategories } from "medusa-react"
import { ProductCategory } from "@medusajs/medusa"
function Categories() {
const {
product_categories,
isLoading } = useAdminProductCategories()
return (
<div>
{isLoading && <span>Loading...</span>}
{product_categories && !product_categories.length && (
<span>No Product</span>
)}
{product_categories && product_categories.length > 0 && (
<ul>
{product_categories.map(
(category: ProductCategory) => (
<li key={category.id}>{category.name}</li>
)
)}
</ul>
)}
</div>
)
}
export default Categories
```
</TabItem>
<TabItem value="fetch" label="Fetch API">
```ts
fetch(`<BACKEND_URL>/admin/product-categories`, {
credentials: "include",
})
.then((response) => response.json())
.then(({ product_categories, limit, offset, count }) => {
console.log(product_categories.length)
// display product categories
})
```
</TabItem>
<TabItem value="curl" label="cURL">
```bash
curl -L -X GET '<BACKEND_URL>/admin/product-categories' \
-H 'Authorization: Bearer <API_TOKEN>'
```
</TabItem>
</Tabs>
This request returns an array of product categories, as well as [pagination fields](/api/admin#section/Pagination).
You can also pass filters and other selection query parameters to the request. Check out the [API reference](/api/admin#tag/Product-Category/operation/GetProductCategories) for more details on available query parameters.
---
## Create a Category
You can create a category by sending a request to the [Create a Category](/api/admin#tag/Product-Category/operation/PostProductCategories) endpoint:
<Tabs groupId="request-type" wrapperClassName="code-tabs">
<TabItem value="client" label="Medusa JS Client" default>
```ts
medusa.admin.productCategories.create({
name: "Skinny Jeans",
})
.then(({ product_category }) => {
console.log(product_category.id)
})
```
</TabItem>
<TabItem value="medusa-react" label="Medusa React">
```tsx
import { useAdminCreateProductCategory } from "medusa-react"
const CreateCategory = () => {
const createCategory = useAdminCreateProductCategory()
// ...
const handleCreate = () => {
createCategory.mutate({
name: "Skinny Jeans",
})
}
// ...
}
export default CreateCategory
```
</TabItem>
<TabItem value="fetch" label="Fetch API">
```ts
fetch(`<BACKEND_URL>/admin/product-categories`, {
credentials: "include",
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Skinny Jeans",
}),
})
.then((response) => response.json())
.then(({ product_category }) => {
console.log(product_category.id)
})
```
</TabItem>
<TabItem value="curl" label="cURL">
```bash
curl -L -X POST '<BACKEND_URL>/admin/product-categories' \
-H 'Authorization: Bearer <API_TOKEN>' \
-H 'Content-Type: application/json' \
--data-raw '{
"name": "Skinny Jeans",
}'
```
</TabItem>
</Tabs>
This request requires one body parameter `name`, which is the name of the category. The request also accepts the following optional body parameters:
- `handle`: a string that is typically used as a URL path or slug. If you don’t provide a `handle`, it will be the kebab case format of the name.
- `is_internal`: a boolean that indicates whether the category is visible to customers. By default, it’s `false`.
- `is_active`: a boolean that indicates whether the category is active. By default, it’s `true`.
- `parent_category_id`: An ID of another category that this new category should be a child of.
The request returns the newly created product category.
---
## Retrieve a Category
You can retrieve a product category by sending a request to the [Get a Product Category](/api/admin#tag/Product-Category/operation/GetProductCategoriesCategory) endpoint:
<Tabs groupId="request-type" wrapperClassName="code-tabs">
<TabItem value="client" label="Medusa JS Client" default>
```ts
medusa.admin.productCategories.retrieve(productCategoryId)
.then(({ product_category }) => {
console.log(product_category.id)
})
```
</TabItem>
<TabItem value="medusa-react" label="Medusa React">
```tsx
import { useAdminProductCategory } from "medusa-react"
const Category = () => {
const {
product_category,
isLoading,
} = useAdminProductCategory(productCategoryId)
return (
<div>
{isLoading && <span>Loading...</span>}
{product_category && <span>{product_category.name}</span>}
</div>
)
}
export default Category
```
</TabItem>
<TabItem value="fetch" label="Fetch API">
<!-- eslint-disable max-len -->
```ts
fetch(`<BACKEND_URL>/admin/product-categories/${productCategoryId}`, {
credentials: "include",
})
.then((response) => response.json())
.then(({ product_category }) => {
console.log(product_category.id)
})
```
</TabItem>
<TabItem value="curl" label="cURL">
```bash
curl -L -X GET '<BACKEND_URL>/admin/product-categories/<CAT_ID>' \
-H 'Authorization: Bearer <API_TOKEN>'
```
</TabItem>
</Tabs>
This request requires the ID of the category to be passed as a path parameter.
It returns the full object of the product category.
---
## Edit a Category
You can edit a product category by sending a request to the [Update a Product Category](/api/admin#tag/Product-Category/operation/PostProductCategoriesCategory) endpoint:
<Tabs groupId="request-type" wrapperClassName="code-tabs">
<TabItem value="client" label="Medusa JS Client" default>
```ts
medusa.admin.productCategories.update(productCategoryId, {
name: "Skinny Jeans",
})
.then(({ product_category }) => {
console.log(product_category.id)
})
```
</TabItem>
<TabItem value="medusa-react" label="Medusa React">
```tsx
import { useAdminUpdateProductCategory } from "medusa-react"
const UpdateCategory = () => {
const updateCategory = useAdminUpdateProductCategory(
productCategoryId
)
// ...
const handleUpdate = () => {
updateCategory.mutate({
name: "Skinny Jeans",
})
}
// ...
}
export default UpdateCategory
```
</TabItem>
<TabItem value="fetch" label="Fetch API">
<!-- eslint-disable max-len -->
```ts
fetch(`<BACKEND_URL>/admin/product-categories/${productCategoryId}`, {
credentials: "include",
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Skinny Jeans",
}),
})
.then((response) => response.json())
.then(({ product_category }) => {
console.log(product_category.id)
})
```
</TabItem>
<TabItem value="curl" label="cURL">
```bash
curl -L -X POST '<BACKEND_URL>/admin/product-categories/<CAT_ID>' \
-H 'Authorization: Bearer <API_TOKEN>' \
-H 'Content-Type: application/json' \
--data-raw '{
"name": "Skinny Jeans",
}'
```
</TabItem>
</Tabs>
This request requires the ID of the category to be passed as a path parameter.
In its body, you can pass any of the category’s fields that you want to update. In the code snippet above, you update the name of the category.
You can check the list of accepted fields in the [API reference](/api/admin#tag/Product-Category/operation/PostProductCategoriesCategory).
The request returns the full object of the updated product category.
---
## Manage Products in a Category
:::note
You can manage the categories of each product individually using the [product APIs](/api/admin#tag/Product). This section explores the other approach of managing a product’s category using the product category APIs.
:::
### Add Products to a Category
You can add more than one product to a category using the [Add Products to a Category](/api/admin#tag/Product-Category/operation/PostProductCategoriesCategoryProductsBatch) endpoint:
<Tabs groupId="request-type" wrapperClassName="code-tabs">
<TabItem value="client" label="Medusa JS Client" default>
```ts
medusa.admin.productCategories.addProducts(productCategoryId, {
product_ids: [
{
id: productId1,
},
{
id: productId2,
},
],
})
.then(({ product_category }) => {
console.log(product_category.id)
})
```
</TabItem>
<TabItem value="medusa-react" label="Medusa React">
```tsx
import { useAdminAddProductsToCategory } from "medusa-react"
const UpdateProductsInCategory = () => {
const addProductsToCategory = useAdminAddProductsToCategory(
productCategoryId
)
// ...
const handleAdd = () => {
addProductsToCategory.mutate({
product_ids: [
{
id: productId1,
},
{
id: productId2,
},
],
})
}
// ...
}
export default UpdateProductsInCategory
```
</TabItem>
<TabItem value="fetch" label="Fetch API">
<!-- eslint-disable max-len -->
```ts
fetch(`<BACKEND_URL>/admin/product-categories/${productCategoryId}/products/batch`, {
credentials: "include",
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
product_ids: [
{
id: productId1,
},
{
id: productId2,
},
],
}),
})
.then((response) => response.json())
.then(({ product_category }) => {
console.log(product_category.id)
})
```
</TabItem>
<TabItem value="curl" label="cURL">
```bash
curl -L -X POST '<BACKEND_URL>/admin/product-categories/<CAT_ID>/products/batch' \
-H 'Authorization: Bearer <API_TOKEN>' \
-H 'Content-Type: application/json' \
--data-raw '{
"product_ids": [
{
"id": "productId1"
},
{
"id": "productId2"
}
]
}'
```
</TabItem>
</Tabs>
This request requires the ID of the category to be passed as a path parameter.
In its body, it requires a `product_ids` parameter which is an array of objects. Each object in the array has the property `id`, which is the ID of the product to add. So, each product you want to add you pass it to the array as an object having the property `id`.
The request returns the full object of the product category updated with the new products.
### Remove Products from a Category
You can remove products from a category by sending a request to the [Delete Products](/api/admin#tag/Product-Category/operation/DeleteProductCategoriesCategoryProductsBatch) endpoint:
<Tabs groupId="request-type" wrapperClassName="code-tabs">
<TabItem value="client" label="Medusa JS Client" default>
```ts
medusa.admin.productCategories.removeProducts(
productCategoryId,
{
product_ids: [
{
id: productId1,
},
{
id: productId2,
},
],
}
)
.then(({ product_category }) => {
console.log(product_category.id)
})
```
</TabItem>
<TabItem value="medusa-react" label="Medusa React">
```tsx
import {
useAdminDeleteProductsFromCategory,
} from "medusa-react"
const DeleteProductsFromCategory = () => {
const deleteProductsFromCategory =
useAdminDeleteProductsFromCategory(productCategoryId)
// ...
const handleDelete = () => {
deleteProductsFromCategory.mutate({
product_ids: [
{
id: productId1,
},
{
id: productId2,
},
],
})
}
// ...
}
export default DeleteProductsFromCategory
```
</TabItem>
<TabItem value="fetch" label="Fetch API">
<!-- eslint-disable max-len -->
```ts
fetch(`<BACKEND_URL>/admin/product-categories/${productCategoryId}/products/batch`, {
credentials: "include",
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
product_ids: [
{
id: productId1,
},
{
id: productId2,
},
],
}),
})
.then((response) => response.json())
.then(({ product_category }) => {
console.log(product_category.id)
})
```
</TabItem>
<TabItem value="curl" label="cURL">
```bash
curl -L -X DELETE '<BACKEND_URL>/admin/product-categories/<CAT_ID>/products/batch' \
-H 'Authorization: Bearer <API_TOKEN>' \
-H 'Content-Type: application/json' \
--data-raw '{
"product_ids": [
{
"id": "productId1"
},
{
"id": "productId2"
}
]
}'
```
</TabItem>
</Tabs>
This request requires the ID of the category to be passed as a path parameter.
In its body, it requires a `product_ids` parameter which is an array of objects. Each object in the array has the property `id`, which is the ID of the product to remove. So, each product you want to remove you pass it to the array as an object having the property `id`.
The request returns the full object of the product category updated with the its products.
---
## Delete a Category
You can delete a product category by sending a request to the [Delete a Product Category](/api/admin#tag/Product-Category/operation/DeleteProductCategoriesCategory) endpoint:
<Tabs groupId="request-type" wrapperClassName="code-tabs">
<TabItem value="client" label="Medusa JS Client" default>
```ts
medusa.admin.productCategories.delete(productCategoryId)
.then(({ id, object, deleted }) => {
console.log(id)
})
```
</TabItem>
<TabItem value="medusa-react" label="Medusa React">
```tsx
import { useAdminDeleteProductCategory } from "medusa-react"
const Category = () => {
const deleteCategory = useAdminDeleteProductCategory(
productCategoryId
)
// ...
const handleDelete = () => {
deleteCategory.mutate()
}
// ...
}
export default Category
```
</TabItem>
<TabItem value="fetch" label="Fetch API">
<!-- eslint-disable max-len -->
```ts
fetch(`<BACKEND_URL>/admin/product-categories/${productCategoryId}`, {
credentials: "include",
method: "DELETE",
})
.then((response) => response.json())
.then(({ id, object, deleted }) => {
console.log(id)
})
```
</TabItem>
<TabItem value="curl" label="cURL">
```bash
curl -L -X DELETE '<BACKEND_URL>/admin/product-categories/<CAT_ID>' \
-H 'Authorization: Bearer <API_TOKEN>'
```
</TabItem>
</Tabs>
This request requires the ID of the category to be passed as a path parameter.
The request returns the following fields:
- `id`: The ID of the deleted category.
- `object`: The type of object that was deleted. In this case, the value will be `product-category`.
- `deleted`: A boolean value indicating whether the category was deleted.
@@ -0,0 +1,94 @@
---
description: 'Learn what product categories are and how they work in a Medusa backend. Product categories can be used to organize products using nested collections.'
---
# Product Categories
In this document, you’ll learn about Product Categories and how they can be used in Medusa.
:::note
Product Category feature is currently in beta mode and guarded by a feature flag. To use Product Categories either:
1. Enable the `MEDUSA_FF_PRODUCT_CATEGORIES` environment variable;
2. Or enable the `product_categories` key in the Medusa backend's settings.
You can learn more about enabling it in the [feature flags](../../development/feature-flags/toggle.md) documentation.
:::
## Introduction
Product Categories allow you to categorize your products. You can manage categories in your store. You can also nest categories in one another, creating a parent-child hierarchy, and there is no limit to how far you can nest the categories.
In addition, you can give a category a ranking. As a product can have multiple categories, rankings can be useful in different cases. For example, when you’re unsure what main category to show in the product’s page in the frontend.
### Example Use Cases
Here are some examples of the usage of Product Categories:
- Organizing your large catalog store in a way that showcases to the customer what products you provide.
- Create a multi-brand store, where each category acts as a brand.
---
## Product Category vs Product Collection
Before v1.8 of Medusa, Product Collection was used as the main way of organizing products. It was used similarly to how you would use a Product Category. However, a Product Collection is not only different in what it actually represents, it also doesn’t provide the same functionalities that a Product Category does.
A Product Collection is used to group together a list of products, generally for a marketing purpose. For example, you can create a summer collection when summer comes around with a variety of products in them including shorts, t-shirts, and more.
On the other hand, a Product Category is used to provide easy and clear navigation for customers to help them find what they need. For example, you can have the following nested product categories:
- Women
- Tops
- Jackets
- Sweatshirt
- T-shirt
- etc…
- Bottoms
- Jeans
- Shorts
- etc…
This allows customers to directly choose the category that the product they’re looking for belongs to, and gives them an idea of what products your store offers. If you were to use Product Collections here, as they don’t support nesting, all of these categories would have to be separate collections that are not tied together.
---
## ProductCategory Entity Overview
A product category is stored in the database as a `ProductCategory` entity. Some of its important attributes are:
- `id`: The ID of the product category.
- `name`: The name of the product category.
- `handle`: A string indicating a slug path of the category. It’s useful when creating a page on your storefront for the category, as the `handle` can be used as the path in the URL.
- `is_active`: A boolean value indicating the status of the Product Category.
- `is_internal`: A boolean value indicating the visibility of the Product Category.
- `mpath`: A string value that keeps the IDs of all the category’s ancestors, delimited by a dot (`.`). This attribute is generated by Typeorm. For example, `pcat_id1.pcat_id2.pcat_id3`.
---
## Relations to other Entities
### Products
Products can be available in more than one category. You can then filter products by a single or list of product categories.
The relation is implemented in the Product entity. You can access the product categories a product is available in by expanding the `categories` relation and using `product.categories`
### ProductCategory
The parent-child hierarchy is represented in the `ProductCategory` entity through the following relations:
- You can access the parent of a category by expanding the `parent_category` relation and accessing `category.parent_category`. You can also access the ID of the parent category by accessing `category.parent_category_id`. If a category doesn’t have a parent, the relation and the ID will be `null`.
- You can access the children of a category by expanding the `category_children` relation and accessing `category.category_children`. If a category doesn’t have children, the relation will be an empty array. By default, when expanding this relation in Product Category endpoints, only the immediate child categories are returned. If you want to get the entire heirarchy of child categories, you must pass the `include_descendants_tree` flag to the endpoint setting its value to `true`.
Aside from these relations, the `mpath` attribute, which is a [Materialized Path](https://typeorm.io/tree-entities#materialized-path-aka-path-enumeration) that is automatically generated by Typeorm, can be used to query deep trees faster.
![product-categories.jpg](https://res.cloudinary.com/dza7lstvk/image/upload/v1679916789/Medusa%20Docs/Diagrams/product-categories_x4qp5u.jpg)
---
## See Also
- [How to manage product categories using the admin APIs](./admin/manage-categories.mdx)
+19 -11
View File
@@ -29,7 +29,6 @@ Admins can manage unlimited amount of products and their variants. They can mana
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to manage products using Admin APIs.',
isSoon: true,
}
},
{
@@ -55,37 +54,37 @@ Admins can manage unlimited amount of products and their variants. They can mana
### Product Organization
Admins can organize products into collections, tags, types, and more.
Admins can organize products into categories, collections, tags, types, and more.
Customers can use this organization to filter products while browsing them.
<DocCardList colSize={4} items={[
{
type: 'link',
href: '#',
label: 'Admin: Manage Collections',
href: '/modules/products/admin/manage-categories',
label: 'Admin: Manage Categories',
customProps: {
icon: Icons['academic-cap-solid'],
description: 'Learn how to manage collections using Admin APIs.',
description: 'Learn how to manage categories using Admin APIs.',
isSoon: true,
}
},
{
type: 'link',
href: '/user-guide/products/collections',
label: 'User Guide: Manage Collections',
href: '/user-guide/products/categories',
label: 'User Guide: Manage Categories',
customProps: {
icon: Icons['users-solid'],
description: 'Learn how to manage collections in Medusa Admin.'
description: 'Learn how to manage categories in the Medusa Admin.'
}
},
{
type: 'link',
href: '#',
label: 'Storefront: Show Collections',
label: 'Storefront: Use Categories',
customProps: {
icon: Icons['server-solid'],
description: 'Learn how to show collections in a storefront.',
description: 'Learn how to use categories in a storefront.',
isSoon: true,
}
},
@@ -131,7 +130,7 @@ Admins can bulk import and export products using CSV files. This facilitates mov
Learn how product-related entities are build, their relation to other modules, and more.
<DocCardList colSize={6} items={[
<DocCardList colSize={4} items={[
{
type: 'link',
href: '#',
@@ -142,6 +141,15 @@ Learn how product-related entities are build, their relation to other modules, a
isSoon: true,
}
},
{
type: 'link',
href: '/modules/products/categories',
label: 'Architecture: Category',
customProps: {
icon: Icons['circle-stack-solid'],
description: 'Learn about the Product Category Architecture.',
}
},
{
type: 'link',
href: '#',