hessam/laravel-blogger
A complete blogging toolkit for Laravel: publish posts with categories, tags and comments, manage media and SEO metadata, and use ready-made routes, controllers and views. Configurable, translatable and easy to drop into any Laravel app.
The package is a self-contained blog engine (front-end routes + Blade views + an admin CRUD panel) that drops into an existing Laravel app. Minimal path from zero to a working blog:
binshops/laravel-blog; the maintainer-distributed name is hessam/laravel-blogger. Confirm which name resolves from your registry before running composer require, otherwise you may pull an unrelated fork.php artisan vendor:publish --provider="BinshopsBlog\BlogServiceProvider"
# or selectively: --tag=config, --tag=migrations, --tag=views, --tag=public
php artisan migrate. This creates the blog tables (posts, categories, uploads, and typically a blog_admin/author table or uses your existing users).auth (and ideally a role check) before you expose the routes.php artisan storage:link; verify uploads_disk in config/blog.php points at a disk whose URL is publicly reachable, or post images will render broken in the admin and front end alike./blog; admin defaults to something like /blog_admin (exact prefix is configurable). Add one category, then one post with an image, then confirm it renders on /blog — that single loop exercises routing, upload, and view rendering, which is where most install problems show up.Where to look first: config/blog.php (routes prefix, admin middleware, pagination, comments/Disqus toggle, image settings) is the single most important file. Then vendor/binshops/laravel-blog/src/Http/Controllers to understand what the admin actually does, and the published resources/views/vendor/... tree once you publish views.
Treat the admin panel as the CMS, and your app as the consumer. The panel gives editors categories, posts, slugs, images, and basic SEO fields. Don't rebuild that UI; instead consume BinshopsBlog\Models\BlogPost (and the category model) from your own controllers when you need custom placements.
Embedding latest posts on a homepage or landing page. Query the model directly and render with your own Blade partial rather than including the package's list view:
$posts = \BinshopsBlog\Models\BlogPost::query()
->whereNotNull('posted_at')
->where('posted_at', '<=', now())
->latest('posted_at')
->limit(3)
->get();
Then loop and link to the package's show route (route('binshopsblog.show_full_text', ...) — confirm the route name in the published routes file, since it varies by version). This keeps marketing pages visually independent of the blog theme.
View overrides over controller overrides. The fastest customisation path is publishing views into resources/views/vendor/binshopsblog/... and editing them. Reach for controller/model overrides only when behaviour changes, not presentation — the package does not have a clean service-container rebinding story for its models, so subclassing or copying controllers is a heavier commitment than editing Blade.
Route prefixing via config, not route files. Set the blog base path (e.g. insights instead of blog) and the admin prefix in config/blog.php / .env. Avoid editing routes directly if you want to survive upgrades. If you must add routes (RSS, sitemap, tag pages), register them in your own routes/web.php alongside the package's — the package's routes are loaded by its service provider and will not conflict as long as prefixes differ.
Middleware layering for the admin. The intended pattern is: package admin routes → your middleware stack → gate. Put auth plus an authorisation middleware or a policy check on the configured admin middleware list, and consider an IP allowlist or a separate subdomain in production. This is the one integration decision you should not defer.
Custom fields and extended metadata. Add columns through a new migration (Schema::table('blog_posts', ...)) and expose them via a small custom admin form if needed, or via model accessors. Editing the package's own published migration works only on a fresh database and will bite you on the next environment.
Caching the listing. Because the front end queries the database on every request, wrap your custom listings in Cache::remember keyed by category/tag, and flush on BlogPost::saved/deleted via an observer. The package's own paginated listing is not cached.
Scheduled publishing. Posts carry a published timestamp; if the package filters on it (confirm in the model scope), you can draft by leaving it null or future-dated. If it does not scope, add a global scope on a subclass or filter in your consuming queries — otherwise drafts leak through your custom listings even if the package's own list hides them.
php artisan route:list --path=blog and check what middleware guards the admin routes. If the default is just web, anyone can publish to your blog.resources/views against your published copy and merge deliberately.migrations table after first run. Schema changes require new migrations; editing the file achieves nothing in existing environments..env changes. If you set the blog prefix or admin middleware in .env, run php artisan config:cache (or clear it) — this is the usual cause of "I changed the URL but it still 404s at /blog."storage:link is missing or the disk is local rather than a public disk. Check the rendered src on the front end, not just the admin thumbnail.saving hook to suffix duplicates — otherwise the show route resolves the wrong post.hessam/laravel-blogger vs binshops/laravel-blog vs the underlying binshops/blog composer name — pin the exact version in composer.json, and test on Laravel upgrades (especially 10→11 skeleton changes) in a branch. The repo is small and moves slowly; budget for it not supporting the newest Laravel immediately.vendor/ — any composer update will discard them.How can I help you explore Laravel packages today?