Detalles del ejemplo
Filament SEO
Campos SEO reutilizables para Filament v4 con soporte para meta tags, Open Graph, Twitter Cards y preview de Google en tiempo real.
Instalación
composer require cursosdesarrolloweb/filament-seo
Configuración
1. Publicar y ejecutar migraciones
php artisan vendor:publish --tag=filament-seo-migrations
php artisan migrate
2. Añadir el trait a tus modelos
use CursosDesarrolloWeb\Seo\Concerns\HasSeoMeta;
class Post extends Model
{
use HasSeoMeta;
}
3. Añadir los campos SEO a tu Resource
use CursosDesarrolloWeb\Seo\Forms\Components\SeoFields;
public static function form(Schema $schema): Schema
{
return $schema->components([
TextInput::make('title')->required(),
RichEditor::make('content'),
// Añadir campos SEO
SeoFields::make()->getSection(),
]);
}
Publicar recursos opcionales
Configuración
php artisan vendor:publish --tag=filament-seo-config
Traducciones
php artisan vendor:publish --tag=filament-seo-translations
Vistas
php artisan vendor:publish --tag=filament-seo-views
Uso
Campos SEO básicos
use CursosDesarrolloWeb\Seo\Forms\Components\SeoFields;
// Todos los campos (Meta, Open Graph, Twitter, Preview)
SeoFields::make()->getSection(),
// Solo meta tags básicos
SeoFields::make()
->withoutOpenGraph()
->withoutTwitter()
->getSection(),
// Sin preview de Google
SeoFields::make()
->withoutPreview()
->getSection(),
// Límites de caracteres personalizados
SeoFields::make()
->seoTitleLimit(70)
->seoDescriptionLimit(180)
->getSection(),
Relación personalizada
Si tu modelo usa un nombre de relación diferente:
// En tu modelo
public function metaSeo(): MorphOne
{
return $this->morphOne(SeoMeta::class, 'seoable');
}
// En tu Resource
SeoFields::make('metaSeo')->getSection(),
Renderizar meta tags en el frontend
En tu layout o vista:
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
{{-- Con modelo que tiene HasSeoMeta --}}
<x-filament-seo::meta-tags :model="$post" />
</head>
O con valores manuales:
<x-filament-seo::meta-tags
title="Mi Página"
description="Descripción de la página"
image="https://ejemplo.com/imagen.jpg"
type="article"
/>
O combinando ambos (el modelo tiene prioridad):
<x-filament-seo::meta-tags
:model="$post"
title="Título por defecto"
description="Descripción por defecto"
/>
Características
Meta Tags Básicos
- Título SEO - Con contador de caracteres (recomendado: 60)
- Descripción SEO - Con contador de caracteres (recomendado: 160)
- URL Canónica - Para evitar contenido duplicado
- Indexable - Control noindex
- Follow - Control nofollow
Open Graph
- og:type - website, article, product, etc.
- og:title - Con fallback a título SEO
- og:description - Con fallback a descripción SEO
- og:image - Imagen para compartir
Twitter Cards
- twitter:card - summary, summary_large_image, etc.
- twitter:title - Con fallback a og:title
- twitter:description - Con fallback a og:description
- twitter:image - Con fallback a og:image
Google Preview
Vista previa en tiempo real de cómo aparecerá tu página en los resultados de búsqueda de Google.
Personalización
Configuración
// config/filament-seo.php
return [
// Nombre de la tabla
'table' => 'seo_metas',
// Modelo personalizado
'model' => \App\Models\SeoMeta::class,
// Límites de caracteres
'limits' => [
'meta_title' => 60,
'meta_description' => 160,
],
// Valores por defecto de Open Graph
'og_defaults' => [
'type' => 'website',
'site_name' => 'Mi Sitio',
],
// Valores por defecto de Twitter
'twitter_defaults' => [
'card' => 'summary_large_image',
'site' => '@miusuario',
'creator' => '@miusuario',
],
// Habilitar/deshabilitar secciones
'sections' => [
'meta' => true,
'open_graph' => true,
'twitter' => true,
'preview' => true,
],
];
Modelo personalizado
use CursosDesarrolloWeb\Seo\Models\SeoMeta as BaseSeoMeta;
class SeoMeta extends BaseSeoMeta
{
// Tus personalizaciones
}
API del Modelo SeoMeta
Métodos Helper
$seo = $post->seoMeta;
// Obtener título con fallbacks
$seo->getTitle('Fallback'); // meta_title → og_title → fallback
// Obtener descripción con fallbacks
$seo->getDescription('Fallback'); // meta_description → og_description → fallback
// Obtener atributo robots
$seo->robots; // "index, follow" o "noindex, nofollow"
// Fallbacks para Open Graph
$seo->getOgTitleWithFallback();
$seo->getOgDescriptionWithFallback();
// Fallbacks para Twitter (cascada completa)
$seo->getTwitterTitleWithFallback(); // twitter_title → og_title → meta_title
$seo->getTwitterDescriptionWithFallback(); // twitter_description → og_description → meta_description
$seo->getTwitterImageWithFallback(); // twitter_image → og_image
Estructura de la base de datos
Tabla seo_metas
| Campo | Tipo | Descripción |
|---|---|---|
id |
bigint | Primary key |
seoable_id |
bigint | ID del modelo relacionado |
seoable_type |
string | Clase del modelo relacionado |
meta_title |
string(200) | Título SEO |
meta_description |
text | Descripción SEO |
meta_canonical |
string(500) | URL canónica |
indexable |
boolean | Permitir indexación (default: true) |
follow |
boolean | Permitir seguir enlaces (default: true) |
og_title |
string(200) | Título Open Graph |
og_description |
text | Descripción Open Graph |
og_image |
string(500) | URL de imagen Open Graph |
og_type |
string(50) | Tipo de contenido (default: website) |
twitter_card |
string(50) | Tipo de tarjeta Twitter |
twitter_title |
string(200) | Título Twitter |
twitter_description |
text | Descripción Twitter |
twitter_image |
string(500) | URL de imagen Twitter |
timestamps |
created_at, updated_at |
Requisitos
- PHP 8.2+
- Laravel 11+
- Filament 4.x|5.x
Licencia
Propietario - Solo para suscriptores de CursosDesarrolloWeb.