Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Blog Laravel Package

wingsline/blog

A Laravel blog package that provides posts, categories, tags, and comments with migrations, Eloquent models, routes, and views, making it easy to add a complete, customizable blog to your Laravel application.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package and publish its assets:

composer require wingsline/blog
php artisan vendor:publish --provider="Wingsline\Blog\BlogServiceProvider"
php artisan migrate

The publish step typically exposes config/blog.php, migrations, and the Blade views used to render posts and the index. Read config/blog.php first — it controls the route prefix (/blog by default), pagination size, and which middleware the public routes sit behind.

Where to look first:

  1. config/blog.php — route prefix, middleware, pagination, layout/view overrides.
  2. routes/web.php (registered by the service provider) — confirm the public route names and whether an admin surface exists.
  3. The Post, Category, and Tag models — these define the fields and relationships you'll be querying.

First use case: stand up a simple markdown blog. Create a post in Tinker (or via the admin UI if included), visit /blog, and confirm the markdown body renders.

use Wingsline\Blog\Models\Post;
use Illuminate\Support\Str;

Post::create([
    'title'        => 'Hello World',
    'slug'         => Str::slug('Hello World'),
    'body'         => "# Welcome\n\nThis is **markdown**.",
    'published_at' => now(),
]);

Once that works, wire a link into your main navigation and you have a functioning blog. Everything after that is customization: overriding views, adding tags/categories, and integrating with your existing layout.

Implementation Patterns

Model-driven authoring. For programmatic publishing (imports, editorial tooling, CMS sync), create posts through the Post model and set published_at explicitly. Publishing is time-based, so scheduling a future date is a natural "draft" mechanism — future-dated posts simply won't show in public scope.

Post::create([
    'title'        => $title,
    'slug'         => Str::slug($title),
    'body'         => $markdown,
    'published_at' => $publishAt, // future date = scheduled
]);

View overrides over source edits. Publish the views (--tag=views if the package exposes it) and edit the copies. Never touch vendor/wingsline/blog. Because the views are plain Blade, reskinning the index and article pages to match your app's layout is the main customization workflow — usually by editing the layout/extend directive at the top of the published post view.

Routing and integration. The blog routes register under a config-driven prefix. To attach the blog to your existing site, link to route('blog.index') / route('blog.show', $post) rather than hard-coding /blog/.... If you need the blog behind auth or inside a subdomain, adjust the middleware and prefix in config/blog.php rather than re-registering routes.

Categories and tags. Use these relationships for archive/related-post navigation. Query through the relationship methods on Post rather than pulling all posts and filtering in PHP; combine with published_at <= now() scoping.

RSS and sitemap. If an RSS route ships with the package, it will consume the same published scope. For a sitemap, iterate published posts and emit route('blog.show', $post). Keep the canonical URL generation in one place (a helper or config) so RSS, sitemap, and views agree.

Observers and cache invalidation. Add a PostObserver on saved/deleted to clear any cached index or feed you layer on top. This is the cleanest extension point because the package predates most modern event conventions.

Testing your integration (not the package). Write feature tests against the public routes with RefreshDatabase, creating posts via the model. Assert the index lists published posts, hides future-dated ones, and that blog.show 404s for unknown slugs.

public function test_future_posts_are_hidden(): void
{
    Post::create([... 'published_at' => now()->addDay()]);
    $this->get(route('blog.index'))->assertDontSee('Scheduled');
}

Gotchas and Tips

It's archived — treat it as vendored code. Last release was December 2020, so expect Laravel 8/PHP 7.4–8.0 era conventions. Modern Laravel (10/11) will fight you on framework APIs. Pin the package, fork it, or budget a migration to first-party models. Do not build a roadmap that depends on upstream fixes.

Composer constraints. The package's composer.json will cap the supported Laravel and PHP versions. Expect to override constraints or use --ignore-platform-reqs at your own risk. Verify before committing to it in a new project.

Markdown rendering is the XSS surface. Posts are rendered from markdown/HTML. Sanitize the rendered output (e.g., a HTML purifier or strip_tags allowlist) if non-trusted users can author. Confirm whether the package uses a markdown parser that allows raw HTML — assume it does and guard accordingly.

Slug uniqueness and URL stability. The package relies on the slug for route binding. If you generate slugs automatically, handle collisions (append -2) before save, and decide early whether slug changes are allowed — changing a published slug breaks inbound links unless you add redirects.

Publishing cache. If you cache the index, remember that published_at crossing "now" doesn't fire a model event. A future-dated post becomes visible only when the cache expires. Use short TTLs or a scheduled command that clears the cache.

No built-in media/SEO. Expect to manage featured images, Open Graph tags, and meta descriptions yourself in the published views. This is normal but worth planning for in the view override step.

Debugging routes and config. Run php artisan route:list | grep blog and php artisan config:clear when behavior looks stale. Because config is published, a cached config file is a common source of "my prefix change didn't apply."

Extension points. Observers, published views, and config are the supported seams. Avoid subclassing package models unless you also control the service provider binding; a forked copy is often less painful than fighting the container.

Migration path. If the package becomes a liability, the safest move is to copy the migrations and models into app/ verbatim, keep the table names, and replace the package routes with your own controllers. This retains data and lets you modernize incrementally.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource