Concepts for WordPress Developers
Most of our team comes from WordPress, so this page exists to be direct about where the analogy in Concepts holds up and where it doesn’t: methodology, not just terminology. Everything linked below is confirmed elsewhere in this documentation; this page is the WordPress-shaped index into it.
Terminology, fuller than the quick table
| WordPress | P1 | Where it actually differs |
|---|---|---|
A WP install (wp-config.php, one database) | A Site | One Site pairs with one Next.js codebase and one CCR content backend. See Sites, branches, and workstreams. |
Post / Page (wp_posts row) | Document | Same idea, different storage: a document is a CCR object at a path, not a DB row with a post_status column. See Workflows. |
Draft → Publish (post_status) | Autosave → Publish → Checkpoint | Not a status field. Publish is an explicit API call that creates a checkpoint; the public read path only ever serves checkpoints. See Publishing. |
| Revisions | Versions | Every autosave creates one, same spirit as WP revisions. See Publishing. |
| Trash | Soft delete + restore() | Same idea. See Publishing. |
| Staging site / manual sync | Branch (Workstream) + real merge | A true fork/merge, not a plugin-driven file/DB copy. See Branches. |
| Custom Post Type + ACF Field Group | Template | Metadata (name, label, URL pattern) is scriptable; the actual field layout is not: it’s built by hand in the Puck editor, every time. See Templates. |
| Gutenberg block | Puck component | A plain JS/TS object, not a PHP render callback + block.json + JS edit/save pair. See Components: Puck’s answer to blocks. |
| ACF field | Puck field | Declared inline on the component, not a separately-managed field group. See Fields Reference. |
| User role (Administrator/Editor/Author/Contributor) | ContentRole (admin/editor/author/junior-editor) | Names line up almost exactly, but P1’s roles only govern structural editing rights in the Puck canvas: much coarser than WP’s full capability system. See Permissions & Roles. |
functions.php / a custom plugin | (no direct equivalent) | See “Habits to unlearn” below. |
Content modeling: register_post_type + ACF → Template
In WordPress, standing up a new content type is code you write once
(register_post_type(), an ACF field group) and content editors then use forever
without touching it again. In P1, Template creation is metadata-only: name,
label, description, URL pattern can be scripted via the Templates API, but the
component layout itself has no write API at all. Someone has to build it by hand in
the Puck editor, and there’s no register_post_type()-with-fields shortcut. This is
confirmed directly from CreateTemplateParams’ own type comment: “Metadata only; the
layout is authored on the editor canvas afterwards.” See
Templates for the
full mechanics, and Products Template /
Cocktails Template for what that looked like in
practice on a real brand site.
The upside WordPress doesn’t have: changing a Template’s structure after real content already exists against it comes with dry-run previews and one-call rollback, self-serve. See Templates. A WP developer’s usual dread of “we need to add a field to 4,000 existing posts” has a real answer here.
Publishing: Draft/Publish → autosave/Publish/Checkpoint
WordPress shows you the state on the page (post_status: draft|publish). P1’s
equivalent has no visible status field: it’s autosave-as-draft-version, with an
explicit Publish action that creates a checkpoint the public site actually reads from.
Easy to miss coming from WP, because there’s nothing in the editor UI that visually
says “draft” the way WordPress does. Full mechanics, confirmed from the SDK source:
Publishing.
Staging & multi-environment: no plugin, a real branch
WordPress staging is typically a second install (a host’s staging environment, or a
migration plugin) you later sync back to production: file copies and DB merges,
essentially. P1’s Workstream is an actual branch with a real merge operation
(checkMergeability → preview → execute, or a full merge-request review flow
closer to a GitHub PR than anything native to WordPress). See
Branches.
Multisite has no equivalent. WordPress Multisite (one codebase, one database,
many independently-managed subsites via Network Admin) doesn’t map onto anything in
P1. A P1 Site is closer to a single normal WP install than to a multisite network
node: there’s no shared-codebase-many-subsites concept, and (confirmed directly from
SitesEndpoint, which only exposes get() and list()) no API to clone or duplicate
a site’s content into a new one. If your team has used WP Multisite to stand up
per-market subsites before, read Localization: it addresses this
exact question and lays out what building the equivalent on P1 would actually take.
Blocks → components: no PHP, no block.json
A Gutenberg block is a block.json manifest, a JS edit/save pair (or dynamic
rendering via a PHP callback), registered through register_block_type(). A Puck
component is one plain object (label, fields, defaultProps, render) imported
into puck.config.tsx. No manifest file, no PHP, no separate registration call; the
object is the registration. See
Components: Puck’s answer to blocks
for the shape, and Components Reference for what ships out
of the box.
Things WordPress gives you for free that P1 doesn’t
WordPress core (or one install-and-activate plugin) covers a lot of ground P1 leaves for you to build. Confirmed absent, each with the plan for filling it:
- Menus & widget areas (Appearance → Menus, sidebar widgets): nothing built in. See Managing the Header & Footer.
- A form builder (Gravity Forms, WPForms, Contact Form 7): nothing native to P1 or Puck. See Form Builder.
- Form entry storage (Gravity Forms’ own entries table) and SMTP/transactional email (WP Mail SMTP and similar): P1 has neither. See Form Builder → Submission Storage and Email Delivery.
- An SEO plugin (Yoast, RankMath): P1’s per-page SEO/OG fields are real and built in, but sitemap.xml, robots.txt, and JSON-LD structured data are not generated automatically the way an SEO plugin gives you on install. See SEO & GEO.
- The Media Library’s automatic responsive images: WordPress core has generated
multiple image sizes and a
srcsetautomatically since 4.4. Nothing in@pantheon-systems/p1-media’s exported surface produces asrcsetfor you; each component controls exactly one delivered width/height/format per call. See Media Library. - A plugin directory: there’s no P1-equivalent marketplace of install-and-activate
extensions. Extending a site means installing an npm package (like
p1-media) or building a component yourself; there’s no ecosystem of third-party P1 plugins to browse.
Habits to unlearn
- No
functions.php. There’s no single “put your customizations here” file: logic lives in Next.js route handlers, Puck components, and installed packages. - No template hierarchy (
single.php,archive-product.php, etc.). Rendering is driven by Templates and dynamic routes, not a file-naming convention. See Dynamic (templated) routes. - No hooks/filters system. There’s no
add_action/add_filterequivalent for hooking into core behavior; extension points are whatever a package’s own config object exposes (see howp1-media’sfieldNamePatternsorp1-form-builder’swebhookAllowlistwork as the closest analogs). - No wp-admin. The P1 dashboard (content.pantheon.io) and the in-page Puck editor cover content authoring; there’s no separate settings/plugins/users admin screen the way wp-admin bundles everything into one place.