Skip to content

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_types table, 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 in template_blocks.html_content.
  • Page descriptor — a row in page_types that 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 default article and a listicle article) 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.

  1. Edit the CSS for the template (the source CSS for celebrity-v1).
  2. Upload it to the R2 assets bucket under a new version number. If the current css_version is 3, upload as version 4:
    # 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"
    
  3. Bump css_version on the template in the database:
    UPDATE templates SET css_version = '4' WHERE slug = 'celebrity-v1';
    
  4. 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}'
    
  5. 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, …).

  1. Find the block for the element_type you want (e.g. article) on the site's template, and edit its html_content. Use the admin API / DB:
    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';
    
    The markup is a small Handlebars-style template. Keep the placeholders the builder expects, e.g. <div data-render="content_blocks"></div>, <div data-grid="related_articles"></div>, <div id="sidebar-slot"></div>.
  2. 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>" }
    
  3. Purge the cache (see Task A step 4).
  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_types row:

    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';
    
    Field meanings: routes = URL patterns ({x} captures a param); layout = which content slot(s) to render (here it reuses the category block); sources = what to fetch and what to call it; grids = put list's items into the data-grid="articles" placeholder; ttl = cache seconds; seo.from = where the title/description come from (site defaults). Then purge the cache. Success: /tag/anything renders 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.

  1. Add a second page_types row for the same type with a different variant:
    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';
    
  2. Make sure a listicle article block exists (Task B) if the markup differs.
  3. The variant is chosen per content item (e.g. from the content's settings.layout field). Set that on the articles that should use it.
  4. 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.