The Filament content ops stack we hand over to marketing teams
Reusable panels, approval queues, and asset automation in under a sprint.
The Filament Content Ops Stack We Hand Over to Marketing Teams
Reusable panels, approval queues, and asset automation in under a sprint.
Handing over a new CMS to a marketing team can be a tense moment. As developers, we build powerful, flexible systems. But power and flexibility can translate to complexity and confusion for the non-technical users who will manage the content day-to-day. The ideal handoff is one where marketers feel empowered, not overwhelmed.
This is where Filament truly shines. We've refined a content operations stack built with Filament that not only meets complex business requirements but is also a joy for marketing teams to use. It’s a system designed for efficiency, clarity, and control, enabling us to deliver a complete, production-ready content management solution in under a single development sprint.
This guide will walk you through the exact components we use: reusable content panels, custom approval queues, and powerful asset automation. We’ll show you how to build a system that marketing teams will love, complete with code examples and visuals to guide you.
The Challenge: Bridging the Dev-Marketing Gap
Traditional content management systems often create a divide. Developers build rigid templates, and marketers are forced to work within those constraints. Need a new landing page layout? That’s a new development ticket. Want to A/B test a headline? That might require code changes.
This friction slows down marketing campaigns and pulls development resources away from core product features. We needed a solution that would give marketers the freedom to create and iterate, while developers maintain control over the system's architecture and integrity.
Our goal was to create a content ops stack that delivers:
- Modularity: Allowing marketers to build diverse page layouts from a library of pre-built, on-brand components.
- Governance: Implementing a clear approval process to ensure content quality and consistency before it goes live.
- Automation: Streamlining repetitive tasks like image optimization and metadata generation to save time.
Filament provides the tools to build this stack elegantly and efficiently. Let's dive into how we do it.
1. Reusable Panels with the Repeater and Builder Fields
The cornerstone of our content ops stack is the combination of Filament's Repeater and Builder form fields. This duo allows marketers to construct complex page layouts by adding, reordering, and customizing "blocks" of content without ever writing a line of code.
Think of it like playing with Lego bricks. We provide a box of approved, beautifully styled bricks (content blocks), and the marketing team can assemble them in countless ways to build exactly what they need.
For example, a typical landing page might be composed of a hero section, a features grid, a testimonial slider, and a call-to-action banner. Instead of a single, monolithic form, we create a Builder field that lets the user choose which blocks to add.
The Developer's Side: Building the Blocks
From a development perspective, setting this up is straightforward. First, you define a Builder field in your Filament resource. Each block within the builder is its own set of fields.
Here’s a simplified example of how we might define a content attribute on a Page model.
// In app/Filament/Resources/PageResource.php
use Filament\Forms\Components\Builder;
use Filament\Forms\Components\FileUpload;
use Filament\Forms\Components\Repeater;
use Filament\Forms\Components\Textarea;
use Filament\Forms\Components\TextInput;
// ... inside the form method
public static function form(Form $form): Form
{
return $form
->schema([
// ... other fields like title, slug
Builder::make('content')
->blocks([
Builder\Block::make('hero_section')
->schema([
TextInput::make('heading')->required(),
Textarea::make('subheading'),
FileUpload::make('background_image')->image(),
]),
Builder\Block::make('feature_list')
->schema([
TextInput::make('title')->default('Features'),
Repeater::make('features')
->schema([
TextInput::make('name')->required(),
Textarea::make('description'),
])
->columns(2),
]),
Builder\Block::make('call_to_action')
->schema([
TextInput::make('cta_text')->required(),
TextInput::make('button_url')->url()->required(),
]),
])
->columnSpanFull(),
]);
}In this code:
- The Builder field is named content. This will store all our page blocks as a JSON array in the database.
- We define three Block types: hero_section, feature_list, and call_to_action.
- Each block has its own schema of fields. Notice the feature_list block even contains a Repeater field, allowing marketers to add an unlimited number of features within that block.
This modular approach empowers marketers to create dynamic, unique layouts for campaigns, landing pages, and blog posts, all while staying within the design and brand guidelines you've established.
2. Approval Queues for Quality Control
Giving marketers creative freedom is great, but content governance is crucial for maintaining brand voice and quality. A simple "Draft" and "Published" status is often not enough. You need a workflow.
We implement a simple yet effective approval queue using a status field and Filament's table actions and filters. This creates a clear process where a content creator can submit work for review, and an editor can approve or reject it.
The Developer's Side: Implementing a Status Workflow
First, add a status column to your model's migration. We typically use a string or enum.
// In your migration file
$table->string('status')->default('draft');Next, in your Filament resource, define the selectable statuses and create tabs to filter the table view.
// In app/Filament/Resources/PostResource.php
use Filament\Resources\Components\Tab;
use Filament\Forms\Components\Select;
use Filament\Tables\Actions\Action;
// ... inside the form method
Select::make('status')
->options([
'draft' => 'Draft',
'in_review' => 'In Review',
'published' => 'Published',
'rejected' => 'Rejected',
])
->required(),
// ... inside the table method, add custom tabs
public function getTabs(): array
{
return [
'all' => Tab::make(),
'draft' => Tab::make()->query(fn ($query) => $query->where('status', 'draft')),
'in_review' => Tab::make()->query(fn ($query) => $query->where('status', 'in_review')),
'published' => Tab::make()->query(fn ($query) => $query->where('status', 'published')),
];
}The final piece is creating custom actions for the approval workflow. We can add "Submit for Review" and "Approve" buttons that only appear for records with the appropriate status.
// In app/Filament/Resources/PostResource.php -> table method
->actions([
Tables\Actions\EditAction::make(),
Action::make('submit_for_review')
->action(fn (Post $record) => $record->update(['status' => 'in_review']))
->requiresConfirmation()
->color('warning')
->icon('heroicon-o-arrow-up-on-square')
->visible(fn (Post $record) => $record->status === 'draft'),
Action::make('approve')
->action(fn (Post $record) => $record->update(['status' => 'published']))
->requiresConfirmation()
->color('success')
->icon('heroicon-o-check-circle')
->visible(fn (Post $record) => $record->status === 'in_review'),
])This setup provides a clear, actionable workflow directly within the Filament admin panel. Marketers know exactly what stage their content is in, and editors have a dedicated queue of items to review. You can further enhance this with user roles and permissions, ensuring only authorized editors can approve content.
3. Asset Automation to Eliminate Tedium
Marketing teams handle a lot of media. Images, videos, and documents all need to be uploaded, optimized, and tagged. Manually performing these tasks is time-consuming and prone to error. We use Laravel's event system, combined with packages like Spatie's laravel-medialibrary, to automate these processes.
Our automation stack typically handles:
- Image Optimization: Automatically compressing and resizing images on upload to ensure fast page loads.
- Alt Text Generation: Using AI services to suggest alt text for images, improving accessibility and SEO.
- Metadata Extraction: Pulling EXIF data from images or metadata from documents.
The Developer's Side: Using Observers for Automation
Laravel's model observers are perfect for triggering these automated tasks. When a model with an asset is created or updated, we can fire off jobs to handle the processing in the background.
Let's say we want to automatically generate a WebP version and set alt text for a Post model's featured image. We'll use spatie/laravel-medialibrary for this.
First, set up the media library on your model. Then, create an observer.
php artisan make:observer PostObserver --model=Post
Now, in the PostObserver, we can hook into the created and updated events.
// In app/Observers/PostObserver.php
namespace App\Observers;
use App\Models\Post;
use Spatie\Image\Image;
class PostObserver
{
public function saved(Post $post): void
{
if ($post->hasMedia('featured_image')) {
$mediaItem = $post->getFirstMedia('featured_image');
// Generate a WebP conversion
if (!$mediaItem->hasGeneratedConversion('webp')) {
$mediaItem->addGeneratedConversion('webp', fn (Image $image) => $image->format('webp'));
}
// If alt text is empty, generate it (pseudo-code)
if (empty($mediaItem->getCustomProperty('alt'))) {
//dispatch(new GenerateAltTextJob($mediaItem));
}
$mediaItem->save();
}
}
}This is a simplified example, but it demonstrates the power of this approach. By moving these tasks into background jobs triggered by observers, the user experience for marketers remains fast and fluid. They upload an image, and Filament takes care of the rest.
A Content Stack That Empowers Everyone
By combining reusable Builder blocks, a clear approval workflow, and automated asset handling, you can deliver a content operations stack that bridges the gap between development and marketing. Marketers gain the freedom to create and manage content efficiently, while developers maintain a robust, scalable, and maintainable system.
Filament provides the perfect foundation for this stack. Its flexibility and developer-friendly API make it possible to build these sophisticated features in a fraction of the time it would take with other tools. The result is a faster time-to-market, a happier marketing team, and more time for developers to focus on what they do best: building great products.
Related articles
Continue exploring Laravel insights and practical delivery strategies.
Streamline PHP Workflows: Composer Scripts vs. Makefile
Learn how to centralize code quality commands in your PHP projects. This guide compares Composer scripts and Makefiles with practical examples and best practices.
Florentin Pomirleanu
Principal Laravel Consultant
Build Scalable Apps with Laravel Microservices
A complete guide to designing, building, and scaling microservices in Laravel. Learn to handle communication, deployment, and monitoring for large applications.
Florentin Pomirleanu
Principal Laravel Consultant
Streamline Development with GitHub Workflows
Master GitHub with this guide to deployment pipelines, pull requests, and code reviews. Learn best practices for managing branches and CI/CD.
Florentin Pomirleanu
Principal Laravel Consultant
Laravel consulting
Need senior Laravel help for this topic?
Let's adapt these practices to your product and deliver the next milestone.