Managing pages and designs (step-by-step)¶
Who this is for: anyone who needs to change how the websites look or behave — no coding required for the common cases. Since the data-driven engine (P1) shipped, pages and designs are configuration, not worker code.
The Cloudflare Worker is now a generic engine. It reads "page descriptors" (rows in the
page_typestable, served inside the API's/settings) and the template HTML/CSS, then renders. You change the data; the live site changes — no worker deploy for the cases below.
Read the box that matches your task. Each is a numbered checklist. Copy-paste commands assume you run them from the workspace root.
Glossary (read once)¶
- Template — a named design a site uses (e.g.
celebrity-v1). A site points at one template (sites.template_id). - Template block — the HTML for one part of a page, keyed by an
element_type (e.g.
header,article,homepage,footer,article_card,sidebar). Stored intemplate_blocks.html_content. - Page descriptor — a row in
page_typesthat says: this URL pattern → use these content slots, fetch this data, cache for this long. This replaces the old hardcoded routing in the worker. - css_version — a number on the template. The worker links the stylesheet at
/_assets/styles/<template-slug>/<css_version>.css(served from the R2 bucket). Bumping it publishes new CSS. - variant — lets one page type have more than one layout (e.g. a
defaultarticle and alisticlearticle) on the same site.
The element_type names that exist: homepage, article, category, author,
contact_us, about, privacy_policy, terms_of_use, do_not_sell, 404
(page slots) and layout, header, footer, sidebar, article_card,
breadcrumb, pagination, author_card (components).
TASK A — Change the look of a site (new CSS / redesign)¶
You are changing colors, fonts, spacing — the stylesheet.
- Edit the CSS for the template (the source CSS for
celebrity-v1). - Upload it to the R2 assets bucket under a new version number. If the
current
css_versionis3, upload as version4:# stage bucket is cms-assets-stg; prod is cms-assets-prd npx wrangler r2 object put cms-assets-stg/templates/celebrity-v1/4.css \ --file ./celebrity-v1.css --content-type "text/css" - Bump
css_versionon the template in the database:UPDATE templates SET css_version = '4' WHERE slug = 'celebrity-v1'; - Purge the site cache so pages re-render with the new link:
curl -X POST https://stg.wantskicks.com/__cms/purge \ -H "Authorization: Bearer $ADMIN_PURGE_SECRET" \ -H "content-type: application/json" -d '{"site": true}' - What success looks like: view-source on any page shows
<link rel="stylesheet" href="/_assets/styles/celebrity-v1/4.css">, and that file returns your new CSS.
Why a new version number instead of overwriting? The CSS URL is cached forever (immutable). A new number is a new URL, so browsers and the edge pick it up instantly and old cached pages keep working during the switch.
No worker deploy. No worker code change.
TASK B — Change the HTML of a page section (e.g. the article layout)¶
You are changing the markup/structure of a slot (header, article body wrapper, card, footer, …).
- Find the block for the element_type you want (e.g.
article) on the site's template, and edit itshtml_content. Use the admin API / DB:The markup is a small Handlebars-style template. Keep the placeholders the builder expects, e.g.UPDATE template_blocks SET html_content = '<main> ... your new markup ... </main>' WHERE template_id = (SELECT id FROM templates WHERE slug = 'celebrity-v1') AND element_type = 'article';<div data-render="content_blocks"></div>,<div data-grid="related_articles"></div>,<div id="sidebar-slot"></div>. - To change just ONE site (not every site on the template), set a site
override instead of editing the shared block:
-- via admin API: PUT /admin/v1/sites/{site_id}/block-overrides -- { "element_type": "article", "html_content": "<main>…</main>" } - Purge the cache (see Task A step 4).
- Success: the page renders your new markup.
No worker deploy.
TASK C — Add a brand-new page type (URL pattern)¶
Example: add a /tag/{slug} listing page that shows articles for a tag.
First ask: does it just fetch a list (or a single item) and drop it into slots, like category/author/homepage already do?
-
Yes → it's pure configuration (no code). Add a
page_typesrow:Field meanings:INSERT INTO page_types (template_id, type, variant, routes, layout, ttl, sources, grids, seo, position, is_active) SELECT id, 'tag', 'default', '["/tag/{slug}"]', '["category"]', 300, '[{"bind":"list","call":"lists","params":{"kind":"category","category_slug":"{slug}"}}]', '{"articles":"list"}', '{"from":"site"}', 45, 1 FROM templates WHERE slug = 'celebrity-v1';routes= URL patterns ({x}captures a param);layout= which content slot(s) to render (here it reuses thecategoryblock);sources= what to fetch and what to call it;grids= putlist's items into thedata-grid="articles"placeholder;ttl= cache seconds;seo.from= where the title/description come from (sitedefaults). Then purge the cache. Success:/tag/anythingrenders the list. No deploy. -
No — it needs custom logic (special data shaping, an unusual layout the generic path can't express) → this needs a small builder in the worker (code + one deploy). See
AGENTS.md("When code IS required").
TASK D — Add a layout VARIANT for an existing page type¶
Example: some articles should use a "listicle" layout, others the normal one, on the same site.
- Add a second
page_typesrow for the sametypewith a differentvariant:INSERT INTO page_types (template_id, type, variant, routes, layout, ttl, builder, seo, position, is_active) SELECT id, 'article', 'listicle', '["/{category}/{slug}"]', '["article"]', 1800, 'article', '{"from":"page"}', 40, 1 FROM templates WHERE slug = 'celebrity-v1'; - Make sure a
listiclearticle block exists (Task B) if the markup differs. - The variant is chosen per content item (e.g. from the content's
settings.layoutfield). Set that on the articles that should use it. - Purge the cache. Success: flagged articles render the listicle layout; the rest stay default.
TASK E — Change a static page (Contact, About, Privacy, …)¶
These are just a template block (Task B) with element_type contact_us,
about, privacy_policy, terms_of_use, or do_not_sell. Edit the block's
html_content, purge, done. No deploy.
When something DOES need a worker deploy¶
Only these need code + npm run deploy:site-stage (then prod after sign-off):
- A genuinely new builder (custom rendering logic) — see
AGENTS.md. - Changing the engine itself (routing rules, caching, the Handlebars renderer).
- New global behavior (headers, security, redirects).
Everything else on this page is configuration.
Quick reference¶
| I want to… | Where | Deploy? |
|---|---|---|
| Change colors/fonts | CSS in R2 + bump css_version |
No |
| Change a section's HTML | template_blocks.html_content (or site override) |
No |
| Add a list/detail page | new page_types row |
No |
| Add a layout variant | new page_types row (same type, new variant) |
No |
| Edit a static page | its template_blocks block |
No |
| Custom rendering logic | new builder in src/engine |
Yes |
After any data change, purge the cache (Task A step 4) or wait for the TTL.