Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions apps/docs/.vitepress/sidebar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,18 +99,10 @@ export const sidebar = [
link: "/guides/cms/",
collapsed: true,
items: [
{
text: "Custom Elements",
link: "/guides/cms/custom-elements.html",
},
{
text: "Content Pages",
link: "/guides/cms/content-pages.html",
},
{
text: "Customize Components",
link: "/guides/cms/customize-components.html",
},
{
text: "Implement Missing Component",
link: "/guides/cms/missing-component.html",
Expand Down
64 changes: 4 additions & 60 deletions apps/docs/src/concepts/shopping-experiences.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ This guide will discuss how to use and customize [Shopping Experiences](https://

Shopping Experiences are implemented as a dedicated package that you can install in your project.

If your project is based on the [Demo Store Template](../introduction/templates/demo-store-template), that package is already installed. If you are using a custom template, follow the instructions in [Install the package](#install-the-package) first.
If your project is based on the [Vue Starter Template](../introduction/templates/vue-starter-template.html), that package is already installed. If you are using a custom template, follow the instructions in [Install the package](#install-the-package) first.

## Install the package

Expand Down Expand Up @@ -64,76 +64,20 @@ If you already have your own UnoCSS or Tailwind setup, you can keep using `@shop

## CMS rendering workflow

Understanding how the API data flows into rendered components helps you know what's automatic and what requires your own implementation.

### Data → Component mapping

The Shopware API returns a nested CMS tree:

<!-- automd:file src="examples/docs-code-examples/src/generated/concepts/shopping-experiences/data-component-mapping" code no-name -->

```
CmsPage
└── CmsSection (type e.g. "default", "sidebar")
└── CmsBlock (type e.g. "image-text", "product-slider")
└── CmsSlot (type e.g. "image", "text")
```

<!-- /automd -->

Each node has a `type` field. The `cms-base-layer` package resolves a Vue component for every node by converting the type to a PascalCase component name:

| API node | type value | resolved component |
| ------------- | ------------ | ------------------- |
| `cms_section` | `default` | `CmsSectionDefault` |
| `cms_block` | `image-text` | `CmsBlockImageText` |
| `cms_slot` | `image` | `CmsElementImage` |

This resolution is done by `resolveCmsComponent` from `@shopware/composables`.
The [Rendering CMS Pages recipe](../frontends-recipes/cms/rendering.html) explains how the CMS tree in the API response — sections, blocks and slots — is resolved to components.

### What is handled automatically

The `@shopware/cms-base-layer` package ships ready-made components for all **default** Shopware CMS blocks and elements. If your project uses this package, those render without any configuration.

### What requires your implementation

Any CMS block or element type that is **not** part of the default set — typically custom blocks created in the Shopware backend — will not have a matching component. In development mode you will see an outlined placeholder where the component is missing, with:

- the expected component name to create (e.g. `CmsElementMyCustomSlider.vue`)
- a link to the relevant docs
- a one-click "copy AI prompt" button pre-filled with the live API data for that element

In production the placeholder is invisible (renders nothing), so missing components fail silently.

### Implementing a missing component

When a CMS element or block has no matching Vue component, the dev-mode placeholder gives you everything you need to get started quickly.

**Using the placeholder:**

1. Open your browser on any page that contains the unimplemented CMS type.
2. You will see a highlighted placeholder showing the expected component name (e.g. `CmsElementMyCustomSlider`).
3. Click **docs ↗** to open the relevant implementation guide.
4. Click **copy AI prompt** to copy a ready-to-use prompt to your clipboard. It includes:
- the exact component name and CMS type
- the full `content` prop JSON as returned by the API (including `config` and `data` fields)
- a reference to the docs
5. Paste the prompt into your AI coding assistant to generate a working first draft of the component.

**Completing the implementation:**

1. Create a file with the expected component name in your project, e.g. `components/CmsElementMyCustomSlider.vue`.
2. Nuxt auto-imports it as a global component, which is picked up by the resolver — the placeholder will disappear on the next hot-reload.
3. Use `defineProps<{ content: Schemas["CmsSlot"] }>()` and access `content.data` / `content.config` for the element's data.

::: tip Console warnings
In development mode the browser console also logs a warning for each missing component, including the component name to create and a direct link to the relevant docs page.
:::
A block or element type outside the default set — typically a custom block created in the Shopware backend — has no matching component. In development it renders a placeholder with the component name to create; in production it renders nothing. A missing section type shows a plain "There is no …" line instead, in every mode. [Implement a Missing CMS Component](../guides/cms/missing-component.html) takes you from the placeholder to a working component.

## 3D / spatial media support

Shopping Experiences also support 3D models (GLB format) in image elements, image galleries, and the Spatial Viewer block. The 3D viewer is loaded on demand to keep the default bundle small. See [Working with Images — 3D and spatial media](../guides/page-elements/images.html#_3d-and-spatial-media-glb) for setup instructions.

## How to build Pages, Elements and Blocks?

<PageRef page="../guides/cms/" title="BUILDGING > CMS" sub="See the buliding chapter about CMS." />
<PageRef page="../guides/cms/" title="CMS guides" sub="Create, override and implement CMS blocks and elements." />
2 changes: 1 addition & 1 deletion apps/docs/src/frontends-recipes/cms/contact-form.md
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,7 @@ Send both from an element override: `slotId` from `content.id`, which `CmsSlot`
- [Create content pages](../../guides/cms/content-pages.html)
- [Create elements](../../guides/cms/create-elements.html)
- [Overwriting CMS components](../../guides/cms/overwriting-cms.html)
- [Custom CMS elements](../../guides/cms/custom-elements.html)
- [Implement a Missing CMS Component](../../guides/cms/missing-component.html)
- [Composables reference](../../packages/composables/)
- [CMS base layer package](../../packages/cms-base-layer.html)
- [API client package](../../packages/api-client.html)
6 changes: 3 additions & 3 deletions apps/docs/src/getting-started/cms/custom-elements.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ nav:
head:
- - meta
- http-equiv: refresh
content: "0; url=/frontends/guides/cms/custom-elements.html"
content: "0; url=/frontends/guides/cms/missing-component.html"
---

# This page has moved

This content is now part of **[Custom Elements (CMS)](/frontends/guides/cms/custom-elements.html)**.
This content is now part of **[Implement a Missing CMS Component](/frontends/guides/cms/missing-component.html)**.

If you are not redirected automatically, [click here](/frontends/guides/cms/custom-elements.html).
If you are not redirected automatically, [click here](/frontends/guides/cms/missing-component.html).
6 changes: 3 additions & 3 deletions apps/docs/src/getting-started/cms/customize-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ nav:
head:
- - meta
- http-equiv: refresh
content: "0; url=/frontends/guides/cms/customize-components.html"
content: "0; url=/frontends/guides/cms/overwriting-cms.html"
---

# This page has moved

This content is now part of **[Customize Components](/frontends/guides/cms/customize-components.html)**.
This content is now part of **[Overwrite CMS components](/frontends/guides/cms/overwriting-cms.html)**.

If you are not redirected automatically, [click here](/frontends/guides/cms/customize-components.html).
If you are not redirected automatically, [click here](/frontends/guides/cms/overwriting-cms.html).
2 changes: 1 addition & 1 deletion apps/docs/src/guides/cms/content-pages.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ if you followed the previous chapter on [routing](../routing). The `data` value

The `cms-base` package has an opinionated style of components and is based on Tailwind.css. If you want to override components or add custom ones, you can build them right into your project or import them as a separate package.

<PageRef page="customize-components.html" title="Customize Components" sub="Customize CMS components (Shopping Experiences)" />
<PageRef page="overwriting-cms.html" title="Overwrite CMS components" sub="Replace a section, block or element of cms-base-layer with your own component." />

## Use custom components

Expand Down
39 changes: 3 additions & 36 deletions apps/docs/src/guides/cms/create-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ nav:

# Create Blocks (CMS)

Make sure, you've created a new file as described in [customize components](customize-components.html#create-new-files).
Create the file under a directory registered with `global: true` — `app/components/cms/` in `vue-starter-template` — as [Overwrite CMS components](overwriting-cms.html#where-the-file-goes) explains.

Next, import the correct type for your block and use it to define the `content` property:

<!-- automd:file src="examples/docs-code-examples/src/generated/guides/cms/create-blocks/example.vue" code lang="vue" no-name -->

```vue
<!-- components/cms/CmsBlockImageThreeColumn.vue -->
<!-- app/components/cms/CmsBlockImageThreeColumn.vue -->
<script setup lang="ts">
import type { CmsBlockImageThreeColumn } from "@shopware/composables";

Expand All @@ -46,39 +46,6 @@ For that reason, there's a generic element `CmsGenericElement` which can be plac

Let's build the `image-three-column` block, which has three slots - `left`, `center` and `right`.

<!-- automd:file src="examples/docs-code-examples/src/generated/guides/cms/create-blocks/slots.vue" code lang="vue{4-15}" no-name -->

```vue{4-15}
<!-- components/cms/CmsBlockImageThreeColumn.vue -->
<script setup lang="ts">
import type { CmsBlockImageThreeColumn } from "@shopware/composables";

import { useCmsBlock } from "#imports";

const props = defineProps<{
content: CmsBlockImageThreeColumn;
}>();

const { getSlotContent } = useCmsBlock(props.content);

const leftContent = getSlotContent("left");
const centerContent = getSlotContent("center");
const rightContent = getSlotContent("right");
</script>

<template>
<div class="grid grid-cols-3">
<CmsGenericElement :content="leftContent" />
<CmsGenericElement :content="centerContent" />
<CmsGenericElement :content="rightContent" />
</div>
</template>
```

<!-- /automd -->

That works, but it's quite repetiive and hard to read. So we can use another composable `useCmsBlock` which makes our lives way easier.

<!-- automd:file src="examples/docs-code-examples/src/generated/guides/cms/create-blocks/slots-2.vue" code lang="vue{12,14-16,20-22}" no-name -->

```vue{12,14-16,20-22}
Expand Down Expand Up @@ -110,4 +77,4 @@ const centerContent = computed(() => getSlotContent("center"));

<!-- /automd -->

No you can go ahead and override blocks and elements step by step.
Now you can go ahead and override blocks and elements step by step. The [Rendering CMS Pages recipe](../../frontends-recipes/cms/rendering.html) explains how a block's `content` reaches this component, and why the getter and the `computed` matter.
18 changes: 10 additions & 8 deletions apps/docs/src/guides/cms/create-elements.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Start with importing the correct element type from the `@shopware/composables` p
<!-- automd:file src="examples/docs-code-examples/src/generated/guides/cms/create-elements/example.vue" code lang="vue" no-name -->

```vue
<!-- components/cms/CmsElementImage.vue -->
<!-- app/components/cms/CmsElementImage.vue -->

<script setup lang="ts">
import type { CmsElementImage } from "@shopware/composables";
Expand All @@ -35,10 +35,10 @@ const props = defineProps<{

Now, you can use `props.content` to access all properties of the element in your template.

<!-- automd:file src="examples/docs-code-examples/src/generated/guides/cms/create-elements/example-2.vue" code lang="vue{8}" no-name -->
<!-- automd:file src="examples/docs-code-examples/src/generated/guides/cms/create-elements/example-2.vue" code lang="vue{12}" no-name -->

```vue{8}
<!-- components/cms/CmsElementImage.vue -->
```vue{12}
<!-- app/components/cms/CmsElementImage.vue -->

<script setup lang="ts">
import type { CmsElementImage } from "@shopware/composables";
Expand All @@ -57,10 +57,10 @@ const props = defineProps<{

However, for some elements the configuration can be quite complex, so there are composables to give you a hand:

<!-- automd:file src="examples/docs-code-examples/src/generated/guides/cms/create-elements/example-3.vue" code lang="vue{10-14,18-20}" no-name -->
<!-- automd:file src="examples/docs-code-examples/src/generated/guides/cms/create-elements/example-3.vue" code lang="vue{11-15,19-21}" no-name -->

```vue{10-14,18-20}
<!-- components/cms/CmsElementImage.vue -->
```vue{11-15,19-21}
<!-- app/components/cms/CmsElementImage.vue -->

<script setup lang="ts">
import { useCmsElementImage } from "@shopware/composables";
Expand All @@ -71,7 +71,7 @@ const props = defineProps<{
}>();

const {
containerStyle, // padding, background-color etc.
containerStyle,
displayMode, // cover, contain, stretch etc.
imageAttrs, // automatically resolves src, alt and srcset attributes
} = useCmsElementImage(props.content);
Expand All @@ -85,3 +85,5 @@ const {
```

<!-- /automd -->

`useCmsElementImage` returns more than these three values, and `getConfigValue` from `useCmsElementConfig` returns `false` for a config entry mapped from the surrounding entity. The [Rendering CMS Pages recipe](../../frontends-recipes/cms/rendering.html#composables) lists both.
Loading
Loading