P1 Concepts, Mapped to WordPress & Drupal
P1’s own docs describe it as “decoupled and API-first, not headless and even less monolithic.” In practice: a Next.js frontend (the P1 Client) talks to a hosted backend (the Collaborative Content Repository, or CCR) that stores your content as structured documents, with Cloudflare (Pantheon Edge) caching and routing in front of both.
None of that maps perfectly onto WordPress or Drupal: P1 has no themes directory, no
wp_posts table, no .info.yml files. But the concepts underneath rhyme closely
enough that naming the closest analog is the fastest way to get oriented, so long as you
remember it’s an analogy, not an equivalence.
Quick comparison
| P1 | WordPress | Drupal |
|---|---|---|
| Site (one P1 dashboard entry) | A WP install | A Drupal site |
| CCR document (a page) | A Post / Page | A Node |
Template (_registry/templates/*) | Custom Post Type + ACF Field Group | Content Type + Field UI |
| Puck component | Gutenberg block | Paragraph type / Block plugin |
| Puck field (on a component) | ACF field | Drupal field (Field UI) |
Puck visual editor (/p1) | Block editor | Layout Builder |
| Site Structure (dashboard tab) | Pages screen + menu editor | Content list + Menu UI |
| Branch / Workstream | (closest: staging site + merge, but a real branch/merge, not a plugin) | Content moderation workflow |
| Pantheon Edge | Cloudflare sitting in front of WP (via your host or the Cloudflare plugin) | Drupal’s internal page cache + Cloudflare |
If you’re coming from one platform specifically, the quick table above is a starting point, not the full picture: Concepts for WordPress Developers and Concepts for Drupal Developers go deeper: a fuller terminology mapping, the concrete workflow differences (not just the closest analog), and the platform-specific habits worth unlearning. And since Puck and Gutenberg are both React-based, block/component-oriented visual editors (the closest pairing in this whole comparison), Puck vs. Gutenberg goes deep on just that one comparison specifically.
Sites, branches, and workstreams
A Site in the P1 dashboard is the rough equivalent of one WordPress or Drupal install: one content backend, paired with one Next.js codebase.
Content lives on a branch: main is the default/live one, and it’s what your local
.env.local reads from unless you override NEXT_PUBLIC_CSS_BRANCH_ID. The dashboard’s
workstream is a branch by another name. Editing has its own draft-autosave-vs-publish
distinction independent of branches; see Workflows
for the full mechanics of both, confirmed directly from the SDK source: how autosave and
Publish differ, how a workstream gets merged into Live, checkpoints, and template
migrations.
We’ve observed a real gap between a page existing in the dashboard and that page actually rendering through the public/local read path. Workflows explains the publish mechanism that’s almost certainly behind it; see Known Issues for the specific incident before you assume something’s broken.
Documents, pages, and templates
Every page, template, and redirect is stored as a document in the CCR: the closest
single concept to a WordPress Post/Page or a Drupal Node. A document lives at a
path (/about, /events/us/go-live), and the URL-to-document relationship is
one-to-one for static pages.
A Template, stored at _registry/templates/{name}, is the closest thing to a
WordPress Custom Post Type combined with an ACF Field Group, or a Drupal Content Type
with its fields: it defines a Content Type (name, label, description) plus a
component tree that pages created from it inherit. Templates distinguish:
- Pinned components: locked into place by whoever built the template; a content editor can’t move, remove, or restructure them. Think of these like a Drupal “required” field, or an ACF field group locked to specific block positions.
- Editorial components: everything else; freely configurable within the guardrails the template sets.
Dynamic routes (/company/leadership/:name) are P1’s answer to what WordPress does
with a CPT archive/single template, or what Drupal does with a Views page + node
template: one template renders many URLs, each resolved against a data record at
request time, rather than one document per URL.
Changing a template’s structure after real pages already exist against it (the thing that’s usually painful in WordPress or Drupal) has dedicated, self-serve tooling in P1: dry-run previews, async migration jobs, and rollback. See Templates.
Components: Puck’s answer to blocks
Puck is P1’s visual, drag-and-drop editor, closest to the WordPress block editor (Gutenberg) or Drupal’s Layout Builder. What Gutenberg calls a “block” and Drupal calls a “Paragraph type,” Puck calls a component.
Concretely, a component is a plain JS/TS object with four parts:
export const quoteBlock = {
label: "Quote", // shown in the component picker
fields: { // the editor sidebar's inputs
quote: { type: "textarea", label: "Quote" },
attribution: { type: "text", label: "Attribution" },
},
defaultProps: { // what a fresh instance starts with
quote: "A short quotation goes here.",
attribution: "",
},
render: ({ quote, attribution }) => ( // the actual React output
<blockquote>
<p>{quote}</p>
{attribution ? <footer>— {attribution}</footer> : null}
</blockquote>
),
};Components live in components/puck/*.tsx and get registered (plus assigned to a
sidebar category) in puck.config.tsx at the project root. There’s no separate “block
registration” API call and no PHP-side register_block_type equivalent: the object
above is the registration; importing it into puck.config.tsx’s components map is
what makes it appear in the editor.
See Fields Reference for the full list of field types
available inside fields, and Components Reference for
what ships out of the box. Puck is a third-party library P1 builds its editor on top
of; its own docs on
Component Configuration
cover the same object shape in more depth, independent of anything P1-specific.
Naming trap: “CSS” doesn’t mean stylesheets here
Across P1’s SDK and env vars, CSS stands for Content and Site Services (the
backend API), not Cascading Style Sheets. CSS_API_KEY, NEXT_PUBLIC_CSS_SITE_ID,
@pantheon-systems/css-client are all this. It reads oddly the first few times; worth
knowing up front so you don’t go looking for a stylesheet config.