# Contentful

## Install Shopstory app in the Contentful

Go to the [https://www.contentful.com/marketplace/app/shopstory ](https://www.contentful.com/marketplace/app/shopstory/)and install the Shopstory in your space. The last step of the installation is Shopstory configuration:

<figure><img src="https://1906827321-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F4j4BoYKV0GXMySXRws9n%2Fuploads%2F8RNpo970rbpNSomcklMv%2FScreenshot%202022-12-07%20at%2011.25.59.png?alt=media&#x26;token=f9a70b72-9a5a-46da-bcdc-b5f45edd7165" alt=""><figcaption></figcaption></figure>

Fill the "Canvas URL" field with the URL of the canvas page you just created and add a query param with Shopstory access token:

```
http://localhost:3000/shopstory-canvas?shopstoryAccessToken={YOUR_SHOPSTORY_ACCESS_TOKEN}
```

Click "Save" to finish the installation process.

## Connect Contentful in the front-end code

The last step we need do is to tell our front-end how to connect to Contentful. In order to do it you must use Shopstory Contentful plugin.

Start with installing the Shopstory-Contentful plugin in your project:

```
npm install @shopstory/contentful
```

Now go to `shopstory/config.ts` and add the plugin:

```typescript
import { Config } from "@shopstory/core";
import { contentfulPlugin } from "@shopstory/contentful";

export const shopstoryConfig : Config = {
  plugins: [contentfulPlugin({
    space: process.env.NEXT_PUBLIC_CONTENTFUL_SPACE!,
    environment: process.env.NEXT_PUBLIC_CONTENTFUL_ENVIRONMENT ?? 'master',
    accessToken: process.env.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN!,
    previewAccessToken: process.env.NEXT_PUBLIC_CONTENTFUL_PREVIEW_ACCESS_TOKEN!
  })]
}

```

In order to make Shopstory work properly you must pass both preview token and standard Contentful access tokens.

## Let's build some content!

During installation of Shopstory Contentful app, a new content type is added to your space: "Shopstory Block". It's a very simple content type representing a piece of visual content.

In order to build your first visual content just create a new "Shopstory Block" entry, click the button "Open visual editor" and build something:

{% embed url="<https://vimeo.com/779544071>" %}

#### Content modeling with Shopstory

From the content modeling perspective Shopstory Block is just a starting point. It can be referenced by other content types representing for example landing pages or product pages. If you don't like references you can also add Shopstory field directly in your content types. To learn more about content modeling with Shopstory read [this guide](https://docs.shopstory.app/getting-started/connecting-cms/broken-reference).

## Displaying content

The last step is to render Shopstory content in your project. For the demo purpose we'll create a page that renders Shopstory Block entry by id - `pages/shopstory-block/[entryId].tsx`:

```typescript
import type { NextPage, GetStaticProps, GetStaticPaths } from "next";
import {RenderableContent, Metadata, RawContent} from "@shopstory/core";
import { createClient, Entry } from "contentful";
import { ShopstoryClient } from "@shopstory/core";
import { Shopstory, ShopstoryMetadataProvider } from "@shopstory/react";
import { shopstoryConfig } from "../../src/shopstory/config";
import { DemoShopstoryProvider } from "../../src/shopstory/provider";

type ShopstoryBlockPageProps = {
  renderableContent: RenderableContent;
  meta: Metadata;
};

const ShopstoryBlockPage: NextPage<ShopstoryBlockPageProps> = (props) => {
  return (
    <DemoShopstoryProvider>
      <ShopstoryMetadataProvider meta={props.meta}>
        <Shopstory content={props.renderableContent} />
      </ShopstoryMetadataProvider>
    </DemoShopstoryProvider>
  );
};

export const getStaticPaths: GetStaticPaths = () => {
  return { paths: [], fallback: "blocking" };
};

export const getStaticProps: GetStaticProps<
  ShopstoryBlockPageProps,
  { entryId: string }
> = async (context) => {
  let { params, preview, locale = "en-US" } = context;

  if (!params) {
    return { notFound: true };
  }

  const rawContent = await fetchShopstoryContentJSONFromCMS(params.entryId, locale, !!preview);

  const shopstoryClient = new ShopstoryClient(shopstoryConfig, {
    locale,
    contentful: { preview },
  });
  const renderableContent = shopstoryClient.add(rawContent);
  const meta = await shopstoryClient.build();

  return {
    props: { renderableContent, meta },
    revalidate: 10,
  };
};

async function fetchShopstoryContentJSONFromCMS(entryId: string, locale: string, preview: boolean) : Promise<RawContent> {
  const contentfulClient = createClient({
    space: process.env.NEXT_PUBLIC_CONTENTFUL_SPACE!,
    environment: process.env.NEXT_PUBLIC_CONTENTFUL_ENVIRONMENT ?? "master",
    accessToken: preview
      ? process.env.NEXT_PUBLIC_CONTENTFUL_PREVIEW_ACCESS_TOKEN!
      : process.env.NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN!,
    host: preview ? "preview.contentful.com" : undefined,
  });

  const entry: Entry<any> = await contentfulClient.getEntry(entryId, {
    content_type: "shopstoryBlock",
    locale,
  });

  return entry.fields.content;
}

export default ShopstoryBlockPage;

```

Most of the code is CMS-agnostic and relates to how Shopstory SDK works (`ShopstoryClient`, `ShopstoryMetadataProvider`, `Shopstory`, etc). This will be explained in the next chapter: [Displaying Content](#displaying-content). &#x20;

However, there are 2 Contentful-specific pieces of code here.

First one is the body of the `fetchShopstoryContentJSONFromCMS` function. As you can see it's a standard call to Contentful API that fetches Shopstory `JSON` field content. In this example we fetch the field named `content` from the built-in `Shopstory Block` content type. It's a standard Contentful `JSON` field and we can access its value via `entry.fields.content`.&#x20;

The second Contentful-specific piece of code is here:

```typescript
 const shopstoryClient = new ShopstoryClient(shopstoryConfig, {
    locale,
    contentful: { preview }, // Contentful-specific code
  });
```

Here we tell the Shopstory-Contentful Plugin if the Contentful resources linked in Shopstory content (media and entries) should be fetched with Content Preview API (`preview: true`) or Content Delivery API (`preview: false`).

## Further reading

Now it's time to read [Displaying Content](https://docs.shopstory.app/getting-started/displaying-content) chapter and understand how Shopstory SDK works.

{% hint style="info" %}
`getStaticPaths` implementation is dummy just for the sake of demo simplicity.&#x20;
{% endhint %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.shopstory.app/getting-started/connecting-cms/contentful.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
