Skip to content

Sections

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.

Fetch 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[]
}

Fetch multiple sections with optional filters:

import { getSections } from "emdash";
// Get all sections
const all = await getSections();
// Filter by source
const themeSections = await getSections({ source: "theme" });
// Search by title/keywords
const results = await getSections({ search: "newsletter" });
interface Section {
id: string;
slug: string;
title: string;
description?: string;
keywords: string[];
content: PortableTextBlock[];
previewMedia?: { id: string; url: string };
source: "theme" | "user" | "import";
themeId?: string;
createdAt: string;
updatedAt: string;
}
SourceDescription
themeDefined in seed file, managed by theme
userCreated by editors in admin
importImported from WordPress (reusable blocks)

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. This means:

  • Changes to the section don’t affect already-inserted content
  • Editors can customize the inserted content
  • Content remains self-contained
  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

Include sections in your theme’s seed file:

{
"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" }]
}
]
}
]
}

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

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

For server-rendered section content 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>
)}

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)

Fetch a section by slug.

Parameters:

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

Returns: Promise<Section | null>

List sections with optional filters.

Parameters:

  • options.source — Filter by source: "theme", "user", or "import"
  • options.search — Search title and keywords

Returns: Promise<Section[]>

GET /_emdash/api/sections
GET /_emdash/api/sections?source=theme
GET /_emdash/api/sections?search=newsletter
GET /_emdash/api/sections/newsletter-cta
POST /_emdash/api/sections
Content-Type: application/json
{
"slug": "my-section",
"title": "My Section",
"description": "Optional description",
"keywords": ["keyword1", "keyword2"],
"content": [...]
}
PUT /_emdash/api/sections/my-section
Content-Type: application/json
{
"title": "Updated Title",
"content": [...]
}
DELETE /_emdash/api/sections/my-section