diff --git a/www/apps/docs/content/plugins/cms/contentful.md b/www/apps/docs/content/plugins/cms/contentful.md new file mode 100644 index 0000000000..6855cae066 --- /dev/null +++ b/www/apps/docs/content/plugins/cms/contentful.md @@ -0,0 +1,602 @@ +--- +addHowToData: true +--- + +# Contentful Plugin + +In this document, you’ll learn how to install and use the Contentful plugin. + +## Overview + +[Contentful](https://www.contentful.com/) is a headless CMS service that allows developers to integrate rich CMS functionalities into any platform. + +By integrating Contentful to Medusa, you can benefit from powerful features in your ecommerce store including detailed product CMS details, easy-to-use interface to use for static content and pages, localization, and much more. The data is also automatically synced between Contentful and your Medusa store. + +--- + +## Prerequisites + +### Medusa Components + +This guide assumes you already have a Medusa backend installed. If not, you can learn how to install it [here](../../create-medusa-app.mdx). + +Redis must also be configured in your Medusa backend if you want to sync data from Medusa to Contentful. Learn how to configure it [here](../../development/backend/configurations.md#redis_url). + +### Needed Account + +- [Contentful](https://www.contentful.com/sign-up/) account with a space created. A space is created by default when you create a new account. + +--- + +## Install Plugin + +In the directory of your Medusa backend, run the following command to install the Contentful plugin: + +```bash npm2yarn +npm install medusa-plugin-contentful +``` + +Next, add the plugin into the `plugins` array in `medusa-config.js`: + +```js title=medusa-config.js +const plugins = [ + // ... + { + resolve: `medusa-plugin-contentful`, + options: { + space_id: process.env.CONTENTFUL_SPACE_ID, + access_token: process.env.CONTENTFUL_ACCESS_TOKEN, + environment: process.env.CONTENTFUL_ENV, + }, + }, +] +``` + +### Plugin Options + +The plugin accepts the following options: + +1. `space_id`: (required) a string indicating the ID of your Contentful space. Refer to [Contentful’s documentation](https://www.contentful.com/help/find-space-id/) if you’re unsure where to find it. +2. `access_token`: (required) a string indicating the personal access token for content management. Refer to [Contentful’s documentation](https://www.contentful.com/help/personal-access-tokens/#how-to-get-a-personal-access-token-the-web-app) to learn how to create it. +3. `environment`: (required) a string indicating the [Contentful environment](https://www.contentful.com/developers/docs/concepts/multiple-environments/). Typically, its value should be `master`. +4. `ignore_threshold`: (optional) a number indicating the number of seconds to wait before re-syncing a specific record. By default, its value is `2`. +5. `custom__fields`: (optional) an object that allows you to map fields in Medusa to custom field names. Learn more [here](#custom-field-mapping). + +Make sure to add required values as environment variables: + +```bash +CONTENTFUL_SPACE_ID= +CONTENTFUL_ACCESS_TOKEN= +CONTENTFUL_ENV=master +``` + +### Custom Field Mapping + +When the plugin syncs data between Contentful and Medusa, it expects a set of fields to be defined in the respective content models in Contentful. If you choose to use different names to define those fields in Contentful, you have to specify them in the `custom__fields` option mentioned earlier, where `` is the name of the content model. + +For example, to change the name of the product’s `title` field, pass the following option to the plugin: + +```js title=medusa-config.js +const plugins = [ + // ... + { + resolve: `medusa-plugin-contentful`, + options: { + space_id: process.env.CONTENTFUL_SPACE_ID, + access_token: process.env.CONTENTFUL_ACCESS_TOKEN, + environment: process.env.CONTENTFUL_ENV, + custom_product_fields: { + title: "name", + }, + }, + }, +] +``` + +The rest of this section includes the field names you can customize using this option for each content model type. + +
+ +product + + +- `title` +- `subtitle` +- `description` +- `variants` +- `options` +- `medusaId` +- `type` +- `collection` +- `tags` +- `handle` + +
+ +
+ +variant + + +- `title` +- `sku` +- `prices` +- `options` +- `medusaId` + +
+ +
+ +region + + +- `name` +- `countries` +- `paymentProviders` +- `fulfillmentProviders` +- `medusaId` + +
+ +
+ +collection + + +- `title` +- `medusaId` + +
+ +
+ +type + + +- `name` +- `medusaId` + +
+ +### Migrate Content Models + +In your Contentful space, you must have content models for Medusa entities such as products and regions. + +You can either create the content models manually, or you can write a migration script in the Medusa backend that migrates these content models into Contentful. + +This section includes migration scripts for Medusa’s entities that are relevant for Contentful. You can customize the scripts if necessary. You can also create scripts for custom content models, such as a Link or Navigation Item content model. + +Before creating the migration scripts, run the following command in the root of your Medusa backend to install Contentful’s migration SDK: + +```bash npm2yarn +npm install --save-dev contentful-migration +``` + +
+ +product Content Model + + +Create the file `src/loaders/contentful-migrations/product.ts` with the following content: + +```ts title=src/loaders/contentful-migrations/product.ts +import Migration, { + MigrationContext, +} from "contentful-migration" + +export function productMigration( + migration: Migration, + context?: MigrationContext +) { + const product = migration + .createContentType("product") + .name("Product") + .displayField("title") + + product + .createField("title") + .name("Title") + .type("Symbol") + .required(true) + product + .createField("subtitle") + .name("Subtitle") + .type("Symbol") + product + .createField("handle") + .name("Handle") + .type("Symbol") + product + .createField("thumbnail") + .name("Thumbnail") + .type("Link") + .linkType("Asset") + product + .createField("description") + .name("Description") + .type("Text") + product + .createField("options") + .name("Options") + .type("Object") + product + .createField("tags") + .name("Tags") + .type("Object") + product + .createField("collection") + .name("Collection") + .type("Symbol") + product + .createField("type") + .name("Type") + .type("Symbol") + product + .createField("variants") + .name("Variants") + .type("Array") + .items({ + type: "Link", + linkType: "Entry", + validations: [ + { + linkContentType: ["productVariant"], + }, + ], + }) + product + .createField("medusaId") + .name("Medusa ID") + .type("Symbol") +} +``` + +
+ +
+ +productVariant Content Model + + +Create the file `src/loaders/contentful-migrations/product-variant.ts` with the following content: + +```ts title=src/loaders/contentful-migrations/product-variant.ts +import Migration, { + MigrationContext, +} from "contentful-migration" + +export function productVariantMigration( + migration: Migration, + context?: MigrationContext +) { + const productVariant = migration + .createContentType("productVariant") + .name("Product Variant") + .displayField("title") + + productVariant + .createField("title") + .name("Title") + .type("Symbol") + .required(true) + productVariant + .createField("sku") + .name("SKU") + .type("Symbol") + productVariant + .createField("options") + .name("Options") + .type("Object") + productVariant + .createField("prices") + .name("Prices") + .type("Object") + productVariant + .createField("medusaId") + .name("Medusa ID") + .type("Symbol") +} +``` + +
+ +
+ +collection Content Model + + +Create the file `src/loaders/contentful-migrations/product-collection.ts` with the following content: + +```ts title=src/loaders/contentful-migrations/product-collection.ts +import Migration, { + MigrationContext +} from "contentful-migration"; + +export function productCollectionMigration ( + migration: Migration, + context?: MigrationContext +) { + const collection = migration + .createContentType("collection") + .name("Product Collection") + .displayField("title"); + + collection + .createField("title") + .name("Title") + .type("Symbol") + .required(true); + collection + .createField("medusaId") + .name("Medusa ID") + .type("Symbol"); +}; +``` +
+ +
+ +productType Content Model + + +Create the file `src/loaders/contentful-migrations/product-type.ts` with the following content: + +```ts title=src/loaders/contentful-migrations/product-type.ts +import Migration, { + MigrationContext +} from "contentful-migration"; + +export function productTypeMigration ( + migration: Migration, + context?: MigrationContext +) { + const collection = migration + .createContentType("productType") + .name("Product Type") + .displayField("title"); + + collection + .createField("title") + .name("Title") + .type("Symbol") + .required(true); + collection + .createField("medusaId") + .name("Medusa ID") + .type("Symbol"); +}; +``` +
+ +
+ +region Content Model + + +Create the file `src/loaders/contentful-migrations/region.ts` with the following content: + +```ts title=src/loaders/contentful-migrations/region.ts +import Migration, { + MigrationContext, +} from "contentful-migration" + +export function regionMigration( + migration: Migration, + context?: MigrationContext +) { + const region = migration + .createContentType("region") + .name("Region") + .displayField("name") + + region + .createField("name") + .name("Name") + .type("Symbol") + .required(true) + region + .createField("countries") + .name("Options") + .type("Object") + region + .createField("paymentProviders") + .name("Payment Providers") + .type("Object") + region + .createField("fulfillmentProviders") + .name("Fulfillment Providers") + .type("Object") + region + .createField("currencyCode") + .name("Currency Code") + .type("Symbol") + region + .createField("medusaId") + .name("Medusa ID") + .type("Symbol") +} +``` + +
+ +Finally, create a [loader](../../development/loaders/overview.mdx) at `src/loaders/index.ts` with the following content: + +```ts title=src/loaders/index.ts +import { ConfigModule, StoreService } from "@medusajs/medusa" +import { AwilixContainer } from "awilix" +import { runMigration } from "contentful-migration" +import { + productMigration, +} from "./contentful-migrations/product" +import { + productVariantMigration, +} from "./contentful-migrations/product-variant" +import { + productCollectionMigration, +} from "./contentful-migrations/product-collection" +import { + productTypeMigration, +} from "./contentful-migrations/product-type" +import { + regionMigration, +} from "./contentful-migrations/region" + +type ContentfulPluginType = { + resolve: string + options: { + space_id: string + access_token: string + environment: string + } +} + +export default async ( + container: AwilixContainer, + config: ConfigModule +): Promise => { + // ensure that migration only runs once + const storeService = container.resolve( + "storeService" + ) + const store = await storeService.retrieve() + + if (store.metadata?.ran_contentful_migrations) { + return + } + + console.info("Running contentful migrations...") + + // load Contentful options + const contentfulPlugin = config.plugins + .find((plugin) => + typeof plugin === "object" && + plugin.resolve === "medusa-plugin-contentful" + ) as ContentfulPluginType + + if (!contentfulPlugin) { + console.log( + "Didn't find Contentful plugin. Aborting migration..." + ) + return + } + + const options = { + spaceId: contentfulPlugin.options.space_id, + accessToken: contentfulPlugin.options.access_token, + environment: contentfulPlugin.options.environment, + yes: true, + } + + const migrationFunctions = [ + { + name: "Product", + function: productMigration, + }, + { + name: "Product Variant", + function: productVariantMigration, + }, + { + name: "Product Collection", + function: productCollectionMigration, + }, + { + name: "Product Type", + function: productTypeMigration, + }, + { + name: "Region", + function: regionMigration, + }, + ] + + await Promise.all( + migrationFunctions.map(async (migrationFunction) => { + console.info(`Migrating ${ + migrationFunction.name + } component...`) + try { + await runMigration({ + ...options, + migrationFunction: migrationFunction.function, + }) + console.info(`Finished migrating ${ + migrationFunction.name + } component`) + } catch (e) { + if ( + typeof e === "object" && "errors" in e && + Array.isArray(e.errors) && + e.errors.length > 0 && + e.errors[0].type === "Invalid Action" && + e.errors[0].message.includes("already exists") + ) { + console.info(`${ + migrationFunction.name + } already exists. Skipping its migration.`) + } else { + throw new Error(e) + } + } + }) + ) + + await storeService.update({ + metadata: { + ran_contentful_migrations: true, + }, + }) + + console.info("Finished contentful migrations") +} +``` + +Notice that in the script you store a flag in the default store’s `metadata` attribute to ensure these migrations only run once. + +### Setup Webhooks + +As mentioned in the introduction, this plugin supports two-way sync. A [subscriber](../../development/events/create-subscriber.md) listens to changes in the data, such as adding a new product, and syncs the data with Contentful. + +To update the Medusa backend when changes occur in Contentful, you must configure webhooks settings in Contentful. + +:::note + +For webhooks to work, your backend must be deployed and accessible publicly. If you haven’t deployed your backend, refer to [these deployment guides](../../deployments/server/index.mdx). + +::: + +To do that: + +1. On your Contentful Space Dashboard, click on Settings from the navigation bar, then choose Webhooks. +2. Click on the Add Webhook button. +3. In the form, enter a name for the webhook. +4. In the URL field, choose the method `POST` and in the input next to it enter the URL `/hooks/contentful` where `` is the URL of your deployed Medusa backend. +5. Scroll down to find the Content Type select field. Choose `application/json` as its value. +6. You can leave the rest of the fields the same and click on the Save button. + +--- + +## Test the Plugin + +Run the following command to start your Medusa backend and test the plugin: + +```bash +npx medusa develop +``` + +If you created migration scripts, they’ll run when the Medusa backend first starts and migrate your content models to Contentful. You can go to your space’s dashboard to confirm they’ve been created. + +After that, try the sync functionality by creating or updating products in the Medusa backend. If you’ve also setup webhooks, you can test out the sync from Contentful to Medusa. + +:::note + +As mentioned in the [Prerequisites section](#prerequisites), you must configure Redis for the Medusa to Contentful sync to work. + +::: + +--- + +## What’s Next? + +After installing the plugin, you can either customize the [Next.js storefront](../../starters/nextjs-medusa-starter.mdx) to fetch data from Contentful, or [build a storefront](../../storefront/roadmap.mdx) that connects to both Medusa and Contentful. diff --git a/www/apps/docs/content/plugins/cms/contentful/customize-contentful.md b/www/apps/docs/content/plugins/cms/contentful/customize-contentful.md deleted file mode 100644 index bae4f7c365..0000000000 --- a/www/apps/docs/content/plugins/cms/contentful/customize-contentful.md +++ /dev/null @@ -1,335 +0,0 @@ ---- -description: 'Learn how to customize the Contentful integration with Medusa and how to customize the Gatsby storefront that is connected to Contentful.' -addHowToData: true ---- - -# Customize your Medusa and Contentful Integration - -In this document, you’ll learn how to customize the Contentful integration with Medusa and how to customize the Gatsby storefront that is connected to Contentful. - -:::warning - -This guide covers how to customize the Gatsby storefront which is now deprecated. It's recommended to integrate Contentful into either the Next.js Starter Template or your custom storefront. - -::: - -## Overview - -Part of what makes the integration between Medusa and Contentful powerful is that it’s completely customizable. - -On the backend, you can create Contentful migrations that allow you to add or edit Content Types in Contentful. Although this can be done through Contentful’s interface, this solution allows you to create a reusable codebase for your store that is independent of a specific Contentful Space. - -On your storefront, you can add any necessary components that can render the Content Types you create. - -As an example to explain this process, in this documentation, you’ll create a migration that creates a Rich Text content model in Contentful and edits the Page and Product content models to allow using Rich Text content as a tile in pages and products. Then, you’ll modify the Gatsby storefront to render the Rich Text content model. - ---- - -## Prerequisites - -It’s assumed you already have set up a Medusa backend integrated with Contentful and have a Gatsby storefront integrated with Contentful. If not, [please follow this documentation first](index.md). - ---- - -## Create a Contentful Migration - -The Contentful migrations are located in the `contentful-migrations` directory in the Medusa Contentful backend starter. So, if you want to create your own Contentful migrations, you can create them under that directory. - -Here’s an example of a migration created in a new file `contentful-migrations/rich-text.js`: - -```jsx title=contentful-migrations/rich-text.js -#! /usr/bin/env node - -require("dotenv").config() - -const { runMigration } = require("contentful-migration") - -const options = { - spaceId: process.env.CONTENTFUL_SPACE_ID, - accessToken: process.env.CONTENTFUL_ACCESS_TOKEN, - environment: process.env.CONTENTFUL_ENVIRONMENT, - yes: true, -} - -const migration = async () => { - await runMigration({ - ...options, - migrationFunction: function (migration, context) { - - // create Rich Text content model - const richText = migration - .createContentType("richText") - .name("Rich Text") - .displayField("title") - - richText - .createField("title") - .name("Title (Internal)") - .type("Symbol") - richText - .createField("body") - .name("Body") - .type("RichText") - - // edit Page content model - const page = migration.editContentType("page") - - page.editField("contentModules").items({ - type: "Link", - linkType: "Entry", - validations: [ - { - linkContentType: [ - "hero", "tileSection", "richText", - ], - }, - ], - }) - - // edit Product content model - const product = migration.editContentType("product") - - product - .createField("contentModules") - .name("Content Modules") - .type("Array") - .items({ - type: "Link", - linkType: "Entry", - validations: [ - { - linkContentType: ["richText"], - }, - ], - }) - }, - }) -} - -migration() -``` - -This example creates a new content model Rich Text that has two fields: title and body. It also edits the Page content model to allow using Rich Text content models on the page. - -In addition, it edits the Product content model by adding a new field `contentModules`. This field accepts an array of sections that can be of type Rich Text. This allows you to display rich details on a product page. - -You can also add other types of content models the `contentModules` should accept. For example, to accept `tileSection` add it to the `linkContentType` option: - -```jsx -product - .createField("contentModules") - .name("Content Modules") - .type("Array") - .items({ - type: "Link", - linkType: "Entry", - validations: [ - { - linkContentType: ["richText", "tileSection"], - }, - ], - }) -``` - -### Run a Contentful Migration - -To run a Contentful Migration that you create you can use the following command: - -```bash -node -``` - -Where `` is the path of the file you created. - -To run the Contentful migration in the previous example, you can use the following command: - -```bash -node contentful-migrations/rich-text.js -``` - -This runs the Contentful migration in that file and makes the necessary changes in your Contentful Space. - -### Test if Contentful Migration Worked - -To check if the above migration worked, in your Contentful Space dashboard go to Content Models from the navigation bar. You should see the new content model Rich Text. - -The above migration also allows you to add Rich Text content to pages. To test this out: - -1. Go to Content from the navigation bar. -2. Choose Page in the select field next to the search bar. This shows the available pages in your Contentful Space. -3. Choose one of the pages. For example, the About page. -4. Scroll down to the Add content button. If you click on it, you should be able to choose Rich Text under New Content. -5. Click on Rich Text and a new form will open to create new Rich Text content. It has the same fields that you defined in the migration file. -6. After adding the content you want, click on the Publish button on the right then go back to the About page editor. -7. Similarly, in the About page editor, click on the Publish Changes button on the right to view these changes later in the storefront. -8. Similarly, you can add Rich Text content to any product page. - ---- - -## Render New Content Models in the Storefront - -After creating a new content model in your Contentful Space, you must add the necessary component to render it in your Gatsby storefront. - -### Create Component - -To render the Rich Text content you created in the previous example, create the file `src/components/rich-text/rich-text.js` with the following content: - -```jsx title=src/components/rich-text/rich-text.js -import React from "react" -import { - renderRichText, -} from "gatsby-source-contentful/rich-text" - -const RichText = ({ data }) => { - return ( -
- {data.body ? renderRichText(data.body) : ""} -
- ) -} - -export default RichText -``` - -This creates the component `RichText` responsible for rendering the Rich Text content model. Notice that the fields of the content model are available under the `data` prop variable. - -### Render Component in a Page - -Since the Rich Text model can be added to any page, you must edit `src/pages/{ContentfulPage.slug}.js` to show it. - -In `src/pages/{ContentfulPage.slug}.js`, import the `RichText` component at the top of the file: - -```jsx title=src/pages/{ContentfulPage.slug}.js -import RichText from "../components/rich-text/rich-text" -``` - -Then, in the returned JSX add a new case to the switch statement: - -```jsx title=src/pages/{ContentfulPage.slug}.js -switch (cm.internal.type) { - // ... - case "ContentfulRichText": - return - default: - return null -} -``` - -If the content model of a tile is Rich Text, you’ll display it with the `RichText` component. - -Finally, to retrieve all necessary data of the Rich Text content, in the `query` GraphQL variable add the following after the `... on ContentfulTileSection` fragment: - -```jsx title=src/pages/{ContentfulPage.slug}.js -export const query = graphql` - # find the following line - ... on ContentfulTileSection { - - } - # add the following - ... on ContentfulRichText { - id - body { - raw - } - internal { - type - } - } - } - } - } -` -``` - -### Test Rich Text in Page Content - -To test this out, run your Medusa backend by running this command in its directory: - -```bash npm2yarn -npx medusa develop -``` - -Then run the Gatsby storefront by running this command in its directory: - -```bash npm2yarn -npm run start -``` - -This runs the Gatsby storefront on `localhost:8000`. Go to the storefront in your browser and open the About page. You should see the Rich Text content you added. - -### Render Component in a Product Page - -In the example migration, you also edited the product page to include a new Content Modules field that allows inserting Rich Text content. - -To render them on the Product Page, add the following in the GraphQL query defined in the `query` variable inside `product`: - -```jsx title=src/pages/{ContentfulPage.slug}.js -export const query = graphql` - query ($id: String!) { - product: contentfulProduct(id: { eq: $id }) { - # Other fields - contentModules { - ... on ContentfulRichText { - id - body { - raw - } - internal { - type - } - } - } - } - } -` -``` - -:::note - -If you added other accepted Content Models to the `contentModules` field of the Product content type, make sure to add them here. - -::: - -Then, in `src/views/product.js` import the `RichText` component: - -```jsx title=src/views/product.js -import RichText from "../components/rich-text/rich-text" -``` - -And in the returned JSX add the following before the last ``: - -```jsx title=src/views/product.js -
- {product.contentModules?.map((cm) => { - switch (cm.internal.type) { - case "ContentfulRichText": - return - default: - return null - } - })} -
-``` - -:::note - -If you added other accepted Content Models to the `contentModules` field of the Product content type, make sure to add cases for them here to display them. - -::: - -This loops over `contentModules` and if the type of the content is Rich Text, it is rendered with the `RichText` component. - -### Test Rich Text on a Product Page - -Restart the Gatsby storefront then open a product that you added Rich Text content to. You should see the Rich Text component at the end of the page. - ---- - -## See Also - -- How to deploy your Medusa backend to [Heroku](../../../deployments/server/deploying-on-heroku.mdx), or [DigitalOcean](../../../deployments/server/deploying-on-digital-ocean.md), or [other providers](../../../deployments/server/index.mdx) \ No newline at end of file diff --git a/www/apps/docs/content/plugins/cms/contentful/index.md b/www/apps/docs/content/plugins/cms/contentful/index.md deleted file mode 100644 index e90b17c64c..0000000000 --- a/www/apps/docs/content/plugins/cms/contentful/index.md +++ /dev/null @@ -1,297 +0,0 @@ ---- -description: 'Learn how to integrate Contentful with the Medusa backend and a Gatsby storefront. Contentful is a headless CMS backend that provides rich CMS functionalities.' -addHowToData: true ---- - -# Contentful - -In this document, you’ll learn how to integrate a Medusa backend with Contentful to add rich Content Management System (CMS) functionalities - -## Overview - -[Contentful](https://www.contentful.com/) is a headless CMS service that allows developers to integrate rich CMS functionalities into any platform. - -By integrating Contentful to Medusa, you can benefit from powerful features in your ecommerce store including detailed product CMS details, easy-to-use interface to use for static content and pages, localization, and much more. - ---- - -## Prerequisites - -### Needed Accounts - -- [Contentful](https://www.contentful.com/sign-up/) account with a space created. A space is created by default when you create a new account. - -### Required Tools - -- PostgreSQL with an empty database created. You can follow [this documentation to learn how to install it for your operating system](../../../development/backend/prepare-environment.mdx#postgres). -- Redis. You can follow [their documentation to learn how to install it](https://redis.io/docs/getting-started/installation/). -- Git’s CLI tool. You can follow [this documentation to learn how to install it for your operating system](../../../development/backend/prepare-environment.mdx#git). -- Gatsby’s CLI tool. You can follow [this documentation to install it](https://www.gatsbyjs.com/docs/reference/gatsby-cli/#how-to-use-gatsby-cli). -- Medusa’s CLI tool. You can follow [this documentation to install it](../../../cli/reference.mdx#how-to-install-cli-tool). - ---- - -## Install Medusa Backend Using Contentful Starter - -Instead of using the default Medusa backend starter, you must use the [Contentful starter](https://github.com/medusajs/medusa-starter-contentful) to install a backend that is ready to be used with Contentful. This backend contains all the necessary files to make the integration work. - -In your terminal, run the following command to install the backend: - -```bash -npx @medusajs/medusa-cli@latest new medusa-contentful https://github.com/medusajs/medusa-starter-contentful -``` - -This installs a new Medusa backend in the directory `medusa-contentful`. - -### Add Contentful Environment Variables - -Change to the `medusa-contentful` directory. In `.env` you’ll find three variables: - -```bash title=.env -CONTENTFUL_SPACE_ID= -CONTENTFUL_ACCESS_TOKEN= -CONTENTFUL_ENV= -``` - -#### Value of CONTENTFUL_ENV - -Set the value for `CONTENTFUL_ENV` to `master`. - -#### Value of CONTENTFUL_SPACE_ID - -To retrieve the value of `CONTENTFUL_SPACE_ID`: - -1. Go to your [Contentful Space dashboard](https://app.contentful.com/). Then, choose Settings in the navigation bar and select API keys from the dropdown. -2. On the APIs page, click Add API Key. -3. In the form, enter a name for the API key and click Save. -4. Copy the value of Space ID and set it as the value of `CONTENTFUL_SPACE_ID`. - -#### Value of CONTENTFUL_ACCESS_TOKEN - -To retrieve the value of `CONTENTFUL_ACCESS_TOKEN`: - -1. Go back to the API Keys page and click on the Content management tokens tab. -2. Click on Generate personal token. -3. In the pop-up that opens, enter a name for the token. -4. Click the Generate button. A personal access token will be generated. Use it to set the value of `CONTENTFUL_ACCESS_TOKEN`. - -:::warning - -Once you close the pop-up, you won’t be able to get the value of the personal access token again. Make sure to copy it first. - -::: - -### Configure Redis - -In `.env` set the value of your Redis URL: - -```bash -REDIS_URL= -``` - -Where `` is the URL of your Redis service. - -:::tip - -The default Redis URL is `redis://localhost:6379`. - -::: - -### Configure PostgreSQL - -In `.env` set the value of your PostgreSQL URL: - -```bash -DATABASE_URL= -``` - -Where `` is the URL of your PostgreSQL database. - -:::tip - -You can find the format of the PostgreSQL database URL in [PostgreSQL’s documentation](https://www.postgresql.org/docs/current/libpq-connect.html). - -::: - -Then, in `medusa-config.js` in the exported object, add the PostgreSQL database configurations: - -```jsx title=medusa-config.js -module.exports = { - projectConfig: { - // ... - database_url: DATABASE_URL, - database_type: "postgres", - }, -} -``` - -### Migrate Content Types to Contentful - -The Contentful starter provides the necessary scripts to create content types in your Contentful space. - -Run the following commands to migrate the content types into Contentful: - -```bash -npm run migrate:contentful -``` - -Once this command finishes executing, in your Contentful Space dashboard click on Content Model in the navigation bar. You should see a list of new content models added. - -### Seed Content to Contentful - -The next step is to seed the Contentful Space with some content data. - -Run the following command to seed some data into it: - -```bash -npm run seed:contentful -``` - -After this command finishes running, in your Contentful Space dashboard click on Content in the navigation bar. You should see a list of new content added. - -### (Optional) Seed Medusa Database - -This step seeds your Medusa database with demo data to easily add products as well as other data to your Medusa backend. - -Run the following command to seed the Medusa database: - -```bash -npm run seed -``` - -### Start the Backend - -To start the backend run the following command: - -```bash -npx medusa develop -``` - -If you seeded the database with demo data, you should see that events related to the products are triggered. - -The Contentful integration ensures a sync between the Medusa backend and Contentful. So, when new products are added to Medusa, these products will be added to your Contentful Space as well. - ---- - -## (Optional) Add Products with the Medusa Admin - -Using the Medusa admin, you can add products to your Medusa backend. This will trigger product events that subsequently add these products to Contentful. - ---- - -## (Optional) Two-way Sync with Contentful - -This section explains how you can establish a two-way sync between Medusa and Contentful. This would ensure that not only is the data updated from the Medusa backend to Contentful, but also ensure the updates are relayed from Contentful to the Medusa backend. - -However, to perform this sync, it's required that you deploy your backend so that it can be publicly accessible. You can learn how to do that through the [backend deployment](../../../deployments/server/index.mdx) guides. - -Configuring two-way sync requires configuring Webhooks in Contentful. To do that: - -1. On your Contentful Space Dashboard, click on Settings from the navigation bar, then choose Webhooks. -2. Click on the Add Webhook button. -3. In the form, enter a name for the webhook. -4. In the URL field, choose the method `POST` and in the input next to it enter the URL `/hooks/contentful` where `` is the URL of your production Medusa backend. -5. Scroll down to find the Content Type select field. Choose `application/json` as its value. -6. You can leave the rest of the fields the same and click on the Save button. - -Now, every time you change a product’s data on your Contentful Space it will be updated on your Medusa backend as well. - ---- - -## Manage Contentful Data - -### Publish Products - -Products added through the integration with the Medusa backend are by default saved as drafts. To show them on the storefront, you must set them as published. - -To do that, open your Contentful Space Dashboard and click on Content in the Navigation bar. Then, change Any to Product in the select field next to the search bar. This shows only the content of the type Product, rather than all content. - -Click on the checkbox at the top of the table to select all products then click Publish to publish these products. - -### Added Featured Products - -On the homepage of the storefront, there’s a featured products tile that shows a set of products. Before running the storefront, you must add at least one product to the list. - -To do that: - -1. Open your Contentful Space Dashboard and click on Content in the Navigation bar. -2. Set the select field next to the search bar Any and search for Featured Products. You should find one content of the type Tile Section. -3. Click on the result. You should find on the page an empty Tiles section where you can add tiles and products. -4. Click on the "Add content" button, then on "Add existing content" from the dropdown. -5. Pick some of the products you want to show on the homepage. -6. Once you’re done adding products, click on Publish changes in the right sidebar. - ---- - -## Setup Gatsby Storefront - -:::warning - -This Gatsby storefront is deprecated. It's recommended to integrate Contentful into either the Next.js Starter Template or your custom storefront. - -::: - -In this section, you’ll set up the Gatsby storefront of your Medusa backend. - -In your terminal in a different directory of the Medusa backend, run the following command: - -```bash -gatsby new medusa-contentful-storefront https://github.com/medusajs/medusa-contentful-storefront -``` - -This will install the storefront in the directory `medusa-contentful-storefront`. - -### Set Contentful Environment Variables - -Change to the newly created directory and rename `.env.template`: - -```bash -mv .env.template .env -``` - -Then, open `.env`. You should find the following environment variables: - -```bash title=.env -CONTENTFUL_SPACE_ID= -CONTENTFUL_ACCESS_TOKEN= -``` - -The value of `CONTENTFUL_SPACE_ID` is the same value you [retrieved while setting up the Medusa backend](#value-of-contentful_space_id). - -To retrieve the value of `CONTENTFUL_ACCESS_TOKEN`: - -1. On your Contentful Space dashboard click on Settings in the navigation bar then choose API keys. -2. Choose the API key you created in the previous section. -3. You should find the field "Content Delivery API - access token”. Copy its value and set it as the value of `CONTENTFUL_ACCESS_TOKEN`. - -### Start Storefront - -Make sure the Medusa backend is still running. Then, start the storefront: - -```bash npm2yarn -npm run start -``` - -This starts the storefront at `localhost:8000`. Open it in your browser and you should see on the homepage the Featured Product section with the products you chose on Contentful. - ---- - -## Make Changes to Content - -You can update the CMS content of your storefront in your Contentful Space. This includes the CMS pages or product details. - -:::note - -If you make changes to the data while your Gatsby storefront is running, the changes are not reflected instantly. That’s because the data is fetched from Contentful during build time. Instead, you must restart your Gatsby storefront to see the changes you make. - -::: - ---- - -## What’s Next - -Learn [How to customize your Contentful backend and storefront](./customize-contentful.md). - -## See Also - -- How to deploy your Medusa backend to [Heroku](../../../deployments/server/deploying-on-heroku.mdx), or [DigitalOcean](../../../deployments/server/deploying-on-digital-ocean.md), or [other providers](../../../deployments/server/index.mdx) \ No newline at end of file diff --git a/www/apps/docs/sidebars.js b/www/apps/docs/sidebars.js index 0fce40c378..aa5950df19 100644 --- a/www/apps/docs/sidebars.js +++ b/www/apps/docs/sidebars.js @@ -2187,24 +2187,14 @@ module.exports = { }, items: [ { - type: "category", + type: "doc", label: "Contentful", - link: { - type: "doc", - id: "plugins/cms/contentful/index", - }, + id: "plugins/cms/contentful", customProps: { iconName: "bolt-solid", description: "Learn how to integrate Contentful with the Medusa backend.", }, - items: [ - { - type: "doc", - id: "plugins/cms/contentful/customize-contentful", - label: "Customize Integration", - }, - ], }, { type: "doc", diff --git a/www/apps/docs/src/css/_docusaurus.css b/www/apps/docs/src/css/_docusaurus.css index 4880ffada5..f93e68f5e8 100644 --- a/www/apps/docs/src/css/_docusaurus.css +++ b/www/apps/docs/src/css/_docusaurus.css @@ -49,7 +49,8 @@ video { @apply mt-1.5; } -.card + p { +.card + p, +details + p { @apply mt-2; }