Content Fields & Sections
How a section is built, what the field-name prefixes do, and how to keep every page editable by someone who has never seen the plugin.
A section is four things
| Part | Holds | Who edits it |
|---|---|---|
template_html |
Markup with {{placeholder}} markers |
AI, or you in Advanced Mode |
content_fields |
The actual words, images, links, icons | Anyone, in Content Mode |
scoped_css |
CSS scoped to this section | AI, or you |
section_js |
Optional JS, in an IIFE with section pre-bound |
AI, or you |
The split is the point. Changing the design needs the AI. Changing the content never does.
<!-- template_html -->
<section class="hero">
<h1>{{title}}</h1>
<p>{{html_subhead}}</p>
<img src="{{image_hero}}" alt="{{image_hero_alt}}" loading="lazy" />
<a class="hero__cta" href="{{cta_url}}">{{cta_label}}</a>
</section>
{
"title": "Care that starts with listening",
"html_subhead": "Same-day appointments, <strong>no waiting room</strong>.",
"image_hero": "https://example.com/wp-content/uploads/hero.jpg",
"image_hero_alt": "Dentist talking with a patient",
"cta_url": "/book/",
"cta_label": "Book a visit"
}
Field name prefixes
The prefix decides how the value is treated on render and which input Content Mode shows.
| Prefix | Behaviour |
|---|---|
| (none) | Plain text, HTML-escaped |
html_ |
Safe HTML allowed — bold, links, lists |
image_ |
Media picker. Always add a companion *_alt field |
icon_ |
Phosphor icon picker. Value is a kebab-case icon name |
shortcode_ |
Run through do_shortcode() on render |
Icons, specifically
Put the placeholder directly inside its container. The renderer replaces it with a complete
<span class="ppd-icon">…<svg>…</span>.
<div class="card__icon">{{icon_feature1}}</div> <!-- right -->
<span data-icon="{{icon_feature1}}"></span> <!-- wrong: SVG inside an attribute -->
For an icon that shouldn't be editable, hardcode it: <span class="ppd-icon" data-icon="shield-check"
data-icon-style="fill"></span>.
Icons inherit currentColor and are sized with CSS on the .ppd-icon span. 104 ship with the plugin;
1,500+ more are fetched on demand. Never use emoji.
Site-level placeholders
These resolve at render time and need no content field:
NoLeemits · https://noleemits.com/ · 2026 · ·
· · · {{business:social:*}}
Template placeholders — {{post_*}}, {{archive_*}}, {{term_*}}, {{search_query}}, {{paged_*}},
{{loop_wc_*}}, {{main_query}} — are covered in
Template System.
Content Mode field types
Attach a content_fields_schema and Content Mode renders a proper labelled form instead of bare text boxes.
Per field you can set label, description, type, placeholder, options and required.
Available types: text, textarea, wysiwyg, url, image, icon, number, select, color.
This is UI metadata only — it never changes what renders. Always provide it on any page you hand to someone else.
Hover to pause · click for full sizeKeeping pages editable
This is the single most important habit, and the plugin enforces it:
When the AI saves a section that is mostly hardcoded text with few or no editable fields, the plugin warns it during the write that Content Mode users won't be able to edit it.
If a section slipped through anyway, its editor shows a notice explaining that its content is hardcoded and
pointing at the code editor. The fix is always the same: pull the copy out of template_html and into
content_fields.
Rule of thumb: if a human might ever want to change it, it belongs in a content field.
Styling
- Use design tokens —
var(--ppd-colors-primary),var(--ppd-spacing-section-y)and so on. Set them once at Settings → Design Tokens. - Never declare
--ppd-*variables in page CSS. Tokens are owned by the token system and rendered fresh on every load; declarations in page CSS are stripped on save and on render so a stale hex can't shadow a live token. - Give every section a uniquely-classed wrapper.
- Section CSS is scoped and minified.
calc(),clamp(),min(),max()andvar()survive minification intact.
Section JavaScript
Use section_js, not a <script> tag in the markup. It runs in an IIFE with section pre-bound:
var btn = section.querySelector('.hero__cta');
Declare libraries in js_dependencies — gsap, scrolltrigger, aos, alpinejs, swiper, splide,
plyr, countup, typed, lottie — or pass a full CDN URL. They load only on pages that ask for them.
Prefer CSS. And never use IntersectionObserver on an above-the-fold section — elements already in the
viewport on load may never fire the observer and stay stuck at opacity: 0. Use setTimeout for hero entrances.
Reusing sections
- Section Library — save a section once, insert it into many pages. Edit the library item and every page using it updates. Per-page overrides are available. Library previews snapshot the source page's CSS so they render faithfully.
- Global sections — header and footer, injected on every page, with per-page overrides and an on/off switch.