Skip to main content

Article Body Elements

This is the golden standard for how article body content is authored, rendered, and styled on id86.net. Any AI or author creating or editing a .md file in ID86-instant-documentation must read this document first and follow the contract below.

Pipeline Overview

Markdown is converted by sync.py using markdown2 with these extras:

fenced-code-blocks, tables, strike, header-ids, footnotes, highlightjs-lang

The generated HTML is serialized into Gutenberg block markup by tools/blockify.py and stored as post_content, so posts open in the block editor as real blocks (headings, tables, lists, admonitions, and Code Block Pro blocks) — no "Classic" block or manual Convert-to-blocks step. Styling and behavior are applied at render time:

  • css/article-content-v2.css — all article body element styles (child theme).
  • js/article-content.js — table scroll wrapper, heading anchors, task checklists (child theme).
  • opshell-docusaurus-admonitions — renders opshell/admonition blocks server-side.
  • Code Block Pro (plugin) — code blocks are pre-rendered by Shiki (VS Code engine, github-dark) into wp:kevinbatdorf/code-block-pro blocks; the plugin's front.js adds the copy button.

See 4. WP Ops → Gutenberg Block Reference for the exact block serialization formats and the markdown→block mapping.

Element Contract

This table is the authoritative mapping. Follow it exactly when authoring.

ElementMarkdown syntaxSerialized as (Gutenberg block)Rendered HTMLStyled byJS
Page titleFrontmatter title— (rendered by #Single Post Title)H1Brand H1
Post meta linenone (auto)— (rendered by [id86_modified_date])updated M j, Y · N min read.id86-post-meta
H2 section## Headingcore/heading (anchor)<h2 id class="wp-block-heading">article-content-v2.css h2anchor link
H3### Headingcore/heading (level+anchor)<h3 id class="wp-block-heading">h3anchor link
H4#### Headingcore/heading (level+anchor)<h4 id class="wp-block-heading">h4anchor link
Paragraphblank-line separated textcore/paragraph<p>p
Bold**text**inline in paragraph<strong>strong
Italic*text*inline in paragraph<em>inherited
Inline code`code`inline in paragraph<code>:not(pre) > code
Strikethrough~~text~~inline in paragraph<del>inherited
Link[text](url)inline in paragraph<a href>a
Unordered list- itemcore/list + core/list-item<ul class="wp-block-list"><li>ul/ol
Ordered list1. itemcore/list (ordered) + core/list-item<ol class="wp-block-list"><li>ul/ol
Task checklist- [ ] item / - [x] itemcore/list + core/list-item (literal [ ]/[x] kept in <li> text)<ul><li>[ ] item</li></ul>article-content-v2.cssarticle-content.js → interactive checkbox
Code block```lang fencedkevinbatdorf/code-block-pro block (Shiki pre-rendered)<div class="wp-block-kevinbatdorf-code-block-pro">plugin CSSCBP copy button
Tablepipe tablecore/table<figure class="wp-block-table"><table class="has-fixed-layout">tablescroll wrapper
Blockquote> textcore/quote<blockquote class="wp-block-quote">blockquote
Admonition:::type titleopshell/admonition<aside class="opshell-admonition">plugin CSS
Footnote[^1] + definitioninline <sup> in paragraph + .footnotes in core/html<sup class="footnote-ref"> / .footnotesfootnotes
Image![alt](url)core/image<figure class="wp-block-image"><img>img
Horizontal rule---core/separator<hr class="wp-block-separator has-alpha-opacity"/>hr

Every element is wrapped in <!-- wp:<name> … --> … <!-- /wp:<name> --> block comments (serialized blocks), so the stored post_content is editor-ready block markup. See 4. WP Ops → Gutenberg Block Reference for every serialization format verbatim.

Authoring Rules

Heading hierarchy

The single-post template renders the title as H1. Article bodies must start at H2. Never use an H1 in the body — it duplicates the template title.

---
title: Git Quick Reference
---

## Start a repository ✅ correct — H2 is the first heading

Code blocks

Always use a fenced code block with a language tag. The tag drives Shiki highlighting and the language label:

```bash
sudo apt install plocate
```

markdown2 with the highlightjs-lang extra emits class="bash language-bash", which the sync pipeline converts into a Code Block Pro Gutenberg block (wp:kevinbatdorf/code-block-pro) pre-rendered with Shiki (VS Code engine) using the github-dark theme. The rendered block includes a built-in copy button, line numbers are off by default, and highlighting is baked into the saved HTML (no client-side tokenizer).

Tables

Use pipe tables. A header row is required:

| Task | Command |
|------|---------|
| Commit | `git commit -m "msg"` |

Wide tables are wrapped in a horizontal-scroll container by JS; keep cells concise.

Admonitions

Use Docusaurus ::: syntax. Supported types: note, tip, info, warning, danger. A custom title is optional.

:::note
Documentation posts do not require a featured image.
:::

:::warning[Custom title]
Removing a `.md` file does not delete its WordPress post.
:::

Admonitions are converted to <aside class="opshell-admonition opshell-admonition--note"> by the opshell-docusaurus-admonitions plugin (active on production).

Styling is a disclosure card — the child theme overrides the plugin stylesheet (css/article-content-v2.css) so admonitions match the .id86-affiliate-disclosure box on the Recommendations page (CSS-only, no icons, no JS):

  • Card: solid tinted surface, 1px border + 4px left accent, border-radius: 6px, no gradient, no box-shadow; full column width, padding: 14px 16px.
  • No icon: the plugin's SVG badge (.opshell-admonition__badge) is hidden with display: none.
  • Body: 0.92rem / line-height 1.6; title is bold, accent-colored (1rem).
  • Per-type accents (light / dark): note violet #7c5cbf / #a78bfa, tip green #2f9e44 / #4cc46a, info teal #0d9488 / #2fc3b3, warning amber #b7791f / #e0a83c, danger red #c24141 / #e05a5a. Dark mode uses solid dark surfaces.
  • Palette changes belong in css/article-content-v2.css (theme --id86-admonition-* custom properties); bump the theme Version header so the ?ver= cache-bust updates.

Task checklists

Use task-list bullets for sequential setup/checklist steps. The marker renders as a clickable, Notion-style checkbox on the live site — state is persisted per visitor in localStorage, so progress survives reloads. Each checklist group (<ul>) with two or more items shows a "X of Y done" progress badge + bar above it that updates live. Theme v1.20 adds a per-group Reset button, a green completion checkmark on full completion, and a Checklist hint pill for single-item lists. See Task Checklists for the full contract.

- [ ] Install tmux from your package manager.
Debian/Ubuntu and macOS (Homebrew) are both supported.
sudo apt install tmux
brew install tmux

Layout contract:

  • Checkbox + title inline on the bullet line — the checkbox always leads.
  • Content goes below the title, never before the checkbox: an optional short description can be indented (4 spaces) directly under the bullet (renders as a muted sub-line); commands go in a separate fenced code block below.
  • - [ ] = pending, - [x] (or - [X]) = already done (renders pre-checked and struck through).
  • Do not nest checkbox lists deeper than one level; sub-commands belong in code blocks.
  • Use checklists for step-by-step flows (setup, verification, migration). Don't use them for ordinary prose lists.

Prefer multi-item groups

A checklist group only earns its full UX — the "X of Y done" progress bar, the completion checkmark, and the per-group Reset — when the group holds two or more contiguous - [ ] items. Design checklists so each section has at least 2–3 steps in one block; a lone - [ ] item still becomes a checkbox but renders only a small Checklist hint pill and no progress.

Keep the group contiguous. The items of one group must sit in the same block with nothing between them — no fenced code blocks, no blank-line paragraphs, no headings, and no nested lists. Any of those breaks the <ul> in HTML, silently splitting the group into single-item lists, so the progress header disappears for that section even though the checkboxes still work.

To keep groups contiguous when a step needs commands:

  • Write the full group of - [ ] items first, then put the fenced code block(s) after the whole group:

    - [ ] Install tmux from your package manager.
    - [ ] Confirm the version with `tmux -V`.
    - [ ] Reload the config inside a running session.

    ```bash
    sudo apt install tmux
    tmux -V
    tmux source-file ~/.tmux.conf
  • Or keep the code block inside one item's indented description (4 spaces) so it stays within that item and does not separate siblings:

    - [ ] Install tmux from your package manager.
    ```bash
    sudo apt install tmux
    brew install tmux
    • Confirm the version.

Rule of thumb: if you can visually draw one box around the whole section's checkboxes, the group is contiguous. If a code block or paragraph sits between two checkboxes, split it into its own group or move it after the list.

Visual contract (design rules — see Task Checklists):

  • Rows are card-style (light #fcfeff fill, thin border, 3px left accent rail, 10px radius, soft shadow).
  • Idle → hover #f4faff; checked (is-done) → #e8f3fb; checked + hover → #dceefa. Dark mode has its own palette.
  • The checklist is flush against the left edge of the article column (list indent removed).
  • Checked rows strike through and mute the text; each group's Reset button clears only that group, and a final Reset checklist button clears the visitor's whole-post progress.

The stored HTML keeps the literal [ ] marker; js/article-content.js converts it to a styled <input type="checkbox"> at render time, adds id86-task-list to the parent <ul>, groups items by parent <ul>, and injects the per-group progress header (CSS in css/article-content-v2.css).

End-to-end: Markdown to live checkboxes

  1. Author the checklist in the .md source with literal - [ ] / - [x] bullets (see Task checklists above). Keep each group's items contiguous — a fenced code block between items splits the group in HTML, so no "X of Y done" progress header renders for that group.

  2. Sync the repo to WordPress with the standard wrapper:

    cd /home/rezriz/github/ID86-instant-documentation
    ./tools/id86-sync.sh --dry-run # validate markdown only, no WordPress changes
    ./tools/id86-sync.sh # real sync: render → WP-CLI bridge → WordPress

    id86-sync.sh runs sync.py, which converts the body with markdown2, renders code blocks with Shiki, SCPs the payload + bridge to the origin host, and runs wp eval-file through WP-CLI. Only changed documents (by source hash) are updated.

  3. Post-sync automation runs automatically: the Fuse.js search index is rebuilt, and LiteSpeed (origin-direct) + Cloudflare caches are purged for the changed posts (plus the homepage).

  4. Verify on the live post: checkboxes render clickable, a multi-item group shows the live progress header with a per-group Reset button and a green ✓ on full completion, single-item lists show the Checklist hint pill, and the final Reset checklist button clears the post's localStorage state. The score-90 reference post is demo/checklist-ux-demo.md (https://id86.net/demo/checklist-ux-demo/).

The checklist transform happens entirely at render time in js/article-content.js — nothing in the stored HTML changes beyond the literal [ ] marker, so re-syncing an unchanged file is a no-op.

Glossary

A glossary post (content type: glossary) is one term per H2, never a bold list under a single Terms heading. This gives every term a heading anchor and makes each term a scannable section that answers what is X?.

## Pane

A rectangular split region inside a window. Panes share the window's size and can be
resized, zoomed, and rearranged.

## Session

A named collection of windows. Sessions survive detach and are the unit you attach
to with `tmux attach`.

Layout contract:

  • Each term = ## Term — sentence case, no trailing period in the heading.
  • Definition-first: sentence 1 answers "what is it"; sentence 2 (optional) adds usage, a command, or a relevant cross-link.
  • No ## Terms wrapper heading — it becomes empty once terms are H2s. Add an optional lead-in paragraph before the first term instead.
  • Keep 8–15 terms, roughly 250–450 words, so every heading carries real definition content rather than a heading dump.
  • Cross-link each term to the deepest existing post on that concept — descriptive anchor text, one target per term, no dead-end terms. This is what lets a glossary feed per-term rankings; see Glossary SEO.
  • The heading hierarchy rule still applies — the template title is H1, so ## Term is the correct starting level.

The reference post content/demo/DEM-000005-tmux-glossary.md (https://id86.net/demo/tmux-glossary/) is the verification fixture for this format.

Footnotes

Define the note anywhere below the reference:

A reference here.[^1]

[^1]: The footnote definition text.

Where Styling Lives

ConcernLocation
Article CSSid86/css/article-content-v2.css
Article JSid86/js/article-content.js
Admonition CSSplugin opshell-docusaurus-admonitions/assets/css/admonitions-v2.css, overridden by id86/css/article-content-v2.css (disclosure card, no icon)
Code blocksCode Block Pro plugin (code-block-pro free + cbp-theme-pack), pre-rendered by Shiki in ID86-instant-documentation/tools/code_block_pro/ during sync
Syntax themeShiki github-dark (VS Code engine)
Enqueuefunctions.php — article CSS/JS loaded only on is_single(); CBP block assets auto-enqueued when a block is present

All CSS uses the brand tokens from the brand system (--id86-navy, --id86-blue, --id86-sky, --id86-ink, --id86-mist).

Verified Sample

The live reference post demo/styling-sample.md (https://id86.net/demo/styling-sample/) exercises every element above and is the verification fixture for this standard. Re-run the sync and inspect that post after any styling change.