Getting Started

Public-routes mode

Get a working blog at /blog without writing controllers — opt in via config flags.

The package ships an opt-in public-routes mode. Flip a flag in config and you get:

RouteNameNotes
GET /blogblog.indexPaginated post listing
GET /blog/{slug}blog.showSingle post (only published)
GET /blog/category/{slug}blog.categoryCategory archive (paginated)
GET /blog/preview/{post}blog.previewSigned-only draft preview, with noindex,nofollow meta
GET /blog/feedblog.feedRSS 2.0 feed (gated by features.feed)
GET /blog/tag/{slug}blog.tagTag archive (gated by features.tags)

Enable it

config/filament-blog.php
'features' => [
    'public_routes' => true,
    'feed'          => true,   // optional, enables /blog/feed
    'tags'          => true,   // optional, enables /blog/tag/{slug}
],

'layout' => 'layouts.app',     // your host layout the page views extend

That's it. The service provider registers the routes at boot — no Filament panel boot is required, so the public site keeps working for guests who never touch the admin.

Required: a host layout

The page views extend the layout you set in 'layout'. It must define a @yield('content') slot. A minimal example:

resources/views/layouts/app.blade.php
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>{{ $title ?? config('app.name') }}</title>
    @stack('head')
</head>
<body class="bg-white text-gray-900 dark:bg-gray-950 dark:text-gray-100">
    @yield('content')
</body>
</html>

If your layout uses a different slot mechanism (e.g. Blade components with {{ $slot }}), publish the page views and adapt them:

Terminal
php artisan vendor:publish --tag=filament-blog-views

Customizing pages

The shipped pages live at:

  • resources/views/vendor/blog/pages/index.blade.php
  • resources/views/vendor/blog/pages/show.blade.php
  • resources/views/vendor/blog/pages/category.blade.php
  • resources/views/vendor/blog/pages/preview.blade.php
  • resources/views/vendor/blog/pages/tag.blade.php
  • resources/views/vendor/blog/pages/feed.blade.php

Edit them freely — once published, the package no longer serves its own copies.

Custom prefix

Change 'prefix' => 'blog' in config. All routes pick up the new prefix.

Disabling individual pieces

Each feature flag is independent:

'features' => [
    'public_routes' => true,
    'feed'          => false,   // no RSS feed
    'tags'          => false,   // no tag archive (admin still works if registered)
],

When a flag is off, requests to that path return 404 (not registered). Route::has(...) returns true (the route is defined) but the controller calls abort_unless($flag, 404). That's a deliberate choice so route ordering stays predictable and you can probe the route name without crashing.

Mode comparison

HeadlessPublic-routes
Routes registeredNoneAll 6
ControllersYou writeShipped
ViewsComponents onlyFull pages
Custom domain logicYes (any)Limited to view overrides
Effort to ship a blog~2 hours~5 minutes

If you outgrow public-routes mode, flip the flag back to false and write your own controllers — see Frontend Setup (headless).