karnoweb / metapilot
Offline-first SEO intelligence for Laravel.
Requires
- php: ^8.2
- ext-dom: *
- ext-mbstring: *
- illuminate/console: ^12.0|^13.0
- illuminate/database: ^12.0|^13.0
- illuminate/queue: ^12.0|^13.0
- illuminate/support: ^12.0|^13.0
Requires (Dev)
- orchestra/testbench: ^10.0|^11.0
- phpunit/phpunit: ^10.5|^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
MetaPilot is an offline-first SEO intelligence engine for Laravel. It stores editable SEO metadata, builds normalized snapshots, and produces deterministic findings without a crawler, HTTP renderer, Redis, queue worker, or AI dependency.
Requirements: PHP 8.2+, Laravel 12–13, DOM and Mbstring extensions, and a Laravel-supported database. Laravel 13 itself requires PHP 8.3+. CI covers PHP 8.2–8.5 where each Laravel version permits it, SQLite, and MySQL 8.4; MariaDB 11.8 is also verified. Laravel 11 is not declared because its currently resolvable releases are blocked by Composer security advisories. Install the package with Composer and run migrations; publishing config is optional.
Five-minute quick start
use Illuminate\Database\Eloquent\Model; use Karnoweb\MetaPilot\Facades\Seo; use Karnoweb\MetaPilot\Traits\HasSeo; class Post extends Model { use HasSeo; public function seoHtml(): ?string { return $this->rendered_html; } public function seoUrl(): ?string { return route('posts.show', $this); } } $post = Post::query()->firstOrFail(); Seo::for($post)->upsertMeta([ 'title' => 'Laravel SEO Example', 'description' => 'A useful description for the page.', ]); Seo::for($post)->refreshSnapshot(); $report = Seo::for($post)->analyze(); $report->score(); $report->health(); $report->findings(); $report->recommendations();
Tenant and locale overrides are immutable-style:
Seo::for($post)->tenant('club-10')->locale('fa')->refreshSnapshot();
Batch and operational APIs:
Seo::batch()->rebuild(Post::query(), tenantId: 1, locale: 'fa'); Seo::batch()->analyze(Post::query(), tenantId: 1, locale: 'fa'); Seo::site()->analyze(tenantId: 1, locale: 'fa'); Seo::priority()->recalculate(tenantId: 1, locale: 'fa');
CLI commands:
php artisan metapilot:snapshots:rebuild "App\Models\Post" php artisan metapilot:analyze "App\Models\Post" --fresh --site
MetaPilot is snapshot-first: analyze() reads an existing snapshot and never renders or parses HTML. Use analyzeFresh() when an explicit rebuild is desired.
See the complete documentation. Run composer test for the default SQLite suite.