Search by

A Magna CMS plugin.

Package info

github.com/Magna-CMS/Blog

Type:magna-plugin

pkg:composer/magna-cms/blog

Statistics

Installs: 24

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.3.0 2026-10-22 14:28 UTC

This package is auto-updated.

Last update: 2026-10-23 15:38:03 UTC


README

Magna Blog

Magna Blog

A blog plugin for Magna CMS, the open-source Laravel headless CMS — public post pages through Magna Pages, and a delivery API for headless frontends.

License: MIT PHP Magna CMS

Magna Blog is a plugin for Magna CMS. It manages blog content through the Magna admin panel using an Editor.js block editor, and exposes a read-only delivery API for any frontend — a headless site, a static build, or a native app.

With Magna Pages installed, every published post is also served as a page of your site, at its permalink and inside your theme's layout. Without Pages the blog stays headless: it owns authoring, organisation and delivery, and presentation is left to your frontend.

Screenshots

The full-screen post builder

An Editor.js canvas beside a tabbed sidebar for post settings, block settings and SEO.

The Magna Blog post builder — Editor.js canvas with the post settings sidebar

Blocks and paragraph templates

Insert from the block toolbox, then restyle the selected block from the Block tab — thirty-six paragraph treatments, all sanitised server-side, no CSS required.

The block toolbox open beside the paragraph template gallery

Posts

Every post with its category, status, visibility, author and schedule, filterable and searchable.

The Posts table in the Magna admin panel

Per-post SEO

With the optional Magna SEO plugin installed, each post gains a search-appearance panel: SEO title, meta description, canonical URL, focus keyword, robots directives and social cards.

The SEO tab of the post builder

Settings

General, slugs, permalinks, editor, fonts, content, custom fields and comment options — all in the admin panel.

The Blog settings page

Overview

  • Block editor — a rich Editor.js authoring experience with 30+ content blocks, sanitised server-side and delivered as structured JSON.
  • Full content model — posts, nested categories, tags, series, co-authors, per-post language and translation groups.
  • Editorial workflow — draft, pending review, scheduled, published and archived states, with soft- delete Trash, revisions and scheduled publishing.
  • Public post pages — with Magna Pages, each published post is served at its permalink inside the site's theme.
  • Delivery API — a versioned, cache-friendly JSON API for headless frontends.
  • Engagement — threaded comments with spam protection, and anonymous reactions.
  • Operations — CSV export, WordPress (WXR) import, GDPR personal-data export/erase, and webhooks.
  • Optional SEO — integrates with the Magna SEO plugin for per-post metadata when it is installed.

Features

  • Posts — title, slug, excerpt, Editor.js content, featured image, author and co-authors, category, tags, series and position, status, visibility (public / private / password-protected), and per-post locale with translation groups.
  • Editor.js — a configurable, extensible block set; content is stored as JSON and sanitised on the server through an allowlist model.
  • Taxonomies — nested categories and flat tags, each managed as its own admin resource, with a self-healing default ("Uncategorised") category.
  • Series — group related posts into an ordered set with automatic previous/next navigation.
  • Revisions — every create/update snapshots the post into the core revision store, pruned to a configurable maximum; restore any revision from the editor.
  • Scheduling — scheduled posts publish automatically when their date arrives.
  • Delivery API — read-only JSON for published, public posts, with filtering, search, pagination, related posts, adjacent posts, taxonomies, comments and reactions.
  • Comments — held for moderation or auto-approved, protected by a honeypot and an optional Akismet driver; one level of threading.
  • Reactions — anonymous, per-visitor reactions with a non-reversible fingerprint (no personal data stored).
  • Import / export — bulk CSV export (formula-injection safe) and WordPress WXR import.
  • Privacy — GDPR personal-data export and erase for authors and commenters.
  • Webhooks — emits blog.post.published, blog.post.updated and blog.post.deleted events.
  • Internationalisation — a blog:: translation namespace for the admin surface.

Requirements

  • PHP 8.3+
  • Magna CMS 1.6.2 or later, below 2.0 (provides Laravel, Filament, the media library, users, permissions, settings, revisions, privacy and webhook subsystems)
  • Magna Pages — optional, for public post pages
  • Magna SEO — optional, for per-post SEO metadata
  • Laravel's task scheduler running (php artisan schedule:run every minute from cron) — scheduled posts are published by blog:publish-scheduled, and buffered view counts are saved by blog:flush-views

Installation

Magna Blog is installed from the Plugin Marketplace inside Magna CMS — no Composer commands, no manual file copying, no build step.

  1. Sign in to your Magna CMS admin panel.
  2. Go to Plugins → Add New Plugin.
  3. Find Magna Blog in the marketplace and click Install.
  4. Activate the plugin when the install finishes.
  5. Open Blog → Posts and write your first post.

Magna Blog installed and active on the Plugins page

Updates arrive the same way: when a new version is published, the Plugins page shows it under Update Available.

Configuration

Backend and content settings are edited from Admin → Blog → Settings (general, slugs, permalinks, editor, fonts, content, custom fields and comments). Infrastructure options — the comment spam driver and reaction types — live in config/blog.php and are environment-driven:

BLOG_COMMENT_SPAM_DRIVER=honeypot   # or "akismet"
AKISMET_KEY=
BLOG_COMMENT_MIN_SECONDS=2
BLOG_DEFAULT_LOCALE=en

Usage

Create and manage posts from Admin → Blog. The full-screen builder pairs an Editor.js canvas with a tabbed sidebar for post settings, block settings and (when the Magna SEO plugin is installed) SEO.

Artisan commands

Command What it does
php artisan blog:import-wxr <file> Import posts, categories and tags from a WordPress WXR (.xml) export
php artisan blog:export [--out=<file>] Export all blog content to a JSON bundle (default storage/app/blog-export.json)
php artisan blog:import <file> Import a JSON bundle created by blog:export (idempotent, matched by slug)
php artisan blog:reindex Rebuild the search index column for all posts
php artisan blog:publish-scheduled Publish scheduled posts whose date has passed (runs every minute via the scheduler)
php artisan blog:flush-views Save buffered view counts to the database (runs every five minutes via the scheduler)

Public post pages

With Magna Pages installed, each published, public post is served at the Permalink pattern set in Blog → Settings (default /blog/{slug}), inside the site's layout, with the post's title and description as the page's meta. For the /blog listing, place the Blog posts block on a Pages page.

  • Patterns — tokens {slug}, {year}, {month}, {day} and {category}, each a whole path segment (/blog/{year}/{slug}, not /blog/{year}-{slug}). {slug} is required; a pattern the site cannot serve falls back to /blog/{slug} and logs a warning. Every blog link, and the sitemap when Magna SEO is installed, follows the same pattern; only a post's canonical path answers.
  • Visibility — drafts, scheduled, private and password-protected posts, and unknown slugs, get the site's 404. A Pages page published at the same path wins over the post.
  • Theming — themes style the page with CSS: <article> sits directly inside .magna-frontend-page--content, with .post-title, .post-meta (.who, .dot), .featured, .post-body and .post-nav. The comments section is a sibling after </article>: section.post-comments#comments with .post-comments__title, .post-comments__list, li.post-comment#comment-{id} (.post-comment__meta, .post-comment__author, .post-comment__date, .post-comment__text, details.post-comment__reply, .post-comment__replies, .post-comment--reply), .post-comments__notice (--pending, --approved), .post-comments__closed, .post-comments__login and form.post-comments__form with .post-comments__submit.
  • Pagination — set the Blog posts block's Pagination to Newer / older pages: "How many" becomes the number per page (empty means the Posts per page setting), page 1 lives at the bare path and the rest at ?page=N (up to 100), and a page past the end is a 404. The block renders core's magna-pagination navigation.
  • Languages — a post whose language is one of the site's languages other than the default is served under that language's prefix (/fr/blog/bonjour); every other post at the bare path. Prev/next links stay within the language, and translations sharing a translation group are offered as alternates.
  • Caching — guest post pages and listings are stored by the Pages cache and purged when a post, comment, category, tag or Blog setting changes; a post scheduled for later appears on time with no save, and a comment form closes on time.
  • Redirects — changing a published post's slug, date, category or language, renaming a category, or editing the permalink pattern redirects the old URL to the new one (through Magna Pages' redirects).
  • Comments — each post shows its approved comments (oldest first) and, while comments are open, a form. New comments are held for moderation or auto-approved per Blog → Settings. The form works on cached pages, carries a signed render stamp and a honeypot, is rate limited, and can show a captcha when Magna Defence enables the Blog comment form surface.

Known limits

  • Commenter identity. There is no frontend member system: "Require login to comment" means signed in to the Magna panel, and a signed-in commenter's name and email come from their panel account. Guests give a name and email.
  • One ?page per page. Two paginated Blog posts blocks on the same page follow the same ?page= parameter and move together.
  • Threads are one level deep and a post page shows at most 100 top-level comments.
  • Pattern edits run inline. Redirects for a permalink pattern change are worked out during the save, a few queries per published post; on a very large blog the save takes a moment.

Editor

Content is authored with Editor.js and stored as a structured block document. The tool set is open for extension without modifying this plugin — register a tool before an editor mounts:

window.magnaBlog.registerTool('myBlock', { class: MyBlockTool, inlineToolbar: true });

Server-side security allowlists (block types, templates, code languages, social networks) live once, in PHP, and are shared by the sanitiser and renderer. See docs/adding-a-block.md for the full block-authoring checklist.

API

The delivery API is auto-prefixed at /api/v1/blog/ and protected by the magna.api middleware (delivery-token auth with per-token rate limiting). Only published, public posts are ever returned.

Method Path Returns
GET /api/v1/blog/posts Paginated, filterable, searchable list
GET /api/v1/blog/posts/{slug} A single published public post
GET /api/v1/blog/categories The category tree with post counts
GET /api/v1/blog/tags Tags with post counts
GET /api/v1/blog/posts/{slug}/comments Approved comments (threaded one level)
GET /api/v1/blog/posts/{slug}/comments/stamp A signed _ts for a comment form (no-store)
POST /api/v1/blog/posts/{slug}/comments Submit a comment for moderation
POST /api/v1/blog/posts/{slug}/reactions Toggle a reaction

Responses are frontend-agnostic and never expose internal fields (password hashes, soft-delete state). Fields are only ever added: since 1.2.0 a post also carries summary (its excerpt, else one generated from the body) and url (its public, language-prefixed path). Since 1.2.1 adjacent prev/next stay in the post's own language, and each entry in translations carries the url it is served at.

Comment bot check. Fetch GET …/comments/stamp when your comment form is shown and send the returned _ts with the submission. A stamp younger than blog.comments.min_submit_seconds (default 2) is treated as a bot and quietly not stored. The unsigned form_started_at field is deprecated: it is still honoured (it can only make a submission look automated, never admit one) and will be removed in 2.0.

Permissions

blog.posts.view        blog.posts.create      blog.posts.edit
blog.posts.edit-others blog.posts.delete      blog.posts.publish     blog.posts.restore
blog.categories.manage blog.tags.manage       blog.series.manage
blog.comments.manage   blog.settings.manage

Per-record post actions follow a permission-plus-ownership rule: an author acts on their own posts, while blog.posts.edit-others lifts the ownership restriction for editors and administrators.

Content blocks

The editor ships a broad block set, including paragraph (with visual templates), headings, lists, checklists, quotes and pullquotes, tables, code, callouts, CTAs, buttons, FAQ, details, galleries, cover, image, video and audio, embeds, maps, social icons, footnotes, RSS, table of contents, related posts, group and columns layouts, and dynamic post blocks (excerpt, featured image). Every block is validated server-side before it can be persisted.

Contributing

Working on the plugin itself (rather than using it) needs Node.js, because the editor bundle is a build artifact:

npm ci
npm run build            # rebuild dist/blog-editor.js after changing resources/js/
php artisan filament:assets

Testing

The plugin ships an extensive Pest suite (feature and unit) that runs inside a Magna CMS application.

# From the Magna CMS application
php artisan test --testsuite=Plugins

# Style, static analysis and tests in one go
composer plugin-check -- magna/blog

# Or separately
vendor/bin/phpstan analyse -c plugins-dev/magna/blog/phpstan.neon.dist
vendor/bin/pint --test plugins-dev/magna/blog

Security

Content is protected in depth: an allowlist sanitiser cleans every Editor.js block before it is persisted, and the renderer escapes on output. Outbound editor requests (link preview, RSS) are SSRF-hardened with special-use IP-range blocking and connection pinning. CSV export is protected against formula injection, imports parse XML with network access disabled, and per-record authorisation is enforced server-side on every mutation.

To report a security issue, please contact the Magna CMS maintainers privately rather than opening a public issue.

Changelog

See CHANGELOG.md.

License

Magna Blog is open-source software licensed under the MIT license.