Makes WordPress a private CMS for a separately hosted frontend — REST plugin and Astro fetch client. https://git.rallen.dev/rallendev/blueline
  • PHP 87.8%
  • TypeScript 11.4%
  • Shell 0.8%
Find a file
Ryan Allen 94a45d2468
Some checks failed
check / check (push) Failing after 4s
Pin the Forgejo npm scope and install the plugin as blueline.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-11 11:28:33 +01:00
.agents Add canonical agent workspace and pnpm scaffold 2026-09-11 11:17:39 +01:00
.github/workflows Add README, changelog, contributing, and CI check 2026-09-11 11:18:34 +01:00
docs Pin the Forgejo npm scope and install the plugin as blueline. 2026-09-11 11:28:33 +01:00
packages/astro Pin the Forgejo npm scope and install the plugin as blueline. 2026-09-11 11:28:33 +01:00
plugin Document Forgejo package install for the 0.1.0 release. 2026-09-11 11:26:13 +01:00
scripts Add canonical agent workspace and pnpm scaffold 2026-09-11 11:17:39 +01:00
.gitignore Add canonical agent workspace and pnpm scaffold 2026-09-11 11:17:39 +01:00
AGENTS.md Add canonical agent workspace and pnpm scaffold 2026-09-11 11:17:39 +01:00
CHANGELOG.md Document Forgejo package install for the 0.1.0 release. 2026-09-11 11:26:13 +01:00
CLAUDE.md Add canonical agent workspace and pnpm scaffold 2026-09-11 11:17:39 +01:00
CONTRIBUTING.md Add README, changelog, contributing, and CI check 2026-09-11 11:18:34 +01:00
GEMINI.md Add canonical agent workspace and pnpm scaffold 2026-09-11 11:17:39 +01:00
LICENSE Add canonical agent workspace and pnpm scaffold 2026-09-11 11:17:39 +01:00
package.json Add canonical agent workspace and pnpm scaffold 2026-09-11 11:17:39 +01:00
pnpm-lock.yaml Add canonical agent workspace and pnpm scaffold 2026-09-11 11:17:39 +01:00
pnpm-workspace.yaml Add canonical agent workspace and pnpm scaffold 2026-09-11 11:17:39 +01:00
README.md Pin the Forgejo npm scope and install the plugin as blueline. 2026-09-11 11:28:33 +01:00
skills-lock.json Add canonical agent workspace and pnpm scaffold 2026-09-11 11:17:39 +01:00

Blueline

Blueline makes WordPress a private CMS for a separately hosted frontend. WordPress is the newsroom. The frontend is the published edition. Preview is the proof. A rebuild is going to press.

This is not Faust for Astro. Faust is a Next.js + WPGraphQL + Gutenberg product with frontend WordPress cookies. Blueline is REST, a classic-editor-friendly CMS, and a fetch client. It does not add WPGraphQL, block hydration, or WordPress login for public visitors.

Start at docs/context/product.md. Module contracts live in docs/.

Installables

Package Path Role
blueline/wordpress plugin/ WordPress Composer plugin (GPL-2.0-or-later)
@blueline/astro packages/astro/ Typed fetch client for blueline/v1

Install

Installables are published on Forgejo (rallendev/blueline). The Composer package root is plugin/, so consumers use the package registry rather than a VCS checkout of this monorepo.

Composer (blueline/wordpress)

{
  "repositories": [
    {
      "type": "composer",
      "url": "https://git.rallen.dev/api/packages/rallendev/composer"
    }
  ],
  "require": {
    "blueline/wordpress": "^0.1"
  },
  "extra": {
    "installer-paths": {
      "web/app/mu-plugins/blueline/": ["blueline/wordpress"]
    }
  }
}

Then composer update blueline/wordpress. Prefer mu-plugins so the package cannot be deactivated. Without that path, Composer installers put the plugin in wp-content/plugins/wordpress/.

npm (@blueline/astro)

Pin the scope so peers such as astro still come from npmjs:

@blueline:registry=https://git.rallen.dev/api/packages/rallendev/npm/
pnpm add @blueline/astro

Set PUBLIC_BLUELINE_CMS_URL to the WordPress origin. See packages/astro/README.md.

Local path (first consumer)

The first consumer can still map a path repository from /Volumes/2TB SSD/Projects/PRSM/brand-v2/apps/cms/composer.json. Do not edit that monorepo from this repository. Integration brief: docs/architecture/consumers.md.

{
  "repositories": [
    {
      "type": "path",
      "url": "/Volumes/2TB SSD/Projects/rallen.dev/blueline/plugin"
    }
  ],
  "require": {
    "blueline/wordpress": "*"
  },
  "extra": {
    "installer-paths": {
      "web/app/mu-plugins/blueline/": ["blueline/wordpress"]
    }
  }
}

Constants

Defined from env. Never stored in wp_options.

Constant Purpose
BLUELINE_FRONTEND_URL Public frontend origin. Empty → fail-closed 404 on public WP requests
BLUELINE_PERMALINK_STRUCTURE Optional; e.g. /blog/%postname%/
BLUELINE_WEBHOOK_URL Generic rebuild POST target
BLUELINE_WEBHOOK_SECRET HMAC for X-Blueline-Signature
BLUELINE_STATUS_URL Optional consumer status probe
BLUELINE_BUILD_TOKEN Fail-closed GET blueline/v1/redirects
BLUELINE_PREVIEW_SECRET HMAC for preview tokens
BLUELINE_PREVIEW_MODE Optional token or rebuild
BLUELINE_DROP_TABLES_ON_UNINSTALL If true, uninstall drops job/redirect tables

Comment-only examples: plugin/.env.example.

Filters

Filter Default Use
blueline_login_site_link_text ← Go to the website Login "go to site" label
blueline_headless_unavailable_title Headless CMS Missing frontend wp_die title
blueline_headless_unavailable_message headless-only copy Missing frontend wp_die body
blueline_public_post_types ['post'] Types rewritten to the frontend
blueline_rewritten_link rewritten URL Last chance to adjust a public URL
blueline_manage_sitemaps true Frontend owns sitemaps
blueline_seo_frontend_url rewritten canonical SEO seam
blueline_rebuild_debounce_seconds 45 Coalesce window
blueline_rebuild_request outbound payload Shape the webhook POST
blueline_rebuild_status null Consumer status probe
blueline_redirects_public false Opt in to public redirect export
blueline_deleted_redirect_target null (410) 301 deleted posts elsewhere
blueline_content_types ['post'] Types on GET blueline/v1/content
blueline_content_taxonomies ['category', 'post_tag'] Envelope taxonomy keys
blueline_content_item mapped item Extra envelope keys
blueline_menu_locations ['primary'] Menu locations
blueline_preview_ttl 900 Token lifetime
blueline_preview_base /preview Frontend preview prefix
blueline_preview_mode token token or SSG rebuild

REST (blueline/v1)

Public frontends should call these routes, not wp/v2.

Route Purpose
GET /content Published collection (X-Blueline-Total-Pages)
GET /content/{slug} One published item
GET /search Published search (q)
GET /menus/{location} Nav tree
GET /redirects Bakeable map (BLUELINE_BUILD_TOKEN or manage_options)
POST /preview/verify { token } → { post_id, exp }
GET /preview/{id} Draft envelope; ?token= must match id
POST /rebuilds/{id} Signed host callback
GET /rebuild/status Latest job (manage_options)

Features

Slice What you get
Headless core Public 302 to the frontend; admin/API stay; theme lock
URL ownership Permalinks and View links use the frontend origin
SEO Rank Math / Yoast / core adapters; no hard require
Rebuilds Debounced job table + generic webhook
Redirects Slug-change export for the static host
Content Stable envelope (html, path, seo, taxonomies, optional acf)
Menus / search Public nav tree and published search
Preview Signed token; latest revision overlay; frontend owns SSR
@blueline/astro Fail-open published fetch; fail-closed preview; menus; sitemap bake
Operator UX Settings, toolbar, notices, WP-CLI

Demo WordPress (optional)

Tests do not need Docker or wp-env. composer -d plugin test stays offline.

From plugin/:

npx @wordpress/env start

plugin/.wp-env.json boots vanilla WordPress with this plugin and BLUELINE_FRONTEND_URL=http://localhost:4321. WordPress core is downloaded by wp-env; it is not vendored in git.

Point the dummy frontend at a running Astro dev server:

# other terminal, any Astro app
pnpm astro dev --port 4321

Override the origin without committing secrets:

// plugin/.wp-env.override.json (gitignored)
{ "config": { "BLUELINE_FRONTEND_URL": "http://localhost:4321" } }

wp-admin: http://localhost:8888/wp-admin/ (see @wordpress/env docs for the generated password).

Checks

pnpm check

Runs pnpm agent:check, plugin Pint + Pest, and @blueline/astro tsc + Vitest. PHPStan/Psalm are not in the gate; see docs/testing.md.

composer -d plugin i18n   # regenerate plugin/languages/blueline.pot

License and contributing

GPL-2.0-or-later (LICENSE, plugin/LICENSE). How to work in this repo: CONTRIBUTING.md. How a human publishes: docs/architecture/release.md. Changelog: CHANGELOG.md.