Installation:
composer require drewroberts/blog
php artisan vendor:publish --provider="DrewRoberts\Blog\BlogServiceProvider" --tag="config"
config/blog.php.Database Migration:
Run migrations to create tables for Pages, Posts, Series, and Topics:
php artisan migrate
First Use Case:
use DrewRoberts\Blog\Models\Post;
$post = Post::create([
'title' => 'My First Blog Post',
'slug' => 'my-first-post',
'content' => '<p>Hello, world!</p>',
'status' => 'published', // or 'draft'
]);
use DrewRoberts\Blog\Models\Page;
$page = Page::create([
'title' => 'About Us',
'slug' => 'about',
'content' => '<p>About content here.</p>',
]);
Accessing Content:
$posts = Post::published()->get();
$post = Post::published()->where('slug', 'my-first-post')->first();
Content Management:
status (published/draft) and published_at timestamps.$recentPosts = Post::published()->latest()->paginate(10);
Series can contain multiple Posts, and a Topic can group related Posts or Series.Authorization:
tipoff/authorization. Extend or override default roles/permissions in app/Policies or via config.use DrewRoberts\Blog\Models\Post;
use Tipoff\Authorization\Contracts\Role;
Role::find('editor')->givePermissionTo(Post::class, 'update');
Nova Integration:
Page, Post, Series, Topic).app/Nova/Resources.Routing:
/posts/{slug}). Override or extend in routes/web.php:
Route::get('/blog/{slug}', [\DrewRoberts\Blog\Http\Controllers\PostController::class, 'show']);
API Endpoints:
Route::apiResource('posts', \DrewRoberts\Blog\Http\Controllers\Api\PostController::class);
Post:
use DrewRoberts\Blog\Models\Post;
Post::observe(function ($post) {
if ($post->wasRecentlyCreated) {
$post->update(['custom_field' => 'value']);
}
});
use DrewRoberts\Blog\Models\Post;
Post::addGlobalScope('meta', function (Builder $builder) {
$builder->addSelect(['meta_title', 'meta_description']);
});
spatie/laravel-medialibrary alongside the package for post/page attachments.Authorization Conflicts:
tipoff/authorization. Ensure the package is installed and configured:
composer require tipoff/authorization
php artisan vendor:publish --provider="Tipoff\Authorization\AuthorizationServiceProvider" --tag="migrations"
php artisan migrate
\Tipoff\Authorization\Facades\Authorization::can('update', $post);
Nova Resource Overrides:
php artisan nova:publish
php artisan view:clear
Slug Conflicts:
cviebrock/eloquent-sluggable:
use CViebrock\EloquentSluggable\Sluggable;
class Post extends Model implements Sluggable {
public function getSlugOptions() {
return ['source' => 'title'];
}
}
Missing Config:
return [
'default_post_status' => 'draft',
];
Outdated Dependencies:
Post::created(function ($post) {
Log::info('Post created:', ['id' => $post->id]);
});
\Tipoff\Authorization\Facades\Authorization::policies();
php artisan route:list to verify blog routes are registered.Custom Model Events:
Extend models by adding observers or events. Example for Post:
Post::observe(PostObserver::class);
class PostObserver {
public function saving(Post $post) {
$post->author_id = auth()->id();
}
}
API Responses: Override API controllers to customize responses:
class CustomPostController extends \DrewRoberts\Blog\Http\Controllers\Api\PostController {
public function show(Post $post) {
return response()->json([
'data' => $post,
'custom_field' => 'value',
]);
}
}
Query Scopes:
Add custom scopes to models. Example for Post:
class Post extends Model {
public function scopeFeatured($query) {
return $query->where('is_featured', true);
}
}
Usage:
Post::published()->featured()->get();
Middleware: Protect routes with custom middleware:
Route::get('/admin/posts', function () {
// ...
})->middleware(['auth', 'can:manage,post']);
Testing: Use package-specific factories (if available) or create custom ones:
$post = Post::factory()->create(['status' => 'published']);
How can I help you explore Laravel packages today?