Your CMS Shouldn’t Be a Second System: Inside VBWD’s CMS and CMS-AI Plugins

Most SaaS teams bolt WordPress onto a subdomain and live with the seam forever. VBWD makes the CMS a plugin inside the same app as billing and users — with a prerendering SEO layer, a write-side permalink engine, and an AI copilot that proposes patches but never persists them.

A look at two plugins that argue your marketing site and your product shouldn’t be different software.

Here’s a pattern almost every SaaS team repeats. You build the product. Then marketing needs a blog, a pricing page, and landing pages — so you bolt WordPress onto a subdomain. Now you have two systems, two deploys, two security surfaces, two logins, and a permanent seam between “the app” and “the site.” Your pricing page has no idea what your plans cost. Your product pages can’t tell whether the visitor is a paying customer.

VBWD takes the opposite position: the CMS is a plugin inside the same application as your billing, shop, and users. Same database, same auth, same deploy. Two plugins carry it — CMS and CMS-AI — and they’re worth a look whether or not you ever run VBWD, because the design decisions are unusually opinionated.

One content model instead of five

Most CMSs accumulate entities: a table for pages, another for posts, another for whatever came next. VBWD’s CMS runs a single cms_post table with a type discriminator — page, post, or a type a plugin defines itself — plus a matching unified taxonomy table for categories. Hierarchy comes from a self-referencing parent, so page trees and nested categories fall out of the same mechanism.

That sounds like housekeeping until you see what it buys. Because a plugin can register a new post type through a registry, any part of the system can get real CMS content without the CMS knowing it exists. The sharpest example is Entity Pages: attaching a full CMS page to any other plugin’s entity — a shop product, a bookable resource — requires exactly one small link table and zero schema changes in the adopter plugin. Your product detail page inherits the whole stack: rich content, custom CSS, widgets, all ten SEO fields, full-text search, translation linking. For free.

Layouts, widgets, and the override that saves your afternoon

Presentation splits into layouts (named templates with ordered areas), widgets assigned into those areas, and styles. Widgets come in four flavors: raw HTML, menus, slideshows, and Vue components — the last being the seam where any plugin can ship a real interactive block.

The detail worth stealing is the per-post widget override. Anyone who has used a template system knows the moment: one page needs a slightly different header, so you clone the whole layout, and six months later you have nine near-identical layouts nobody dares touch. VBWD lets you swap a single widget on a single page without cloning anything.

Styles are refreshingly unclever: a CmsStyle is a plain CSS stylesheet, one marked default, and the cascade runs default style → the post’s assigned style → the post’s own CSS from the editor’s CSS tab. No proprietary token language to learn or fight.

Widgets can also be gated by access level — meaning a block appears only for users at a given tier. When your CMS lives inside your billing system, “members-only content” stops being a plugin you buy and becomes a checkbox.

The SEO layer is the real story

This is where the plugin stops being a nice CMS and starts being genuinely unusual. Every post carries ten SEO fields — meta title, description, keywords, OG title/description/image, canonical URL, robots directives, JSON-LD schema, and an exclusion flag. That’s table stakes. What follows isn’t.

Prerendering. The CMS subscribes to content-change events and writes static HTML to disk — status-aware, so published content is written, drafts aren’t, and trashed content is removed. Writes are atomic (temp file, fsync, replace) and path-confined. Each document inlines the post’s JSON so the single-page app mounts without a second fetch.

Dynamic rendering for bots. Crawlers hitting the site get a real headless-Chromium render from a separate self-hosted service, cached on miss. Two design choices show the maturity: a wrong or missing shared-secret token returns 404, so the render route is never revealed to a prober; and a render miss returns 502 so nginx falls back to the normal app shell — the site never 5xx’s because the renderer had a bad day.

The rest. A dynamic sitemap that automatically chunks into a sitemap index past 50,000 URLs and emits hreflang alternates. Generated, overridable robots.txt. IndexNow pings to Bing, Yandex, and Seznam on publish. RSS. Scheduled publishing. Asset re-stamping on deploy so prerendered files point at the current hashed bundles.

One small detail tells you this was built by someone who got burned: sitemap timestamps are normalized to W3C datetime at a single choke point, because naive production timestamps make Google reject the entire file. You don’t write that line unless you’ve watched it happen.

Search is Postgres full-text — a generated tsvector column weighted title, excerpt, then body, HTML stripped in pure SQL, GIN-indexed, ranked. No Elasticsearch to operate. It’s English-only today, which the project says plainly rather than burying.

The permalink engine

URLs are configurable in three modes — off, structured, or a token template using tokens like %category%, %year%, and %slug%. The clever part is that it’s a write-side-only transform: the path is computed once and stored, so every read surface — routes, sitemap, canonical tags, prerendered files — needs no knowledge of the scheme. Structured mode is sugar rendered through the same template engine, so the two can’t drift apart. There’s an admin preview endpoint, because changing your URL structure blind is how you lose your rankings.

CMS-AI: a copilot that refuses to overstep

The companion plugin adds AI to the editor, and its restraint is the interesting part.

Text. Four actions — freeform, article, SEO, and restyle. The service returns a validated patch containing only recognized CMS fields the model actually filled, and it is stateless: it never persists anything. The AI proposes; the operator saves. That single decision means an AI action can’t quietly overwrite your page.

Images. Generation runs on Replicate’s FLUX models (flux-schnell by default), and the adapter returns raw image bytes only — upload goes through the CMS’s own image service rather than a duplicate code path, then the gallery image is appended to your content. The Replicate token stays server-side and never appears in a response or an error body.

Where the model comes from. CMS-AI owns no API key, no endpoint, no provider SDK. It resolves a central LLM Connection managed in core by slug and stamps a last-used timestamp so admins can see which connection served a request. Swap providers once, centrally, and everything downstream follows.

Prompts are yours. The prompt flow, template, and variable manifest resolve from a per-instance directory, falling back to the plugin’s shipped defaults — so a file on your server always wins. You can retune how the AI writes without touching code or waiting for a release. Underneath sits LoopForge, a deliberately pure in-repo prompt-flow engine built to be extractable.

In the editor it’s a dropdown and a panel: pick an action, write a prompt, optionally check “generate only image from the prompt,” review the patch, save if you like it. You can watch the platform in action here and see a second walkthrough here.

What else is in the box

Geo-blocking enforced at two layers with an HMAC-signed bypass cookie, off by default and fail-open if the GeoIP database is missing. DB-driven routing rules and redirects with nginx config generation. A contact form with a honeypot and per-IP rate limiting that emits an event for the email plugin to handle — and returns 200 to bots so it never reveals its detection. Preview tokens for sharing unpublished drafts. Pinning, site-wide and per-category. A six-state lifecycle including scheduled and soft-deleted. Import/export using natural keys and two-pass resolution, so it’s idempotent and order-independent. A GDPR cookie-consent widget with Google Consent Mode v2 where reject is as prominent as accept.

The honest caveats

It’s self-hosted: you run the server, and that’s a real cost. Full-text search is English-only for now. The i18n story is translation-group linking plus hreflang, not a complete translation workflow — useful, but don’t imagine a full localization suite. And the visual editor is posts-only; pages are hand-authored HTML by design, which is either a feature or a dealbreaker depending on who’s editing.

Why it’s worth a look

The thesis under both plugins is that a CMS shouldn’t be a second system stapled to your product. When content, billing, users, and catalog share one database, things that are normally integration projects — gated content, product pages with real SEO, pricing pages that know your plans — become configuration. Add an AI layer that proposes rather than persists and reads prompts from a file you control, and you have something genuinely different from bolting a blog onto a subdomain.

VBWD is source-available under BSL 1.1 and free for commercial use below 6.7 BTC a year in attributable sales. Explore the plugin catalogue, the architecture, and the developer docs at vbwd.cc, browse the source on GitHub, or follow the project on LinkedIn.

VBWD is source-available — get the SDK on GitHub.

Happy
Happy
0%
Sad
Sad
0%
Excited
Excited
0%
Angry
Angry
0%
Surprise
Surprise
0%
Sleepy
Sleepy
0%

Investment Idea: Stablecoin Infrastructure Consolidation as Payment Rails

AI Was Supposed to Kill Developer Jobs. Postings Are Up 14% Instead.

Leave a Reply

Your email address will not be published. Required fields are marked *

6 − six =