vasilgerginski/filament-landing-pages
Installation:
composer require vasilgerginski/filament-landing-pages
php artisan filament-landing-pages:install
php artisan migrate
Verify the plugin is registered in your PanelServiceProvider:
->plugin(FilamentLandingPagesPlugin::make())
First Use Case:
publish-to-web).Key Files to Explore:
/resources/views/vendor/filament-landing-pages/ (custom block templates)/config/filament-landing-pages.php (global settings like default blocks)/database/migrations/ (lead/landing page schema)Drag-and-Drop Reordering:
Use the "Reorder" button in the page editor to visually rearrange blocks (e.g., move Testimonials above FAQ).
Tip: Hold Shift to multi-select blocks for batch reordering.
Block Customization: Each block (e.g., Hero Section) has a dedicated tab in the editor. Override default behavior by publishing the block’s view:
php artisan vendor:publish --tag=filament-landing-pages-blocks
Then extend the template in resources/views/vendor/filament-landing-pages/blocks/hero.blade.php.
Conditional Logic:
Use the shouldRender() method in custom blocks (extend FilamentLandingPages\Contracts\Block):
public function shouldRender(): bool {
return auth()->check() || config('filament-landing-pages.public_preview');
}
Form Submission Handling: Extend the default lead capture form by publishing the form view:
php artisan vendor:publish --tag=filament-landing-pages-forms
Add custom fields in resources/views/vendor/filament-landing-pages/forms/lead-capture.blade.php:
<x-filament-forms::input name="company" label="Company Name" />
Webhook Triggers:
Listen for lead events in your EventServiceProvider:
public function boot(): void {
LeadCreated::listen(function (Lead $lead) {
// Send Slack notification or update CRM
event(new LeadSubmitted($lead));
});
}
Reusing Templates: Clone a template via the "Duplicate" action in the landing page list. Modify the clone to create a new variation (e.g., Event Page – Dark Theme).
Template Inheritance: Create a base template with shared blocks (e.g., Footer), then extend it for specific pages:
// In a custom block provider
public function getTemplates(): array {
return [
'base' => [
'blocks' => ['footer', 'newsletter-signup'],
],
'event' => [
'extends' => 'base',
'blocks' => ['event-hero', 'speakers'],
],
];
}
Dynamic Metadata:
Override the SEO tab in the page editor by extending the SeoManager:
use VasilGerginski\FilamentLandingPages\Contracts\SeoManager;
class CustomSeoManager implements SeoManager {
public function getMetaTags(LandingPage $page): array {
return [
'og:title' => "Special Offer: {$page->title}",
...parent::getMetaTags($page),
];
}
}
Register it in config/filament-landing-pages.php:
'seo_manager' => \App\Services\CustomSeoManager::class,
UTM Tracking:
Append UTM parameters to CTAs automatically by configuring the utm_builder in the config:
'utm_builder' => function (LandingPage $page) {
return [
'utm_source' => 'filament-landing-pages',
'utm_medium' => $page->template->slug,
'utm_campaign' => 'q4-promotion',
];
},
// In config/filament-landing-pages.php
'public_preview' => env('APP_ENV') === 'local',
route('filament-landing-pages.preview', [
'page' => $landingPage->slug,
'token' => $landingPage->previewToken,
]);
Block Caching Issues:
php artisan view:clear
FilamentLandingPages\Contracts\Block and is registered in the service provider.Lead Duplicate Submissions:
deduplicate_leads config option to prevent duplicate entries:
'leads' => [
'deduplicate_by' => ['email', 'phone'], // Fields to check for duplicates
],
LeadValidator:
public function rules(): array {
return [
'email' => ['required', Rule::unique('leads')->ignore($this->lead)],
'custom_field' => ['required', function ($attribute, $value, $fail) {
if (Lead::where('custom_field', $value)->exists()) {
$fail('This value already exists.');
}
}],
];
}
Template Inheritance Conflicts:
extends key in your template definition points to a valid base template. Use:
php artisan filament-landing-pages:list-templates
to debug available templates.Livewire Component Conflicts:
php artisan filament:discover --force
Log Block Rendering:
Add debug output to your custom block’s render() method:
public function render(): string {
\Log::debug('Rendering block', ['data' => $this->data]);
return view('filament-landing-pages::blocks.hero', $this->data);
}
Inspect Lead Data: Use Tinker to verify lead storage:
php artisan tinker
>>> \App\Models\Lead::first()->toArray();
Check Published Assets: After publishing views, verify files exist in:
resources/views/vendor/filament-landing-pages/
Custom Block Types:
Create a new block by extending FilamentLandingPages\Blocks\Block:
namespace App\FilamentLandingPages\Blocks;
use VasilGerginski\FilamentLandingPages\Blocks\Block;
class CustomBlock extends Block {
protected static string $view = 'filament-landing-pages::blocks.custom';
public static function getSchema(): array {
return [
TextInput::make('title')->required(),
// Add custom fields
];
}
}
Register it in FilamentLandingPagesServiceProvider:
public function registerBlocks(): void {
$this->app->bind(
\VasilGerginski\FilamentLandingPages\Contracts\Block::class,
\App\FilamentLandingPages\Blocks\CustomBlock::class
);
}
Override Lead Model:
Extend the default Lead model to add custom fields:
namespace App\Models;
use VasilGerginski\FilamentLandingPages\Models\Lead as BaseLead;
class Lead extends BaseLead {
protected $casts = [
...BaseLead::$casts,
'custom_field' => 'string',
];
}
Update the config to use your model:
'lead_model' => \App\Models\Lead::class,
Hook into Page Events:
Listen for page-related events (e.g., PagePublished):
use VasilGerginski\FilamentLandingPages\Events\PagePublished;
PagePublished::listen(function (PagePublished $event)
How can I help you explore Laravel packages today?