ojessecruz/simple-blog
Ready-to-use Laravel blog package: clean public listing, Livewire admin CRUD, Markdown with HTML escaping, and draft preview in a new tab. Authentication/authorization is up to you via configurable middleware (Gate, guard, etc.).
Installation:
composer require ojessecruz/simple-blog
php artisan vendor:publish --tag="simple-blog-migrations"
php artisan vendor:publish --tag="simple-blog-config"
php artisan migrate
config/blog.php first—this is the central hub for all customization.First Use Case:
admin_middleware in config/blog.php (e.g., ['web', 'auth', 'can:manage-blog']).Author contract by implementing getBlogAuthorName() and getBlogAuthorInitials()./blog and admin panel at /admin/blog.Quick Wins:
--tag="simple-blog-views") if you need to tweak the default UI (e.g., swap Tailwind colors).Post and PostCategory models to query content directly (e.g., for sitemaps or exports).Admin Panel:
/admin/blog to create/edit posts./blog.Str::markdown()).Public Side:
@stack('head') in your layout)./blog/category/{slug}).admin_middleware in config/blog.php to reuse your app’s auth logic (e.g., ['web', 'auth:admin'] or a custom Gate).AuthServiceProvider:
Gate::define('manage-blog', fn ($user) => $user->is_admin);
public_middleware to control who can view the blog (e.g., ['web'] for open access or ['web', 'auth'] for logged-in users only).Public Layout:
blog::layouts.public by publishing views and overriding resources/views/vendor/blog/layouts/public.blade.php.@stack('head') for SEO tags.<x-app-layout>
@yield('content')
</x-app-layout>
// config/blog.php
'layouts.public' => 'layouts.blog-public',
Admin Layout:
layouts.admin to your admin shell (e.g., layouts.app for Jetstream/Breeze):
'layouts.admin' => 'layouts.app',
CTA Injection:
resources/views/components/blog-cta.blade.php) and configuring:
'cta_view' => 'components.blog-cta',
$post model.Custom Queries:
Post model for custom logic:
use Jessecruz\SimpleBlog\Models\Post;
$featuredPosts = Post::published()->latest()->take(3)->get();
Dark Mode:
dark: classes (supported since v0.4.0). Ensure your tailwind.config.js includes:
content: [
'./vendor/ojessecruz/simple-blog/resources/views/**/*.blade.php',
],
config/blog.php:
'route_prefix' => 'journal', // /journal instead of /blog
'admin_route_prefix' => 'content', // /content/blog
route('blog.show', $post)) for links.SEO Meta Tags Missing:
<head>.@stack('head').@push('head') directives are rendering.Dark Mode Flickering:
<input class="bg-white dark:bg-zinc-900 text-zinc-900 dark:text-zinc-100">
Tailwind Classes Not Compiled:
[object Object] or broken styles.tailwind.config.js:
content: [
'./vendor/ojessecruz/simple-blog/resources/views/**/*.blade.php',
],
Drafts Still Visible:
/blog.published_at is null for drafts and query Post::published() (not Post::all()).Livewire Scripts Duplication:
@livewireScripts appears twice in admin views.'assets' => [] in config/blog.php if your layout already loads Livewire scripts.Livewire Errors:
wire:model bindings).php artisan livewire:discover
Markdown Parsing:
Str::markdown() behaves as expected. Example:
# Test
**Bold** and [links](https://example.com).
Route Conflicts:
php artisan route:list to verify no conflicts exist with your app’s routes.Custom Post Fields:
Post model by adding traits or relationships:
// app/Models/Post.php
use Jessecruz\SimpleBlog\Models\Post as BasePost;
class Post extends BasePost {
public function tags() {
return $this->morphToMany(Tag::class, 'taggable');
}
}
Override Markdown Processing:
Str::markdown() pipeline in config/blog.php:
'markdown' => [
'tables' => true, // Enable GitHub-style tables
'html' => false, // Escape HTML by default
],
$this->app->bind(\Jessecruz\SimpleBlog\Contracts\MarkdownRenderer::class, function () {
return new CustomMarkdownRenderer();
});
Custom Validation:
resources/views/vendor/blog/admin/post-form.blade.php.PostForm.Localization:
php artisan vendor:publish --tag="simple-blog-lang"
resources/lang/en/blog.php (or your locale).Sitemap Integration:
Post model to generate a sitemap:
$posts = Post::published()->latest('published_at')->get();
Sitemap::add($posts, function ($post) {
return route('blog.show', $post);
});
Post::with('category', 'author')->published()->get();
public properties for simple data and protected for complex logic.
How can I help you explore Laravel packages today?