Sections

On this page

Sections are reusable content blocks that editors can insert into any content via slash commands. Use them for common patterns like CTAs, testimonials, feature grids, or any content that appears across multiple pages.

Querying Sections

getSection

The following example fetches a single section by slug:

import { getSection } from "emdash";

const cta = await getSection("newsletter-cta");

if (cta) {
  console.log(cta.title);    // "Newsletter CTA"
  console.log(cta.content);  // PortableTextBlock[]
}

getSections

The following example fetches multiple sections with optional filters:

import { getSections } from "emdash";

// Get all sections
const { items: all } = await getSections();

// Filter by source
const { items: themeSections } = await getSections({ source: "theme" });

// Search by title/keywords
const { items: results } = await getSections({ search: "newsletter" });

getSections returns { items: Section[], nextCursor?: string } following the standard pagination pattern.

Section Structure

A section has the following shape:

interface Section {
  id: string;
  slug: string;
  title: string;
  description?: string;
  keywords: string[];
  content: PortableTextBlock[];
  previewUrl?: string;
  source: "theme" | "user" | "import";
  themeId?: string;
  createdAt: string;
  updatedAt: string;
}

Source Types

SourceDescription
themeDefined in seed file, managed by theme
userCreated by editors in admin
importImported from WordPress (reusable blocks)

Using Sections in Content

Editors insert sections using the /section slash command in the rich text editor.

  1. Type /section (or /pattern, /block, /template)

  2. Search or browse available sections

  3. Click to insert the section’s content at the cursor position

The section’s Portable Text content is copied into the document. The inserted content is self-contained: editors can customize it, and later changes to the section do not affect copies already placed in content.

Creating Sections

In the Admin UI

  1. Navigate to Sections in the admin sidebar

  2. Click New Section

  3. Fill in:

    • Title - Display name for the section
    • Slug - URL identifier (auto-generated from title)
    • Description - Help text for editors
  4. Add content using the rich text editor

  5. Optionally set keywords for easier discovery

Via Seed Files

The following seed file defines two sections for a theme:

{
  "sections": [
    {
      "slug": "hero-centered",
      "title": "Centered Hero",
      "description": "Full-width hero with centered heading and CTA",
      "keywords": ["hero", "banner", "header"],
      "content": [
        {
          "_type": "block",
          "style": "h1",
          "children": [{ "_type": "span", "text": "Welcome to Our Site" }]
        },
        {
          "_type": "block",
          "children": [{ "_type": "span", "text": "Your tagline goes here." }]
        }
      ]
    },
    {
      "slug": "newsletter-cta",
      "title": "Newsletter CTA",
      "keywords": ["newsletter", "subscribe", "email"],
      "content": [
        {
          "_type": "block",
          "style": "h3",
          "children": [{ "_type": "span", "text": "Subscribe to our newsletter" }]
        }
      ]
    }
  ]
}

Via WordPress Import

WordPress reusable blocks (wp_block post type) are automatically imported as sections:

  • Source is set to "import"
  • Gutenberg content converted to Portable Text

Rendering Sections Programmatically

The following example renders a section’s content server-side, outside the editor:

---
import { getSection } from "emdash";
import { PortableText } from "emdash/ui";

const newsletter = await getSection("newsletter-cta");
---

{newsletter && (
  <aside class="cta-box">
    <PortableText value={newsletter.content} />
  </aside>
)}

Admin UI Features

The Sections library (/_emdash/admin/sections) provides:

  • Grid view with section previews
  • Search by title and keywords
  • Filter by source
  • Quick copy slug to clipboard
  • Edit section content and metadata
  • Delete with confirmation (warns for theme sections)

API Reference

getSection(slug)

Fetch a section by slug.

Parameters:

  • slug — The section’s unique identifier (string)

Returns: Promise<Section | null>

getSections(options?)

List sections with optional filters.

Parameters:

  • options.source — Filter by source: "theme", "user", or "import"
  • options.search — Search title, description, and keywords
  • options.limit — Page size (default 50, max 100)
  • options.cursor — Pagination cursor from a previous nextCursor

Returns: Promise<{ items: Section[]; nextCursor?: string }>

REST API

List Sections

List sections, optionally filtered by source or search term:

GET /_emdash/api/sections
GET /_emdash/api/sections?source=theme
GET /_emdash/api/sections?search=newsletter

Get Section

Fetch a single section by slug:

GET /_emdash/api/sections/newsletter-cta

Create Section

Create a section with a POST request:

POST /_emdash/api/sections
Content-Type: application/json

{
  "slug": "my-section",
  "title": "My Section",
  "description": "Optional description",
  "keywords": ["keyword1", "keyword2"],
  "content": [...]
}

Update Section

Update a section with a PUT request:

PUT /_emdash/api/sections/my-section
Content-Type: application/json

{
  "title": "Updated Title",
  "content": [...]
}

Delete Section

Delete a section by slug:

DELETE /_emdash/api/sections/my-section

Next Steps