The CWA is in heavy development
The CWA is still in alpha and not ready for production - some code and implementations are likely to change. If you would like to try out the CWA, please enjoy what we have provided and feel free to provide feedback, or get involved on GitHub.
DraftCore Concepts

Dynamic Pages

How PageData records drive template pages — the pattern for blogs, events, products, and any repeating content type.

The Problem

Imagine you're building a blog. You have 50 articles and you need each one at its own URL (/blog/my-first-post, /blog/second-article, etc.). You don't want to create 50 separate pages in the CMS.

The solution is template pages + PageData.

How It Works

  • The Route points to a BlogArticle PageData record (not directly to a Page).
  • BlogArticle carries a page field naming the BlogTemplate page to render — one template shared across all articles.
  • BlogTemplate is a normal Page with ComponentGroups, but some ComponentPositions have a pageDataProperty set (e.g. "htmlContent"). At render time those positions resolve to the matching field on the current BlogArticle — so each article shows its own component in that slot.
  • BlogArticle also carries its own htmlContent component reference. The dashed line in the diagram shows this runtime binding between the ComponentPosition and the component stored on the PageData record.

Creating PageData in PHP

// api/src/Entity/BlogArticleData.php
#[ORM\Entity]
#[ApiResource(mercure: true)]
class BlogArticleData extends AbstractPageData
{
    #[ORM\Column(nullable: true)]
    public ?string $body = null;
}

AbstractPageData already provides title and metaDescription for SEO. You add your custom fields.

Linking a PageData Field to a Region

A template page region can be bound to a PageData field. This means the component in that region comes from the PageData record rather than being manually added.

In the fixture scaffold:

$cwa->page('blog-template', 'PrimaryPageTemplate', layout: 'main', isTemplate: true,
    configure: function (PageBuilder $p) {
        $p->group('primary')
            ->pageDataPosition(BlogArticleData::class, 'htmlContent');  // binds to BlogArticleData->htmlContent
    }
);

When any BlogArticleData page renders, the primary region shows that article's htmlContent component.

Reading PageData in Your Vue Component

<script setup lang="ts">
const pageData = $cwa.resources.pageData.value
// pageData.data.title, pageData.data.body, etc.
</script>

The module makes the current PageData available globally. Your page template can also pass the IRI down to child components as needed.

SEO

PageData records have title and metaDescription fields (from AbstractPageData). The module automatically uses these to set <title> and <meta name="description"> for each article's URL — no extra code needed.

Admin Management

All PageData types appear at /_cwa/data in the admin panel. Admins can:

  • Browse all records for a type (e.g. all blog articles)
  • Create new records
  • Edit title, metaDescription, and any custom fields
  • Publish/unpublish records (if the entity uses #[Silverback\Publishable])