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
Agents
banulakwin/laravel-seo-engine
claude-code
cursor
seo
laravel
meta
open-graph
eloquent
polymorphic
twitter-card

Portable polymorphic SEO meta for Eloquent models.

Install
php artisan boost:add-skill banulakwin/laravel-seo-engine

Save this content to: AGENTS.md

# Agent guide: `banulakwin/laravel-seo-engine`

Portable polymorphic SEO meta for Eloquent models.

## Static pages (`seo_meta` + config)

### Keys and storage

- **`config('seo.static_page_model_type')`** (default `static_page`) is stored in **`seo_meta.model_type`**.
- **Page slug** (e.g. `home`, `privacy-policy`) is stored in **`seo_meta.model_id`** as a **string** (migration uses string columns).

### Adding SEO for a new static route

1. Add an entry under **`config('seo.pages')`** (or a PHP file required from `config/seo.php`):

```php
'promotions' => [
    'title' => 'Promotions',
    'description' => 'Limited-time offers.',
    // optional: image, keywords, is_index, is_follow, og_*, twitter_*
],
```

2. Run **`php artisan seo:sync`** once (or in deploy) to **`firstOrCreate`** missing rows — **never** overwrites existing DB content.
3. In controllers, pass SEO to Inertia using **`inertia_seo_page('promotions')`**, **`inertia_seo($model)`**, or **`app(SeoService::class)->forStaticPage('promotions')`** mapped to your head contract.

### Reading in PHP

- **`seoPage('home')`** → `?SeoMeta` for the static type + id.
- **`SeoService::forStaticPage('home')`** → stable array shape (DB row if present, else **virtual** array built only from `config('seo.pages')` + `defaults`).

## Dynamic models (`Seoable`)

Attach **`Seoable`** to Eloquent models; SEO row is created on **`created`**.

- **`seoKeywordsAttribute`** (`string|list<string>`) -> resolves meta keywords.
- **`seoCanonicalUrlAttribute`** (`string|list<string>`) -> resolves canonical URL.
- Automatic request URL discovery for canonicals is **removed** to prevent admin/Livewire URL leaks. Use the model attribute to define public URLs.

## Do not

- Use **`updateOrCreate`** in **`seo:sync`** (would overwrite user edits).
- Commit generated files (`vendor/`, `composer.lock`, `coverage/`).

## Testing & Quality

```bash
composer test          # PHPUnit
composer pint          # Laravel Pint code style fix
composer pint:check    # Pint check only (no fix)
composer phpstan       # PHPStan level max on src/
composer quality       # All: pint + phpstan + test
```

## CI

GitHub Actions runs tests, Pint, and PHPStan on push/PR (`.github/workflows/tests.yml`).

Agent guide: banulakwin/laravel-seo-engine

Portable polymorphic SEO meta for Eloquent models.

Static pages (seo_meta + config)

Keys and storage

  • config('seo.static_page_model_type') (default static_page) is stored in seo_meta.model_type.
  • Page slug (e.g. home, privacy-policy) is stored in seo_meta.model_id as a string (migration uses string columns).

Adding SEO for a new static route

  1. Add an entry under config('seo.pages') (or a PHP file required from config/seo.php):
'promotions' => [
    'title' => 'Promotions',
    'description' => 'Limited-time offers.',
    // optional: image, keywords, is_index, is_follow, og_*, twitter_*
],
  1. Run php artisan seo:sync once (or in deploy) to firstOrCreate missing rows — never overwrites existing DB content.
  2. In controllers, pass SEO to Inertia using inertia_seo_page('promotions'), inertia_seo($model), or app(SeoService::class)->forStaticPage('promotions') mapped to your head contract.

Reading in PHP

  • seoPage('home') → ?SeoMeta for the static type + id.
  • SeoService::forStaticPage('home') → stable array shape (DB row if present, else virtual array built only from config('seo.pages') + defaults).

Dynamic models (Seoable)

Attach Seoable to Eloquent models; SEO row is created on created.

  • seoKeywordsAttribute (string|list<string>) -> resolves meta keywords.
  • seoCanonicalUrlAttribute (string|list<string>) -> resolves canonical URL.
  • Automatic request URL discovery for canonicals is removed to prevent admin/Livewire URL leaks. Use the model attribute to define public URLs.

Do not

  • Use updateOrCreate in seo:sync (would overwrite user edits).
  • Commit generated files (vendor/, composer.lock, coverage/).

Testing & Quality

composer test          # PHPUnit
composer pint          # Laravel Pint code style fix
composer pint:check    # Pint check only (no fix)
composer phpstan       # PHPStan level max on src/
composer quality       # All: pint + phpstan + test

CI

GitHub Actions runs tests, Pint, and PHPStan on push/PR (.github/workflows/tests.yml).

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.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route