SEO - v1.0.0
Models
This page documents the Eloquent models provided by ArtisanPack UI SEO.
SeoMeta
The SeoMeta model stores SEO metadata for any Eloquent model using a polymorphic relationship.
Table Structure
Schema::create('seo_meta', function (Blueprint $table) {
$table->id();
$table->morphs('seoable');
// Basic meta
$table->string('meta_title')->nullable();
$table->text('meta_description')->nullable();
$table->string('canonical_url')->nullable();
// Robots
$table->boolean('noindex')->default(false);
$table->boolean('nofollow')->default(false);
// Open Graph
$table->string('og_title')->nullable();
$table->text('og_description')->nullable();
$table->string('og_image')->nullable();
$table->unsignedBigInteger('og_image_id')->nullable();
$table->string('og_type')->nullable();
$table->string('og_locale')->nullable();
$table->string('og_site_name')->nullable();
// Twitter
$table->string('twitter_card')->nullable();
$table->string('twitter_title')->nullable();
$table->text('twitter_description')->nullable();
$table->string('twitter_image')->nullable();
$table->unsignedBigInteger('twitter_image_id')->nullable();
$table->string('twitter_site')->nullable();
$table->string('twitter_creator')->nullable();
// Pinterest & Slack
$table->text('pinterest_description')->nullable();
$table->string('pinterest_image')->nullable();
$table->string('slack_title')->nullable();
$table->text('slack_description')->nullable();
// Schema
$table->string('schema_type')->nullable();
$table->json('schema_data')->nullable();
// Keywords
$table->string('focus_keyword')->nullable();
$table->json('secondary_keywords')->nullable();
// Hreflang
$table->json('hreflang')->nullable();
// Sitemap
$table->boolean('exclude_from_sitemap')->default(false);
$table->decimal('sitemap_priority', 2, 1)->default(0.5);
$table->string('sitemap_changefreq')->default('weekly');
$table->timestamps();
});
Properties
| Property | Type | Description |
|---|---|---|
meta_title |
string|null | Custom meta title |
meta_description |
string|null | Custom meta description |
canonical_url |
string|null | Custom canonical URL |
noindex |
bool | Prevent indexing |
nofollow |
bool | Prevent link following |
og_title |
string|null | Open Graph title |
og_description |
string|null | Open Graph description |
og_image |
string|null | Open Graph image URL |
og_image_id |
int|null | Media Library image ID |
og_type |
string|null | Open Graph type |
og_locale |
string|null | Open Graph locale |
og_site_name |
string|null | Open Graph site name |
twitter_card |
string|null | Twitter card type |
twitter_title |
string|null | Twitter title |
twitter_description |
string|null | Twitter description |
twitter_image |
string|null | Twitter image URL |
twitter_site |
string|null | Twitter @site handle |
twitter_creator |
string|null | Twitter @creator handle |
schema_type |
string|null | Schema.org type |
schema_data |
array|null | Custom schema data |
focus_keyword |
string|null | Primary keyword |
secondary_keywords |
array|null | Additional keywords |
hreflang |
array|null | Hreflang URLs |
sitemap_priority |
float | Sitemap priority (0.0-1.0) |
sitemap_changefreq |
string | Sitemap change frequency |
exclude_from_sitemap |
bool | Exclude from sitemap |
Relationships
// Polymorphic parent
public function seoable(): MorphTo
{
return $this->morphTo();
}
// Media Library integration (if installed)
public function ogImage(): BelongsTo
{
return $this->belongsTo(Media::class, 'og_image_id');
}
public function twitterImage(): BelongsTo
{
return $this->belongsTo(Media::class, 'twitter_image_id');
}
Casts
protected $casts = [
'noindex' => 'boolean',
'nofollow' => 'boolean',
'exclude_from_sitemap' => 'boolean',
'schema_data' => 'array',
'secondary_keywords' => 'array',
'hreflang' => 'array',
'sitemap_priority' => 'float',
];
Usage Examples
use ArtisanPackUI\Seo\Models\SeoMeta;
// Find by model
$meta = SeoMeta::where('seoable_type', Post::class)
->where('seoable_id', $post->id)
->first();
// Get all meta for a model type
$postMeta = SeoMeta::where('seoable_type', Post::class)->get();
// Check if model has meta
$hasMeta = SeoMeta::where('seoable_type', Post::class)
->where('seoable_id', $post->id)
->exists();
Redirect
The Redirect model stores URL redirect rules.
Table Structure
Schema::create('redirects', function (Blueprint $table) {
$table->id();
$table->string('source');
$table->string('target');
$table->enum('type', ['exact', 'regex', 'wildcard'])->default('exact');
$table->integer('status_code')->default(301);
$table->boolean('is_active')->default(true);
$table->unsignedBigInteger('hits')->default(0);
$table->timestamp('last_hit_at')->nullable();
$table->text('notes')->nullable();
$table->timestamps();
$table->index(['source', 'is_active']);
});
Properties
| Property | Type | Description |
|---|---|---|
source |
string | Source path/pattern |
target |
string | Destination URL |
type |
string | Match type (exact, regex, wildcard) |
status_code |
int | HTTP status (301, 302, 307, 308) |
is_active |
bool | Whether redirect is active |
hits |
int | Number of times triggered |
last_hit_at |
Carbon|null | Last triggered timestamp |
notes |
string|null | Documentation notes |
Scopes
// Active redirects only
Redirect::active()->get();
// Inactive redirects only
Redirect::inactive()->get();
// Permanent redirects (301, 308)
Redirect::permanent()->get();
// Temporary redirects (302, 307)
Redirect::temporary()->get();
// With hits
Redirect::withHits()->get();
// Most popular
Redirect::mostHits()->limit(10)->get();
// Recently hit
Redirect::recentlyHit()->get();
// By type
Redirect::byType('regex')->get();
Methods
$redirect = Redirect::find(1);
// Check if matches a path
$matches = $redirect->matches('/some/path');
// Get the redirect target for a path
$destination = $redirect->getDestination('/some/path');
// Increment hit counter
$redirect->recordHit();
// Toggle active status
$redirect->toggleActive();
Usage Examples
use ArtisanPackUI\Seo\Models\Redirect;
// Create a redirect
$redirect = Redirect::create([
'source' => '/old-page',
'target' => '/new-page',
'type' => 'exact',
'status_code' => 301,
]);
// Find matching redirect
$redirect = Redirect::active()
->get()
->first(fn ($r) => $r->matches($path));
SitemapEntry
The SitemapEntry model tracks sitemap entries.
Table Structure
Schema::create('sitemap_entries', function (Blueprint $table) {
$table->id();
$table->nullableMorphs('sitemapable');
$table->string('url');
$table->decimal('priority', 2, 1)->default(0.5);
$table->string('changefreq')->default('weekly');
$table->timestamp('lastmod')->nullable();
$table->json('images')->nullable();
$table->json('videos')->nullable();
$table->timestamps();
$table->unique('url');
});
Properties
| Property | Type | Description |
|---|---|---|
url |
string | Page URL |
priority |
float | Priority (0.0-1.0) |
changefreq |
string | Change frequency |
lastmod |
Carbon|null | Last modification |
images |
array|null | Image URLs for image sitemap |
videos |
array|null | Video data for video sitemap |
Relationships
// Polymorphic parent (optional)
public function sitemapable(): MorphTo
{
return $this->morphTo();
}
Scopes
// Entries with images
SitemapEntry::withImages()->get();
// Entries with videos
SitemapEntry::withVideos()->get();
// By priority
SitemapEntry::where('priority', '>=', 0.8)->get();
// Recently modified
SitemapEntry::where('lastmod', '>=', now()->subDays(7))->get();
SeoAnalysisCache
The SeoAnalysisCache model caches SEO analysis results.
Table Structure
Schema::create('seo_analysis_cache', function (Blueprint $table) {
$table->id();
$table->foreignId('seo_meta_id')->constrained('seo_meta')->cascadeOnDelete();
$table->json('results');
$table->integer('score');
$table->timestamps();
});
Properties
| Property | Type | Description |
|---|---|---|
seo_meta_id |
int | Related SeoMeta ID |
results |
array | Analysis results |
score |
int | Overall SEO score |
Relationships
public function seoMeta(): BelongsTo
{
return $this->belongsTo(SeoMeta::class);
}
Next Steps
- Services - Service documentation
- Helper Functions - Helper reference
- Model Integration - HasSeo trait