- PHP 57.7%
- Blade 42.3%
- Add a views column (migration) + integer cast. - recordView(): atomic increment on public show, without bumping updated_at. - related(): same category first, ranked by views then recency, backfilled. - Show the count in the built-in admin list. |
||
|---|---|---|
| config | ||
| database/migrations | ||
| resources/views | ||
| routes | ||
| src | ||
| .gitignore | ||
| composer.json | ||
| LICENSE | ||
| README.md | ||
Laravel Blog
A simple, lightweight, database-driven Markdown blog for Laravel. Posts live in your database, you write them in Markdown, and the package renders a public index + post pages. No uploads, no taxonomy sprawl, no bloat. Drop it into an existing app, point it at a layout, and you have a blog.
It is intentionally framework-light: it depends only on illuminate/* and
Livewire, ships with a minimal Livewire admin you can opt out of, and stays
Filament-free so any host can use it (and a Filament host can supply its own
resource against the Post model).
Features
- DB-driven Markdown posts: title, auto-slug, category, author name, excerpt, body, publish date, and a published toggle.
- Public pages: a blog index and per-post pages with
BlogPostingJSON-LD, meta description, and canonical URL. - Images via Markdown links: no upload pipeline — embed images with
. - Safe rendering: Markdown is rendered with raw HTML escaped and unsafe (
javascript:/data:) links stripped, so author content can't inject script. - Minimal Livewire admin (opt-out): a WordPress-simple CRUD at a configurable path, gated by a configurable gate. Disable it and bring your own admin (e.g. a Filament resource).
- Themeable: point the views at your own layout via config, or publish them to fully control the markup.
- Configurable routing: separate prefixes for the index, individual posts (e.g.
/p/{slug}), and the admin.
Requirements
- PHP 8.2+
- Laravel 11 or 12
- Livewire 3 (the optional admin is a Livewire component)
Installation
This package is loaded as a local Composer path repository. No separate installation is needed when developing within the host monorepo.
For standalone installation, add the git repository as a Composer vcs
repository (there is no Packagist), then require it:
// your app's composer.json
"repositories": [
{
"type": "vcs",
"url": "https://git.lithium.hosting/LithiumHosting/laravel-blog.git"
}
]
composer require lithiumhosting/laravel-blog
php artisan migrate
The service provider auto-registers. Publish the views/config as needed (below).
Configuration
Publish the config file:
php artisan vendor:publish --tag=blog-config
Config Options
| Key | Default | Description |
|---|---|---|
public_prefix |
blog |
Path for the blog index (listing). |
post_prefix |
null |
Path for individual posts; null shares public_prefix. Set to p for /p/{slug}. |
admin_prefix |
blog/admin |
Path for the built-in Livewire admin. |
public_middleware |
['web'] |
Middleware for the public routes. |
admin_middleware |
['web', 'auth'] |
Middleware for the admin routes. |
admin_gate |
manage-blog |
Gate ability the admin requires (in addition to the middleware). null to rely on middleware alone. |
register_admin_routes |
true |
Register the built-in Livewire admin. Set false if the host supplies its own admin. |
layout |
blog::layouts.app |
Blade layout the views extend. Point at your own layout, or publish the views. |
per_page |
10 |
Posts per page on the index. |
brand |
Blog |
Title/brand shown in the package's default layout. |
This package reads no environment variables directly; configure it via the published config file.
Usage
Routes
| Name | Path | Description |
|---|---|---|
blog.index |
/{public_prefix} |
Paginated list of published posts. |
blog.show |
/{post_prefix}/{post:slug} |
A single published post (404s on drafts/future dates). |
blog.admin.posts |
/{admin_prefix} |
Built-in Livewire admin (when register_admin_routes is true). |
Writing posts
Use the built-in admin, or create posts directly against the model:
use LithiumHosting\Blog\Models\Post;
Post::create([
'title' => 'White Rim Trail: a 2-day group plan',
'category' => 'Trails',
'author_name' => 'Troy',
'body' => "## Day 1\n\nDrop in at Shafer...",
'is_published' => true,
'published_at' => now(),
]);
slug auto-generates from the title (uniquely) when left blank. Post::published()
scopes to published posts whose published_at has arrived; $post->rendered_body
returns safe rendered HTML; $post->summary() returns the excerpt or a trimmed body.
Theming
Two options:
-
Use your own layout — set
blog.layoutto a layout that both@yield('content')(public views) and renders{{ $slot }}(the Livewire admin). -
Publish the views and edit them directly:
php artisan vendor:publish --tag=blog-viewsPublished views land in
resources/views/vendor/blog/and override the package's. This is the cleanest way to wrap the blog in an existing component layout.
Bring your own admin
Set register_admin_routes => false and build your own admin against
LithiumHosting\Blog\Models\Post — for example a Filament resource. The public
side and the Post model work the same either way.
Dependencies
illuminate/*(^11|^12): framework contracts, database, support.livewire/livewire(^3.0): the optional built-in admin.
Testing
composer test
(Uses Orchestra Testbench. Within a host app, integration is covered by the host's own test suite.)
License
The MIT License (MIT). Please see the License File for more information.
Is it any good?
Yes.
When people first hear about a new product, they frequently ask if it is any good. A Hacker News user remarked:
Note to self: Starting immediately, all raganwald projects will have a "Is it any good?" section in the readme, and the answer shall be "yes.".