miran/mksine
MKSine is a Laravel + Filament CMS foundation for content sites: a drag-and-drop page builder, installable plugins with lifecycle management, themes, menus, hooks, and settings. It feels native to Filament, so you skip hand-rolling pages, blocks, and plugins.
MKSine assumes you already have a running Laravel app with Filament installed — it is a CMS layer, not a standalone app. Before touching the package, confirm:
composer.json. Filament is a hard dependency, not optional.php artisan storage:link executed if you plan to use the media library.Minimal install flow (verify exact tags/commands against the Quick Install section and docs/ — they are the source of truth for the current release):
composer require miran/mksine
php artisan mksine:install # or vendor:publish + migrate, per docs
php artisan migrate
php artisan mksine:super-admin # create the first admin, or seed one
If an mksine:install command isn't available in your version, the manual path is the usual Laravel package triad:
php artisan vendor:publish --tag=mksine-config
php artisan vendor:publish --tag=mksine-migrations
php artisan vendor:publish --tag=mksine-assets
php artisan migrate
Where to look first, in order:
config/mksine.php — this is where page builder blocks, plugin paths, theme paths, media disk, and hook registration are (usually) declared. Read it end-to-end before writing code; most "why isn't my block showing up?" issues are answered here.docs/ in the repo — the README points at it explicitly and it covers page builder, plugins, themes, hooks, menus, media, settings, and translations separately. Read the page builder and plugins docs first; they define the contract everything else hangs off./admin — this is your debugging surface. Block registry issues, plugin enable/disable state, menu locations, and settings groups are visible there.First meaningful use case: log into /admin, create a Page, drag in two or three core blocks (heading, rich text, image), save, and confirm it renders on the frontend route the package exposes (or via the page model's render method if you're wiring it into your own controller). Once that loop works end-to-end, you understand the core data model and can start extending it with a custom block.
Custom blocks are the primary extension point. Daily work in MKSine is mostly authoring blocks. The pattern is: extend the package's base block class, define the editor UI with Filament form components (TextInput, RichEditor, FileUpload, Repeater, etc.), register a Blade view for frontend output, and add the class to the block registry in config/mksine.php. Treat block data as JSON — design schemas with null-safety and defaults because stored pages will outlive your schema changes.
Plugins for anything cross-cutting. A plugin is the right home for functionality that spans multiple pages, adds a Filament resource, or needs an install/enable lifecycle. Scaffold it with the plugin command if provided, keep its service provider lean, and let it register hooks, routes, and panel components. The lifecycle (install / enable / disable / uninstall) is meant to be respected — don't bypass it by registering plugin service providers manually in config/app.php.
Hooks for surgical modification. The hook system is the non-forking extension path: attach actions before/after render, filters around rendered output, and callbacks on save. Register hooks from a dedicated service provider (App\Providers\MKSineServiceProvider is a reasonable convention) rather than inline in AppServiceProvider, and keep hook callbacks small — they tend to grow into mini-plugins.
Menus and settings as data, not code. Build menus through the admin (or programmatically for seeded ones) and render them via the package's menu helper/renderer instead of hardcoding navigation into Blade. Same for settings: read via the settings helper and group them into logical scopes (site, seo, integrations) so the admin UI stays navigable. Cache reads if the settings table is hit on every request.
Media library as the single source of uploads. Route all content images/files through the media model rather than raw FileUpload fields on your own tables — you get URL generation, responsive variants, and consistent disk config for free. Reference media by ID in block JSON, not by hardcoded path, so storage migrations don't break pages.
Themes = view overrides plus a manifest. A theme should override Blade views and package assets without touching vendor code. Follow the parent/child pattern the docs describe so package updates don't clobber your customizations.
Translations: edit through the admin panel for content editors, and use the package's translation helper (or standard __()) in your blocks and views so strings flow through the same pipeline. Don't mix hand-edited lang/ files with DB-managed translations for the same key.
composer.json uses loose constraints. Pin filament/filament explicitly and re-read the changelog before composer update.php artisan optimize:clear. Block and plugin discovery typically read from config or the registry at boot — stale cache looks exactly like "the feature is broken."vendor:publish --tag=mksine-migrations, delete or rename the duplicate before migrate or you'll get "table already exists." Prefer the install command where available.hero_v2) or add defensive ?? default access in the Blade view. Silent blank blocks in production are almost always this.MKSINE_MEDIA_DISK (or the config equivalent) early. If uploads succeed but URLs 403, it's almost always storage:link missing or a disk not marked public in filesystems.php.php artisan about (confirms package discovery), check the Super Admin console for plugin state, php artisan optimize:clear, then storage/logs/laravel.log with APP_DEBUG=true. Filament's own filament:optimize-clear is worth running alongside if styles/assets look stale after a theme change.config/mksine.php, the plugin manifest/lifecycle API, the hooks service (action + filter), theme view overrides, and custom Filament pages/resources you can add to the panel directly. If a need isn't covered by these five, that's the moment to consider contributing upstream rather than patching vendor — the package is young (106 stars, zero dependents), so upstream fixes are cheap to get merged and cheaper than maintaining a fork.How can I help you explore Laravel packages today?