Detalles del ejemplo
Filament Contact Form
Formulario de contacto con gestión completa en Filament y componente Livewire para frontend con 3 variantes de estilos, honeypot, rate limiting y mapa Leaflet opcional.
Instalación
composer require cursosdesarrolloweb/filament-contact-form
Configuración
1. Registrar el plugin en tu panel
use CursosDesarrolloWeb\ContactForm\ContactFormPlugin;
public function panel(Panel $panel): Panel
{
return $panel
// ...
->plugins([
ContactFormPlugin::make(),
]);
}
2. Publicar y ejecutar migraciones
php artisan vendor:publish --tag=filament-contact-form-migrations
php artisan migrate
Publicar recursos opcionales
Configuración
php artisan vendor:publish --tag=filament-contact-form-config
Traducciones
php artisan vendor:publish --tag=filament-contact-form-translations
Los archivos se publican en lang/vendor/filament-contact-form/.
Vistas
php artisan vendor:publish --tag=filament-contact-form-views
Uso en Frontend
El paquete incluye un componente Livewire con 3 variantes de estilos:
{{-- Sin estilos (clases CSS personalizables) --}}
<livewire:contact-form />
{{-- Con Tailwind CSS --}}
<livewire:contact-form theme="tailwind" />
{{-- Con Bootstrap 5 --}}
<livewire:contact-form theme="bootstrap" />
Con Mapa Leaflet
Si configuras coordenadas en el archivo de configuración, puedes mostrar un mapa:
<livewire:contact-form theme="tailwind" show-map />
Importante: Para que el mapa funcione, tu layout debe incluir @stack('scripts') antes de cerrar </body>:
<body>
{{ $slot }}
@stack('scripts')
</body>
Usando la variante Tailwind
La variante Tailwind usa clases estándar de Tailwind CSS. Para que los estilos se compilen correctamente, debes añadir las vistas del paquete al source de Tailwind.
En Tailwind v4 (CSS), añade en tu archivo CSS principal:
@source '../../vendor/cursosdesarrolloweb/filament-contact-form/resources/views/**/*.blade.php';
En Tailwind v3 (tailwind.config.js), añade al array content:
content: [
// ...
'./vendor/cursosdesarrolloweb/filament-contact-form/resources/views/**/*.blade.php',
]
Después ejecuta npm run build para recompilar los estilos.
Funcionalidades del Backoffice
- Listado de mensajes: Ver todos los mensajes con filtros por estado
- Ver mensaje: Detalle completo del mensaje (marca automáticamente como leído)
- Responder: Acción para responder directamente por email
- Estados: Nuevo (rojo), Leído (amarillo), Respondido (verde)
Personalización
Modelo personalizado
Publica la configuración y modifica el modelo:
// config/filament-contact-form.php
return [
'model' => \App\Models\ContactMessage::class,
];
Tu modelo debe extender el modelo del paquete:
use CursosDesarrolloWeb\ContactForm\Models\ContactMessage as BaseContactMessage;
class ContactMessage extends BaseContactMessage
{
// Tus personalizaciones
}
Notificación de respuesta personalizada
Por defecto, el paquete envía un email con formato Laravel estándar al responder un mensaje. Puedes crear tu propia notificación:
// config/filament-contact-form.php
return [
'reply' => [
'notification' => \App\Notifications\MyCustomReplyNotification::class,
],
];
Tu notificación debe aceptar los mismos parámetros en el constructor:
use CursosDesarrolloWeb\ContactForm\Models\ContactMessage;
use Illuminate\Notifications\Notification;
class MyCustomReplyNotification extends Notification
{
public function __construct(
public ContactMessage $contactMessage,
public string $replyMessage,
) {}
public function via(object $notifiable): array
{
return ['mail'];
}
public function toMail(object $notifiable): MailMessage
{
return (new MailMessage)
->subject('Re: ' . $this->contactMessage->subject)
->view('emails.contact-reply', [
'contactMessage' => $this->contactMessage,
'replyMessage' => $this->replyMessage,
]);
}
}
Grupo de navegación
Por defecto, el recurso aparece en el grupo "Contenido". Puedes cambiarlo en la configuración:
// config/filament-contact-form.php
return [
'navigation' => [
'group' => 'Mi Grupo', // null para sin grupo
'sort' => 20,
],
];
Evento
El paquete dispara un evento ContactFormSubmitted cuando se envía un mensaje. Puedes escucharlo para enviar notificaciones al administrador:
use CursosDesarrolloWeb\ContactForm\Events\ContactFormSubmitted;
class SendContactNotification
{
public function handle(ContactFormSubmitted $event): void
{
$message = $event->contactMessage;
// Enviar email, notificación de Slack, etc.
}
}
Scopes disponibles
El modelo ContactMessage incluye los siguientes scopes:
| Scope | Descripción |
|---|---|
new() |
Solo mensajes nuevos |
read() |
Solo mensajes leídos |
replied() |
Solo mensajes respondidos |
unread() |
Mensajes nuevos y leídos (sin responder) |
use CursosDesarrolloWeb\ContactForm\Models\ContactMessage;
// Obtener mensajes sin responder
$pending = ContactMessage::unread()->get();
// Contar mensajes nuevos
$newCount = ContactMessage::new()->count();
Métodos del modelo
| Método | Descripción |
|---|---|
markAsRead() |
Marca el mensaje como leído |
markAsReplied($message) |
Marca como respondido con el mensaje de respuesta |
isNew() |
Devuelve true si el estado es "new" |
isRead() |
Devuelve true si el estado es "read" |
isReplied() |
Devuelve true si el estado es "replied" |
Personalización de estilos
La variante sin estilos usa clases CSS que puedes personalizar:
| Clase | Elemento |
|---|---|
.contact-form |
Contenedor principal |
.contact-form-field |
Contenedor de cada campo |
.contact-form-label |
Etiquetas |
.contact-form-input |
Campos de texto |
.contact-form-textarea |
Área de mensaje |
.contact-form-button |
Botón de envío |
.contact-form-error |
Mensajes de error |
.contact-form-success |
Mensaje de éxito |
Configuración completa
// config/filament-contact-form.php
return [
// Navegación en Filament
'navigation' => [
'group' => 'Content',
'sort' => 20,
],
// Modelo personalizado
'model' => \CursosDesarrolloWeb\ContactForm\Models\ContactMessage::class,
// Tabla de base de datos
'table' => 'contact_messages',
// Rate limiting
'rate_limit' => [
'enabled' => true,
'max_attempts' => 5,
'decay_minutes' => 60,
],
// Honeypot anti-spam
'honeypot' => [
'enabled' => true,
'field_name' => 'website',
],
// Mapa Leaflet (opcional)
'map' => [
'latitude' => null, // ej: 40.4168
'longitude' => null, // ej: -3.7038
'zoom' => 15,
],
// Email de respuesta
'reply' => [
'from_name' => null, // Si null, usa config('mail.from.name')
'from_email' => null, // Si null, usa config('mail.from.address')
'notification' => \CursosDesarrolloWeb\ContactForm\Notifications\ContactReplyNotification::class,
],
];
Estructura de la base de datos
Tabla contact_messages
| Campo | Tipo | Descripción |
|---|---|---|
id |
bigint | Primary key |
name |
string | Nombre del remitente |
email |
string | Email del remitente |
phone |
string | Teléfono (opcional) |
subject |
string | Asunto del mensaje |
message |
text | Contenido del mensaje |
status |
enum | new, read, replied |
ip_address |
string | IP del remitente |
user_agent |
string | User agent del navegador |
replied_at |
timestamp | Fecha de respuesta |
replied_message |
text | Mensaje de respuesta |
timestamps |
created_at, updated_at |
Requisitos
- PHP 8.2+
- Laravel 11+
- Filament 4.x|5.x
- Livewire 3.x|4.x
Licencia
Propietario - Solo para suscriptores de CursosDesarrolloWeb.