binshops/laravel-blog
A ready-to-use blog package for Laravel with an admin dashboard for managing posts, categories, tags, comments, and media. Includes SEO-friendly URLs, customizable views, and role-based access to help you launch a complete blog quickly.
Install the package and publish its assets before writing any code:
composer require binshops/laravel-blog
php artisan vendor:publish --provider="BinshopsBlog\BinshopsBlogServiceProvider"
php artisan migrate
The publish step matters more than usual here — it copies the binshopsblog config file, the Blade views you'll be overriding, the migrations, and the front-end assets. Run it once, then read the config file from top to bottom; it's the single source of truth for the route prefix, admin middleware, image upload directory, and caching behavior.
Where to look first, in order:
config/binshopsblog.php — route prefix (default blog), the middleware guarding the admin panel, and upload paths.routes/ inside the package (or php artisan route:list | grep blog) — the front-end is a catch-all at /{prefix}/{slug} and the admin panel sits at /{prefix}/admin.resources/views/vendor/binshopsblog/ — the published Blade files you're expected to edit.First real use case: open /blog/admin as an authenticated user, create a category, then a post with an uploaded image, and confirm it renders at /blog. If the admin panel 403s, your admin_middleware in config doesn't match how your app guards privileged users.
Keep the package for authoring, not for presentation. Most teams use the admin UI to write posts and then query the models directly for their own front end, so the blog inherits the site's layout instead of the package's.
use BinshopsBlog\Models\BinshopsPost;
$posts = BinshopsPost::where('is_published', true)
->with(['category', 'tags', 'user']) // always eager load
->latest('posted_at')
->paginate(10);
Render your own card/list views from that. This avoids fighting the package's default CSS and lets you drop "latest three posts" into a homepage or sidebar without duplicating the blog index.
Override views, don't fork them. Publish views, edit the copies in resources/views/vendor/binshopsblog/, and leave the package files untouched. Wrap the default layout in your app's layouts.app by editing the single layout partial — everything else inherits it.
Author attribution. Posts link to a user via a user_id column. If your guard is not the default web guard, set the author explicitly on create, or add an accessor/mutator mapping your author model, otherwise the admin panel silently attributes posts to nobody.
Custom admin access. Rather than editing package code, change admin_middleware in config to something like ['web', 'auth', 'can:manage-blog'] and define that gate in your AuthServiceProvider. This is the clean extension point for role-based access.
Integration with an existing model. If posts belong to a tenant or team, add the foreign key through a follow-up migration and a global scope on BinshopsPost (via a small subclass, or addGlobalScope in a service provider) so the admin panel only lists that tenant's posts.
Caching. The config exposes cache settings; enable them for the front-end routes and bust the cache in an observer on BinshopsPost when a post is saved or deleted.
php artisan storage:link must have run. Check the configured upload path against your filesystem layout — a path that works locally often doesn't exist on the server.LIKE/where clauses or your own Scout integration./blog, change the prefix in config. Changing it after posts exist is safe (slugs are relative), but any hardcoded links in your own views are not.config:cache traps. Publish and edit config before caching, and re-run php artisan config:clear after any change. A stale cached config is the usual cause of "my middleware change did nothing."composer.json, and after upgrading, re-publish views and diff them — published views are not updated automatically, so template changes ship as silent breakage.How can I help you explore Laravel packages today?