Skip to main content

Content Model

Documentation Posts

References are standard WordPress post entries distinguished by a meta key:

_id86_content_type = <frontmatter content_type> (from the Markdown source)

The child theme filters homepage cards and the Fuse.js search index against this marker. A post is part of the documentation experience when _id86_content_type holds one of the registered content types.

Block content: the body is stored in post_content as serialized Gutenberg block markup (generated by the sync pipeline's blockify), so every documentation post opens directly in the block editor. See 4. WP Ops → Gutenberg Block Reference for the block inventory and serialization formats.

Content type values

_id86_content_type drives the content-type badge on archive cards (id86_archive_card_shortcode). The single source of truth is the id86_content_types() registry in the child theme (also exposed as the id86_content_types filter), which mirrors the approved Content Types plus an other catch-all:

ValueBadge shown
cheatsheetCheatsheet
referenceReference
checklistChecklist
glossaryGlossary
promptPrompt
snippetSnippet
patternPattern
templateTemplate
runbookRunbook
otherOther
(unset / unknown)Other (fallback)

Manual override (Content Type metabox)

Each post editor shows a Content Type sidebar dropdown (the ten registered values, or blank to clear) registered by the Fluent Snippets PHP snippet 3-content-type-metabox.php (run_at=backend, storage wp-content/fluent-snippet-storage/). The dropdown options are loaded from the theme's id86_content_types filter, so registering a new type in the theme automatically adds it to the editor. Saving a post writes the selected value to _id86_content_type.

Automation behavior

Every Markdown source must declare content_type in its frontmatter (a registered type from Content Types). The sync bridge (tools/wp-sync-bridge.php) writes that value to _id86_content_type only when the meta is empty (new posts). A manually chosen value is preserved across future syncs — automation never overwrites a manual override. Set or inspect it manually with:

wp post meta update <id> _id86_content_type cheatsheet # -> "Cheatsheet" badge
wp post meta update <id> _id86_content_type reference # -> "Reference" badge
wp post meta get <id> _id86_content_type

The legacy value instant-documentation (pre-registry) was migrated to reference.

Source Metadata

Each documentation post carries two additional meta keys for sync tracking:

KeyPurposeExample
_id86_source_pathRepository-relative Markdown source pathcode/git/git-cheat-sheet.md
_id86_source_hashSHA-256 content hash for change detectionb5a15644535cd33c42322bed4c8361285c21daf621fddcf297739b0067944aa1

Categories

Categories are locked to a single-select of 4 main categories. The four main categories drive the site chrome and are published and shown on the homepage:

SlugDisplay NameTierCurrent Post Count
codeCodeMain2
devopsDevOpsMain2
aiAIMain1
securitySecurityMain1

Auxiliary categories also exist:

SlugNotes
demoHidden system category hosting the article-body styling verification fixture (styling-sample)
testingLeft over from frontmatter verification; no posts

Auxiliary categories (demo, testing) never appear on the homepage.

Categories determine:

  • The hero quick-topic links.
  • The niche card section (4 cards, one per category).
  • The color accent on each card (via .id86-code, .id86-devops, .id86-ai, .id86-security CSS classes).
  • The category archive pages.

New top-level folders auto-create their WordPress category on sync (e.g. demo/demo), so auxiliary categories do not require manual setup.

Note on seo vs security: the content model lists security as a main lane, but the register and live site still hold a seo category (SEO-000001). Migrating the live seo category/post to security (or vice versa) is a separate follow-up; the register documents the current state.

Post Views

Each single post view increments post_views_count post meta. This is used by the optional popular-post query via the order_by_views GenerateBlocks class.

Markdown Source Repository

The pre-publication Markdown source of truth lives at:

/home/rezriz/github/ID86-instant-documentation

Repository: github.com/donnyaw/ID86-instant-documentation

Content is authored in Markdown and synchronized to WordPress for initial publication. After publication, WordPress Gutenberg becomes authoritative for live content. Later Markdown syncs protect the published post and do not overwrite its body or editorial metadata.

Authoring happens in the local register mirror (/home/rezriz/github/seo-content/web-project/id86.net/content/). New documents are created with scripts/new-doc.py, which generates the file named PID-title.md (e.g. content/devops/DEV-000003-tmux-split-panes-cheat-sheet.md) plus the matching content-inventory.csv row in one command. Each file carries an explicit slug: frontmatter field so WordPress URLs stay clean (/devops/tmux-split-panes-cheat-sheet/) even though the filename embeds the PID. See Content Register — New Document Workflow.

Editing Content

Before publication, Markdown is the source of truth for content. After publication, WordPress Gutenberg is authoritative for live content; the CSV register remains the source of truth for lifecycle and identity. The register (content-inventory.csv) documents every column, the status lifecycle, content types, PID rules, and validation tooling — see Content Register. To update a post:

  1. For an unpublished post, edit Markdown in content/ and validate it.
  2. Publish the post once through the scheduled publishing or sync workflow.
  3. For a published post, edit the post directly in WordPress Gutenberg. Do not edit its Markdown expecting the live post to change.
  4. Use the CSV for lifecycle, PID, keyword, and audit identity updates.
FieldWhen to edit
Body contentAlmost always — the actual update
titleWhen renaming the post
descriptionWhen the summary / meta description changes
tagsWhen adding or removing tags — multi-select, comma-separated, maximum 5 tags
dateOnly to change the publish date
id / category / slug / statusNever — structural (id/category), URL-breaking (slug), or CSV-controlled (status)

Two different dates:

FieldFormatMeaningWho updates it
Frontmatter dateYYYY-MM-DD (date only)WordPress publish date shown in the postYou, only when re-dating
CSV Updated columnYYYY-MM-DDWhen the file was last editedAuto — refreshed by the validate script from the file timestamp

Date convention: the frontmatter date field uses date only (YYYY-MM-DD) — no time-of-day component. WordPress stores the post at 00:00:00 on that date. A future date makes WordPress hold the post as future status and auto-publish it when the WordPress scheduler runs on that day, so date doubles as the scheduling mechanism on the sync path.

The Updated refresh is automated by an hourly systemd user timer (id86-inventory-refresh), which runs validate-inventory.py --fix automatically from the file save-times.

Two CSV-driven scripts in wp-ops (01-operations/content-management/) control the flow:

ScriptCSV StatusEffect
id86-publish-scheduled.shscheduledSends the markdown to WordPress directly (via WP-CLI bridge) when Publish Date <= today, then flips the row to published
id86-push-published.shpublishedCopies the markdown into the canonical GitHub repo and pushes to main, where GitHub Actions syncs it to WordPress (SSH fallback: tools/id86-sync.sh locally)

The register's Publish Date column (format YYYY-MM-DD) holds the target go-live date and is required for scheduled rows. When that date arrives, the publish script sends the post to WordPress and automatically flips the status to published.

Content Templates

Single posts use two GeneratePress Elements:

  1. #Single Post Title (ID 3663, Page Hero): Breadcrumbs, H1 title, author, date.
  2. #Single Post Content (ID 1371, Content Template): Featured image, post content, tags, related posts, comments.