If you’ve spent any time battling WordPress theme development, you know the struggle: templates crammed with query_posts, get_field, and all sorts of data retrieval logic, making them a tangled mess. It’s hard to read, harder to debug, and practically impossible to maintain. This is precisely the kind of chaos that led me to Sage, and why I believe it’s the definitive choice for any developer serious about a clean, programmatic WordPress codebase. Forget the drag-and-drop page builder bloat; Sage gives you an MVC-like architecture that promotes sane development.
One of Sage’s most powerful features for keeping your Blade templates purely presentational is the View Composer. Think of a View Composer as a traffic controller for your data. Instead of pulling data directly in your single.blade.php or page.blade.php, you register a Composer that knows exactly what data a specific view (or set of views) needs, fetches it, processes it, and then passes it along. Your Blade template can then just focus on displaying that data beautifully, without a single WP_Query in sight.
Let me walk you through a concrete example: imagine you have a custom post type called ‘project’ and you want to display a dynamic list of these projects in a reusable partial, perhaps on your homepage, an archive page, or even a sidebar.
First, we need to create our View Composer. I typically put these in app/View/Composers. Let’s create app/View/Composers/ProjectComposer.php:
namespace App\View\Composers;
use Roots\Acorn\View\Composer;
use WP_Query;
class ProjectComposer extends Composer
{
/**
* List of views served by this composer.
*
* @var array
*/
protected static $views = [
'partials.project-list',
'template-home', // If you want to use it directly in a template
];
/**
* Data to be passed to view before rendering.
*
* @return array
*/
public function with()
{
$args = [
'post_type' => 'project',
'posts_per_page' => 4,
'order' => 'DESC',
'orderby' => 'date',
];
$projects_query = new WP_Query($args);
$projects = $projects_query->posts;
return [
'projects' => $projects,
];
}
}
In this ProjectComposer, we define which views it will serve using the $views property. Here, it’s partials.project-list – indicating that any time this partial is rendered, our composer will run. The with() method is where the magic happens: we fetch our four most recent projects using WP_Query and then return an associative array. The key 'projects' is how this data will be available in our Blade template.
Next, our Blade template, resources/views/partials/project-list.blade.php, becomes incredibly simple and clean:
<section class="project-list">
<h2>Our Latest Projects</h2>
@if ($projects)
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
@foreach ($projects as $project)
<article class="project-card">
<h3><a href="{{ get_permalink($project->ID) }}">{{ get_the_title($project->ID) }}</a></h3>
<p>{{ get_the_excerpt($project->ID) }}</p>
</article>
@endforeach
@else
<p>No projects to display yet.</p>
@endif
</section>
Notice how there’s no new WP_Query() or get_posts() here. The $projects variable is simply there, ready to be iterated over. It’s pure presentation.
To ensure our Composer is registered and Acorn knows about it, we declare it within a Service Provider. The app/Providers/ThemeServiceProvider.php is often a good place for this. Inside your ThemeServiceProvider class, add your composer to the $viewComposers array like so:
class ThemeServiceProvider extends ServiceProvider
{
// ... other properties
protected $viewComposers = [
ProjectComposer::class,
];
// ... other methods
}
And that’s it! Now, anywhere you include partials.project-list (e.g., @include('partials.project-list') in your homepage template), the ProjectComposer will automatically run, fetch the latest projects, and make them available as $projects in that partial.
This approach dramatically cleans up your WordPress development. Your templates become dumb displays, your data logic lives in organized, testable classes, and you move away from the unmaintainable mess that often plagues standard WordPress themes or, worse, the unreadable database entries of page builders like Divi or Elementor. Sage, with Acorn and Blade, truly empowers developers to build sophisticated, maintainable WordPress sites that scale.