Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Blog Laravel Package

stephenjude/filament-blog

A complete blog management package for Filament. Create and manage posts, categories, tags, authors, and comments from your admin panel, with rich text editing, publishing controls, and SEO-friendly content tools. Integrates smoothly with Laravel and Filament.

View on GitHub
Deep Wiki
Context7

Getting Started

This package is a back-office only content manager: it gives you Filament resources for posts (and their taxonomy/author plumbing) and leaves the public-facing site entirely to you. That "faceless" design is the thing to internalize before you write a line of code — you are installing an admin UI, not a blog engine.

Version alignment comes first. As of 5.0.0 the package requires Filament 5 and supports Laravel 13. The 4.x line is what you want on Filament 4 / Laravel 11–12. Decide your Filament major before composer require, because the package major tracks it — a mismatch surfaces as an unresolvable dependency conflict or, worse, a plugin that registers but explodes on a form API that changed.

# Filament 5 / Laravel 13
composer require stephenjude/filament-blog:^5.0

# Filament 4
composer require stephenjude/filament-blog:^4.2

Minimal path on 5.x:

composer require stephenjude/filament-blog:^5.0
php artisan vendor:publish --provider="Stephenjude\FilamentBlog\FilamentBlogServiceProvider"
php artisan migrate

Use the interactive php artisan vendor:publish prompt if the provider/tag names have drifted in your installed version — publish the config and migrations at minimum, and any views/assets the prompt lists.

Then register the plugin in your panel provider:

public function panel(Panel $panel): Panel
{
    return $panel
        // ...
        ->plugin(FilamentBlogPlugin::make());
}

Where to look first, in this order:

  1. config/filament-blog.php — this is the contract. It decides richtext vs. markdown, which models are used, and often the editor/driver and disk. Read it before touching anything else.
  2. The published migration — confirms the actual columns (slug, content, published_at, category_id, user_id, etc.) so you know what your frontend can query. On 5.0.0, diff it against the version you last published — see Gotchas.
  3. The models the config points at — you will almost certainly subclass these.
  4. The panel's navigation — confirm the blog group appears and which policies/abilities gate it.

First use case: log into /admin, create a category, create a post with the configured editor, publish it, then prove the loop end-to-end by rendering it in your own route:

Route::get('/blog/{post:slug}', fn (Post $post) => view('blog.show', compact('post')));

If that renders, the package is doing its job and everything after this is your application's responsibility.

Implementation Patterns

Own the model layer via config. Don't edit vendor files. Publish/extend the package model, add your own casts, accessors, scopes, and relationships, then point the config's model key at your subclass. This is the sanctioned extension point and it survives upgrades:

class Post extends \Stephenjude\FilamentBlog\Models\Post
{
    protected $casts = ['published_at' => 'datetime', 'content' => 'string'];

    public function scopePublished($q)
    {
        return $q->whereNotNull('published_at')->where('published_at', '<=', now());
    }
}

Treat content as untrusted HTML. The richtext mode stores markup; markdown mode stores source. Decide once, at the model or presenter layer, and be consistent:

  • Richtext → sanitize on output ({!! clean($post->content) !!} via mews/purifier or HTMLPurifier) or sanitize on save via a Filament mutateFormDataBeforeSave.
  • Markdown → render with CommonMark at read time and cache the result if the post is hot. Never store both a markdown source and a rendered HTML blob without a clear rule about which one wins.

Separate the editor decision from the content decision. The config's editor toggle is an authoring convenience; changing it later does not convert existing rows. If you plan to switch, add a content_format column or a format cast so old posts still render correctly.

Draft/review/publish workflow. The cheapest implementation is published_at nullable + a scopePublished. Push it further with a status column and a Filament table badge/action; for scheduled publishing, a php artisan schedule:run command that flips a scheduled → published state is more auditable than a bare timestamp comparison.

Authorization is your job. Filament resources are reachable by any user who can access the panel unless you gate them. Create a PostPolicy, register it, and — if the blog lives alongside other admin concerns — scope access with canAccessPanel() or the resource's canViewAny().

Multi-panel and multi-tenant. If you run separate admin panels, register the plugin only where it belongs. For tenancy, add a tenant_id/team_id to the posts table and override the resource's getEloquentQuery() to scope by the current tenant — the package won't do this for you.

Custom resources must track the Filament major. Any resource you subclass or copy to change the form is written against Filament's schema/form API, and Filament 5 is where those signatures move. If you've overridden PostResource::form(), treat that override as code you must re-verify on 5.0.0 — not something the package upgrade will fix for you. Keep such overrides thin and delegated so a major bump is a small diff.

Headless / API consumption. The admin UI is decoupled, so exposing posts over JSON is trivial: a PostResource API resource over Post::published()->with('category','author')->paginate(). Cache the index aggressively and bust on saved/deleted model events. Laravel 13's serialization and cache defaults are worth re-reading if you're jumping from 11 — verify your cache-busting actually fires under the new model-event behaviour rather than assuming.

SEO and extras. Add meta_title, meta_description, og_image by extending the resource form (PostResource::form() via your own resource registered instead of the package's, or a relation/sidebar section). Prefer your own resource if you need deep form changes; the package form is a starting point, not a fixed schema.

Testing. Use Filament's Livewire testing helpers for the admin side and plain feature tests for the public routes. Test factories may not ship with the package — write your own against the published migration, and pin them to the columns you confirmed there. Filament 5 changed test-helper affordances in places; if admin tests fail after the bump, that is a test-harness issue before it is a package bug.

Gotchas and Tips

5.0.0 is a major, and the changelog undersells it. The release notes read as two lines — "Add support for Filament 5 and Laravel 13" plus a dependabot bump — but that is a compatibility-floor release: it drops Filament 4 support. There are no new features and no deprecations to chase; the entire risk is the peer-dependency jump. Budget the upgrade as a framework migration, not a patch.

Upgrade checklist for 5.0.0:

# 1. Bump Laravel and Filament first, get the panel booting without the blog package
composer require laravel/framework:^13 filament/filament:^5
# 2. Then the package
composer require stephenjude/filament-blog:^5.0
php artisan vendor:publish --provider="Stephenjude\FilamentBlog\FilamentBlogServiceProvider" --tag=filament-blog-migrations  # inspect, do not blindly overwrite
php artisan migrate
php artisan config:clear && php artisan filament:optimize-clear

Then in order: diff the package's database/migrations against your published copies, re-run your admin tests, and click through one create/edit/publish cycle. The migration diff is the step people skip and it's where a new column silently never lands.

Migration collisions. Published migrations are now your migrations. If the package later adds a column, your stale copy won't get it. Keep a note of what was published and diff against the package's database/migrations on upgrade. Never re-run vendor:publish over migrations you've already modified.

Config and component caching. Filament caches components in production. After changing the config, model class, or navigation, run:

php artisan config:clear
php artisan filament:optimize-clear

A "my config change does nothing" bug is almost always one of these two. Filament 5 adds its own optimize command surface, so if filament:optimize-clear isn't the right name in your install, php artisan list filament will tell you.

Rich text rendering is an XSS surface. Filament's editor output is HTML. Echoing it raw into a Blade view is a stored-XSS hole the moment anyone but you can author posts. Sanitize at output, and add a rel="noopener" / link-policy hook if you allow user-supplied content.

Editor switch is not a migration. Flipping richtext ↔ markdown in config changes the form field, not the data. Half your archive will render as literal **bold** or raw <p> tags. Plan the switch, don't discover it.

Slug uniqueness and routing. Confirm whether the package generates slugs and enforces uniqueness. If not, add a unique index and a mutateFormDataBeforeSave that slugifies — duplicate slugs will break {post:slug} route binding and silently return a 404 that looks like a routing bug.

File/disk configuration. If the editor uploads images, the disk comes from the config and the filesystem config. A broken image in the admin usually means php artisan storage:link hasn't run or FILESYSTEM_DISK differs between local and production.

Don't git clone fixes into vendor/. Every customization has a supported path: config model swap → subclass; form changes → your own resource; presentation → your frontend. Anything else gets destroyed by composer update.

Pin the major and read the changelog before bumping. This package's cadence is sparse and it sits on Filament's release schedule — which means its majors will lag Filament majors by an indeterminate amount. Pin explicitly ("stephenjude/filament-blog": "^5.0") and, when Filament ships its next major, expect a window where you must hold Filament back rather than the blog package. That dependency ordering is the practical constraint to plan around, not a hypothetical.

Debugging order when the panel 500s: (1) is the plugin registered in this panel, (2) do the installed package and Filament majors actually match (4.x vs 5.x), (3) does the config point at classes that exist, (4) are the migrations actually run. That sequence resolves most first-install and post-upgrade failures.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums