Imported from shopwareLabs/shopware-catalog-generator (
src/post-processors/cms/AGENTS.md). Install upstream withnpx skills add shopwareLabs/shopware-catalog-generator --skill cms. Copyright stays with the author.
CMS Processors Documentation
Internal documentation for AI agents working on the CMS post-processors module.
Overview
CMS processors create demonstration pages for all Shopware CMS block types. The architecture uses a multi-processor approach with an orchestrator that builds the final category hierarchy.
Category Hierarchy
Testing (testing-placeholder.ts)
├── CMS (welcome.ts - CMS Element Showcase)
│ ├── Text (text.ts)
│ ├── Images (images.ts)
│ ├── Video (video.ts)
│ ├── Text & Images (text-images.ts)
│ ├── Commerce (commerce.ts)
│ └── Form (form.ts)
├── Products (navigation category)
│ ├── Simple Product (link to product)
│ ├── Variant Product (link to product)
│ └── Digital Product (link to product)
└── Cookie settings (external link to /cookie/offcanvas)
The Testing category is always created last via afterCategoryId ordering.
Architecture
BaseCmsProcessor
Abstract base class providing shared functionality for all CMS processors:
abstract class BaseCmsProcessor {
abstract readonly name: string;
abstract readonly description: string;
abstract readonly pageFixture: CmsPageFixture;
readonly dependsOn: string[] = [];
// CMS page operations
protected findCmsPageByName(context, name): Promise<string | null>;
protected createCmsPage(context, fixture): Promise<string | null>;
// Landing page operations
protected findLandingPageByName(context, name): Promise<string | null>;
protected createLandingPage(context, name, cmsPageId): Promise<string | null>;
protected ensureSalesChannelAssociated(context, landingPageId, name, errors): Promise<void>;
// Entity operations
protected deleteEntity(context, entity, id): Promise<boolean>;
// Inter-processor cache
protected saveLandingPageId(context, processorName, landingPageId): void;
protected getLandingPageIds(context): Record<string, string>;
}
HomeProcessor (Homepage)
The cms-home processor is unique among CMS processors:
- Creates a
product_listpage (notlandingpage) - Assigns CMS page to the root category via
cmsPageId(no landing page entity) - Uses template-based text with dynamic values from the blueprint (no AI hydration)
- Generates one hero image per store
The homepage includes a text-teaser-section (hero image + welcome text) followed by a standard product listing with sidebar filters.
Element Processors
Simple processors that extend BaseCmsProcessor:
| Processor | Name | Fixture | Description |
|---|---|---|---|
| HomeProcessor | cms-home |
home-listing.ts | Homepage layout on root category |
| TextProcessor | cms-text |
text.ts | Text blocks, heroes, teasers, HTML |
| ImagesProcessor | cms-images |
images.ts | Image, gallery, slider |
| VideoProcessor | cms-video |
video.ts | YouTube, Vimeo embeds |
| TextImagesProcessor | cms-text-images |
text-images.ts | Combined text/image layouts |
| CommerceProcessor | cms-commerce |
commerce.ts | Product boxes, sliders, buy boxes |
| FormProcessor | cms-form |
form.ts | Contact and newsletter forms |
Dynamic Data Population
Some processors override process() to fetch and populate dynamic data:
HomeProcessor: Builds dynamic HTML from blueprint metadata (store name, description, product/category counts) and generates a hero image. Assigns the CMS page to the root category.
ImagesProcessor: Fetches media IDs from products and the media endpoint to populate image-slider and image-gallery blocks. Generates AI images with block-type-specific dimensions (e.g., hero, gallery), uploads to CMS Media folder.
CommerceProcessor: Fetches product IDs and media to populate product-box, product-slider, and gallery-buybox blocks.
CMS Text Hydration
CMS processors read AI-generated text from cms-blueprint.json (generated during blueprint hydrate --only=cms), not static fixtures. This allows store-context-aware headlines, captions, and body copy for each block type.
CMS Image Hydration
CMS images are pre-generated during blueprint hydration (not in post-processors) by hydrateCmsImages() in src/blueprint/hydrators/image.ts. This function defines all 20 CMS image specs (key, prompt, dimensions) and caches them locally in images/cms_media/.
Post-processors (cms-images, cms-text-images, cms-home) only read from cache and upload to Shopware via getOrCreateCmsMedia(context, imageKey). The BaseCmsProcessor.generateAndUploadCmsImage() method does not call the image provider -- it returns null if the image isn't cached.
TestingProcessor (Orchestrator)
The orchestrator runs last and creates the full category hierarchy:
- Creates Testing placeholder landing page
- Creates "Testing" main category
- Creates CMS showcase landing page
- Creates "CMS" sub-category
- Creates element sub-categories (Text, Images, etc.)
- Creates "Products" navigation category
- Creates product type links (Simple, Variant, Digital)
Dependencies: All element processors + digital-product
Inter-Processor Communication
Processors communicate via a shared JSON cache file:
generated/sales-channels/{store}/cms-landing-pages.json
Each element processor saves its landing page ID:
// In element processor
this.saveLandingPageId(context, this.name, landingPageId);
// In TestingProcessor
const landingPages = this.getLandingPageIds(context);
// { "cms-text": "abc123", "cms-images": "def456", ... }
Validation Approach
API-only validation: If the Shopware sync API returns 200, the CMS page structure is valid. The API enforces:
- Required block/slot structure
- Valid block types
- Proper configuration values
- Association integrity
No additional validation layer is needed. Browser rendering issues (like empty sliderItems) are prevented by dynamic population in processors.
Fixtures Location
All CMS page fixtures are in src/fixtures/cms/:
src/fixtures/cms/
├── index.ts # Re-exports all fixtures
├── types.ts # CmsPageFixture interface
├── testing-placeholder.ts # Testing entry page
├── welcome.ts # CMS showcase page
├── text.ts # Text elements
├── images.ts # Image elements
├── video.ts # Video elements
├── text-images.ts # Text & images elements
├── commerce.ts # Commerce elements
├── form.ts # Form elements
└── home-listing.ts # Home listing page (root category)
Adding a New CMS Demo Page
- Create fixture in
src/fixtures/cms/new-element.ts:
import type { CmsPageFixture } from "../types.js";
export const NEW_ELEMENTS_PAGE: CmsPageFixture = {
name: "New Elements",
type: "landingpage",
sections: [{ ... }],
};
-
Export from
src/fixtures/cms/index.tsandsrc/fixtures/index.ts -
Create processor in
src/post-processors/cms/new-processor.ts:
import { BaseCmsProcessor } from "./base-processor.js";
import { NEW_ELEMENTS_PAGE } from "../../fixtures/index.js";
class NewProcessorImpl extends BaseCmsProcessor {
readonly name = "cms-new";
readonly description = "Create New Elements demo page";
readonly pageFixture = NEW_ELEMENTS_PAGE;
}
export const NewProcessor = new NewProcessorImpl();
-
Export from
src/post-processors/cms/index.ts -
Register in
src/post-processors/index.ts -
If the page needs AI images, add image specs to
buildCmsImageSpecs()insrc/blueprint/hydrators/image.ts -
Add to
CMS_CATEGORIESintesting-processor.ts -
Add unit tests in
tests/unit/post-processors/cms/
Cleanup
All CMS processors support cleanup via --processors=cms-*:
# Cleanup specific processor
bun run cleanup -- --salesChannel="garden" --processors=cms-text
# Cleanup all CMS processors
bun run cleanup -- --salesChannel="garden" --processors=cms-testing
The TestingProcessor cleanup deletes in reverse order (deepest categories first).