Plugin Forge 1.5.1
Content
Post types — pages, posts, events, ingredients — defined in YAML and laid out in the builder.
Content holds every kind of entry a site publishes. A post type is one YAML file: its name, the theme page that shows it, whether it is dated, whether it has a summary and cover, its own extra fields, and the layout a new entry opens with. Adding events or ingredients is a file and a theme page — no PHP, no migration.
All types ship with the platform and each site switches on the ones it uses, so one client has events and another has ingredients from the same code. A switched-off type has no menu item and no public pages; its entries wait in the database.
Every type shares one table and one backend screen, and every entry is laid out in Builder.
What is inside
Post types
types/*.yaml — page.yaml documents every key. Another plugin adds types on forge.content.extendTypes.
- Pages — /your-slug, the title as the page's H1
- Posts — /blog/your-slug, dated, with a summary and cover, listed on /blog
Components
- contentEntry — one entry by type and slug; the draft in the builder preview
- contentList — published entries of one type, paginated
Admin screens
- Content — one menu item per type this site uses: list, settings form, builder
- Display per entry — Theme, Full width, or Canvas with nothing of the site around it
Claude connector
https://<site>/mcp as a custom connector in Claude (sign in with a backend account), or php artisan content:mcp locally.
- Sign-in — OAuth with PKCE through the backend login; works within that user's permissions
- Settings › Content › Claude connections — who is connected, with Disconnect
- get_schema, list_entries, get_entry, search_media — what Claude reads
- create_draft, update_draft — new drafts only, and only its own; nothing publishes
- Settings › Content › Post types — which types this site uses
See it running
Every link below is this site, not a screenshot.
- Journal contentList over the post type
Changelog
[1.5.1] — 2026-10-22
Code only — no migration.
Removed
controllers/entries/builder.php: the builder now renders itself (Builder 2.5.0).
[1.5.0] — 2026-10-22
Code only — no migration.
Added
find_itemsfor the connector: products, categories and tags for an element's picker, and site paths for a button's link — the same search the builder's panel uses, so Claude can build a selling landing page (hero, product slider, spotlight, categories) end to end. The instructions now describe those elements and how a hero is put together.- Published entries are offered when a button's link is chosen with Choose….
[1.4.1] — 2026-10-22
Code only — no migration.
Security
- The connector never adds or changes raw HTML. HTML code Claude sends is left out (and
reported); HTML blocks a person wrote are kept exactly as they are when Claude revises or
proposes changes to a page.
get_schemamarks the HTML element as not available to it.
[1.4.0] — 2026-10-22
Added
- Claude can edit and publish any entry — after you confirm. A new connector tool,
propose_edit, proposes changes to any entry the user may manage (a person's, a live page) and/or publishing it. It changes nothing by itself: it returns a link to a review page in the backend that shows, field by field, what would change (the content summarised as sections, elements and words), with Preview the proposed version rendering it on the real page, and the decision — I'm sure — save as draft, I'm sure — publish, or Decline.check_proposaltells Claude the outcome. Proposals are single-use and expire after 72 hours. - Content › Proposed changes lists them, with a counter on the Content menu for the ones waiting.
- The review page warns when someone saved the entry after Claude proposed the change, and when confirming would replace unpublished changes in the builder.
- View and Preview where you look for them: the settings form shows View for a live entry and Preview draft for a draft or a live entry with unpublished changes; the list has View / Preview beside Open builder.
Changed
- Refusals from
update_drafton a person's or a published entry now point Claude topropose_edit. The connector's instructions describe the confirm flow and tell Claude never to report a change as done beforecheck_proposaldoes.
Security
- Only a user who may manage that post type can confirm or decline a proposal, and only once.
Nothing a proposal carries reaches the entry except through the same cleaning as a draft
(the builder's sanitiser, stripped fields, checked image paths).
[1.3.0] — 2026-10-22
Added
- Remote Claude connector, signed in with a backend account.
https://<site>/mcpspeaks MCP over HTTPS, so Claude connects as a custom connector from the Claude app, claude.ai or Claude Code — no SSH, no files on the computer. Claude opens the site's own admin login; the person signs in and presses Allow; Claude then works as that user. - OAuth 2.1 as the MCP spec asks: discovery documents
(
/.well-known/oauth-protected-resource,/.well-known/oauth-authorization-server), dynamic client registration, PKCE (S256) on every sign-in, one-hour access tokens and 60-day refresh tokens that are replaced each time they are used. - Settings › Content › Claude connections: every connected app, who it works for, when it connected and was last used, with Disconnect.
- The tools are the same as the local
content:mcpserver; both now share one protocol class (Classes\McpProtocol).
Security
- The connector works within the signed-in user's permissions. Without Use the visual builder it does nothing; it sees, lists, creates and revises only the post types the user may manage. The local stdio server is unchanged (it runs as whoever can run artisan).
- Only SHA-256 hashes of sign-in codes and tokens are stored. Codes are single-use and live
ten minutes. Redirect addresses must be https, or http on localhost, and must match what the
app registered — problems before that check are shown on the site, never sent to an
unchecked address. The Allow screen checks the session's CSRF token, cannot be framed, and
sends no-store headers. Registration, sign-in and token endpoints are rate limited.
[1.2.0] — 2026-10-22
Added
- Claude connector.
php artisan content:mcpis an MCP server over stdio: Claude Code (terminal or desktop app) starts it once per session from the project's.mcp.json, and writes content through six tools:get_schema,list_entries,get_entry,search_media,create_draft,update_draft. A post is written as the builder's own element tree and opens in the builder like any other. - The
forge-postproject skill (.claude/skills/forge-post/) sends "make me a post for …" to those tools, with the writing rules: the site's language, one H1, sentence case, theme colours first. - An
origincolumn marks what the connector made.
Security
- The connector writes new drafts; people publish.
create_draftalways creates a new, unpublished entry; a slug already in use gets a number rather than replacing anything.update_draftrefuses any entry a person made and any draft once it has been published. Nothing in the connector can publish. - Every tree goes through the builder's sanitiser, extra fields through strip_tags, and image
paths are checked against the media library (missing ones are left empty and reported).
[1.1.0] — 2026-10-22
Added
-
Display, per entry, on a new Display tab in the entry's settings:
- Theme — the site's header and footer, and the type's own template around the content (for a post: breadcrumbs, title, date, summary, "All posts").
- Full width — the site's header and footer, and only what was built in between.
- Canvas — only what was built: no announcement bar, header, search, footer or side cart. For landing pages.
The
contentEntrycomponent hands templatesdisplayand the layoutcanvas. A type sets the default for its new entries withdisplay:in its YAML (Theme if absent); existing entries are Theme. With Full width or Canvas the page has no title of its own, so the setting reminds editors to add a Title set to H1.[1.0.0] — 2026-10-22
Added
- Post types from YAML. A type is one file in
types/: name, singular, icon, the theme page that shows one entry, whether it is dated (publish date, newest first, scheduling), whether it has a summary and cover, its own extra fields in October form-field syntax, and the element tree a new entry opens with.types/page.yamldocuments every key. A new type needs no PHP and no migration: all types share one table and store their extra fields as JSON, read in templates asentry.fields.<name>. Another plugin can add types on theforge.content.extendTypesevent. - Pages and Posts as the first two types, carried over from Builder 1.0.0: pages at
/:slugwith their title as the H1, posts at/blog/:slug, dated, with a summary and cover. - Switched on per site. Settings › Content › Post types lists every type the platform
ships; each site ticks the ones it uses. A site that has never saved the screen gets each
type's own
enabled:default (Pages and Posts). Unticking a type removes its menu item, its backend screens and its public pages, and leaves its entries untouched. - One backend screen for every type, under Content: a list, a settings form with the type's
own tab first, then Publishing and Search, and the builder. The slug field says where the
entry will live (
Lives at /blog/your-slug). - A permission per type (Manage dogodki, …), registered for every type whether this site uses it or not, so roles can be prepared in advance. Plus Choose which post types this site uses.
- Components:
contentEntry(one entry by type and slug; 404 for anything unpublished, scheduled, unknown or of a switched-off type; the draft in the builder preview) andcontentList(published entries of one type, paginated; newest first for dated types, alphabetical otherwise). - A slug is refused when a fixed theme page already answers to the entry's URL — checked for
every type, so a page cannot be called
aboutbut a post can (/blog/about).