Download the PHP package vitebox/laravel-blog without Composer
On this page you can find all versions of the php package vitebox/laravel-blog. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download vitebox/laravel-blog
More information about vitebox/laravel-blog
Files in vitebox/laravel-blog
Package laravel-blog
Short Description Drop-in blog management backend for Laravel: role-based editorial workflow (Admin, Publisher, Reviewer, Writer), categories, tags, auto/custom slugs with redirects, and multiple post types (standard, video, event, article, news, announcement).
License MIT
Homepage https://github.com/adrift-ghost/laravel-blog
Informations about the package laravel-blog
Laravel Blog (vitebox/laravel-blog)
A drop-in blog management backend for any Laravel 12 or 13 application (PHP 8.2+). You get:
- An admin panel with role-based access (Admin, Publisher, Reviewer, Writer)
- A full editorial workflow: draft → review → approve → publish or schedule
- Categories (nested) and tags, including a tag merge tool
- Automatic and custom slugs. Slugs are always unique, and when a published slug changes, the old URL redirects with a 301
- Six post types, and you can add your own:
- Cover image + content
- Cover image + video + content
- Event
- Article
- News feed
- Public announcement
- A read-only JSON API that your website front end or mobile app can use
It has no front-end build step and no extra Composer dependencies. It never modifies your users table.
1. Installation
blog:install does the following:
- Publishes
config/blog.php - Runs the migrations
- Creates the
storagesymlink for uploads - Makes the given (existing) user a blog Admin
Then open /blog-admin.
The package is auto-discovered, so you don't need to register a provider or alias. The admin panel uses your app's
web+authmiddleware, so users log in through your normal login page.
Using the package from a local folder or a private Git repo
Before migrating: UUID / ULID user keys
If your users table uses UUID or ULID keys, set this before you run the migrations:
Scheduled publishing
The package adds blog:publish-scheduled to Laravel's scheduler. It runs every minute. For it to work, the standard scheduler cron must be running on your server:
2. Roles and permissions
| Permission | Admin | Publisher | Reviewer | Writer |
|---|---|---|---|---|
posts.create (write, edit own drafts, submit) |
✔ | ✔ | ✔ | ✔ |
posts.view_any |
✔ | ✔ | ✔ | – |
posts.update_any |
✔ | ✔ | – | – |
posts.delete_any |
✔ | – | – | – |
posts.review (approve / request changes) |
✔ | – | ✔ | – |
posts.publish (publish, schedule, unpublish, archive, feature, pin) |
✔ | ✔ | – | – |
categories.manage |
✔ | ✔ | – | – |
tags.create (new tags while writing) |
✔ | ✔ | ✔ | ✔ |
tags.manage |
✔ | ✔ | – | – |
team.manage |
✔ | – | – | – |
The matrix lives in config/blog.php under roles, so you can change it without touching code. * and posts.* wildcards are supported.
Other rules:
- Writers see only their own posts. They can edit a post only while it is Draft or Changes requested.
- Reviewers can edit a post while reviewing it. They cannot review their own posts (see
workflow.allow_self_review). - The last active Admin cannot be demoted or removed.
Assigning roles. Use the admin panel (Team & roles), the CLI, or code:
Emergency access. Add BLOG_SUPER_ADMINS="[email protected]" to .env. Anyone listed there always has Admin access.
Optional trait for your User model:
Gates. The package registers a gate for every permission (blog.posts.publish, blog.categories.manage, …) and a PostPolicy. You can use them in your own code:
3. Editorial workflow
- Every transition is recorded in an audit trail, including reviewer comments. The trail is shown on each post.
- Direct publishing. Publishers can publish a draft directly unless you set
workflow.direct_publish = false. - Skipping review. Set
workflow.require_review = false. Submitted posts then go straight to Approved.
Events. Listen to these to send notifications (mail, Slack, …):
PostStatusChanged (fired on every transition), PostSubmittedForReview, PostApproved, PostChangesRequested, PostScheduled, PostPublished, PostUnpublished, PostArchived.
Each event carries $post, $from, $to, $user and $comment.
4. Post types
| Key | Cover | Video | Extra fields |
|---|---|---|---|
standard |
required | – | – |
video |
required | required (YouTube / Vimeo / .mp4 URL, or upload) | duration, transcript |
event |
optional | – | starts_at*, ends_at, venue, address, is_online, online_url, registration_url, organizer, price, capacity |
article |
optional | – | subtitle, byline, show_toc, references |
news |
optional | – | is_breaking, source_name, source_url, location |
announcement |
optional | – | priority* (low / normal / high / critical), audience, expires_at, show_banner, cta_label, cta_url |
Fields that need to be queried are stored in real, indexed columns: starts_at, ends_at and expires_at. All other fields are stored in the type_data JSON column. Everything is validated according to the type.
Adding your own type
The form, validation, storage and API output are generated from these definitions.
5. Slugs
- Auto. If you leave the slug empty, it is generated from the title or name.
- Custom. Whatever you type is normalised (transliterated, lower-case, hyphenated).
- Unique. On a collision the package appends
-2,-3, … It also checks trashed posts and old redirecting slugs. Reserved words (admin,create, …) are never used as-is. - Redirects. When the slug of a published post, category or tag changes, the old slug keeps working (the API answers with a 301 to the new slug).
- Live preview. The admin form shows the final slug as you type.
- Title changes. Editing the title does not change an existing slug, so links don't break. Set
slugs.regenerate_on_title_change = trueif you want slugs to follow title edits (drafts only).
In your own front-end routes:
6. Using posts on your website
Eloquent
JSON API (prefix api/blog; only published content is exposed)
| Endpoint | Notes |
|---|---|
GET /posts |
?type=event,news&category=slug&tag=slug&q=term&featured=1&sort=latest\|popular\|oldest&per_page=12 |
GET /posts/{slug} |
Full content plus related posts. Counts a view. Old slugs return a 301. |
GET /events/upcoming |
|
GET /announcements/active |
|
GET /categories |
Nested tree with post counts |
GET /categories/{slug} |
|
GET /tags |
|
GET /tags/{slug} |
|
GET /types |
Post type definitions |
7. Configuration highlights (config/blog.php)
| Key | Default | Purpose |
|---|---|---|
user_model |
App\Models\User |
Your user model |
table_prefix |
blog_ |
Prefix for all package tables |
admin.prefix / admin.middleware / admin.domain |
blog-admin / ['web','auth'] / null |
Where the admin panel lives and who can reach it |
api.enabled / api.prefix / api.middleware |
true / api/blog / ['api'] |
Public API |
media.disk |
public |
Any filesystem disk, e.g. s3 |
content.sanitizer |
BasicHtmlSanitizer |
Allow-list HTML cleaning. Strips scripts, event handlers and javascript: URLs, and only allows YouTube/Vimeo iframes. Bind your own Contracts\HtmlSanitizer (e.g. HTMLPurifier) if you prefer. |
content.editor |
textarea |
trix loads the Trix WYSIWYG editor |
Customising the UI. Run php artisan vendor:publish --tag=blog-views and edit the files in resources/views/vendor/blog.
8. Database tables
All tables use the configured prefix:
team_members: user ↔ roleposts(soft deletes)categories(nested viaparent_id)tagscategory_postpost_tagpost_activities: audit trail and review commentsslug_redirects
9. Testing
The suite contains 42 tests covering roles, the workflow, slugs, post types, the API, the sanitizer and a render check of every admin page.
License
MIT