Sage View Composers: Keeping Your Blade Templates Presentation-Pure
You’ve likely felt the frustration of building WordPress themes that quickly devolve into an unmaintainable tangle. The traditional WordPress loop, sprinkled with `get_posts` calls or even custom queries directly within your `index.php` or `page.php` files, quickly makes templates difficult to read, reuse, and debug. This is precisely the kind of programmatic chaos that Sage, built on top of Laravel's excellent componentry like Blade and Acorn, seeks to eliminate. We developers choose Sage because it brings an MVC-like structure to WordPress, letting us create clean, presentation-focused templates completely divorced from data retrieval logic.
Today, I want to dive into a specific technique that embodies this philosophy: View Composers. If you've ever found yourself asking, "How do I get complex data into my Blade templates without cluttering them up?", then View Composers are your answer. They provide a powerful, centralized way to bind data to views, ensuring your Blade files remain purely responsible for displaying information, not fetching it. This is a stark contrast to the database bloat and code spaghetti often found in themes built with drag-and-drop page builders like Divi or Elementor, which, while offering quick visual builds, often sacrifice long-term maintainability and developer sanity.
Let's consider a common scenario: you have a custom post type, say "Projects," and you want to display a list of these projects on your home page, perhaps filtered by a custom taxonomy or other criteria. The "old" way, even with Blade, might involve something like this directly in `resources/views/partials/projects-list.blade.php`:
@php $args = ['post_type' => 'project', 'posts_per_page' => 3]; $projects = get_posts($args); @endphp
@if (!empty($projects)) <section class="projects"> <h2>Latest Projects</h2> @foreach ($projects as $project) <article> <h3>{{ $project->post_title }}</h3> <p>{{ $project->post_excerpt }}</p> <a href="{{ get_permalink($project->ID) }}">View Project</a> </article> @endforeach </section> @endif
While this works, it pollutes your Blade template with data fetching logic. The template is no longer just about presentation; it's also about *how* to get the project data. This makes the `projects-list.blade.php` less reusable and harder to test.
This is where View Composers shine. We can extract that data fetching logic into a dedicated class and *compose* it into our view when needed. First, let's create a new class, say `app/View/Composers/ProjectsComposer.php`:
namespace App\View\Composers;
use Roots\Acorn\View\Composer;
class ProjectsComposer extends Composer { /** * List of views served by this composer. * @var array */ protected static $views = [ 'partials.projects-list', 'front-page', // Or any other view that needs this data ];
/** * Data to be passed to view before rendering. * @param array $data * @return array */ public function with() { $args = [ 'post_type' => 'project', 'posts_per_page' => 3, 'orderby' => 'date', 'order' => 'DESC', ];
return [ 'projects' => get_posts($args), ]; } }
Now, instead of manually instantiating this composer, we register it with Acorn. The simplest way is to add it to your `config/view.php` file under the `composers` array, or for a more structured approach, within a service provider. Let’s stick to the `setup.php` for quick setup for this example, although a dedicated service provider offers more robust organization for complex applications. In `app/setup.php`, within the `add_filters()` function or directly after it:
add_action('after_setup_theme', function () { // Other theme setup... Roots\view()->composer(['partials.projects-list', 'front-page'], \App\View\Composers\ProjectsComposer::class); });
With this in place, your `resources/views/partials/projects-list.blade.php` becomes wonderfully simple and purely presentational:
@if (!empty($projects)) <section class="projects"> <h2>Latest Projects</h2> @foreach ($projects as $project) <article> <h3>{{ $project->post_title }}</h3> <p>{{ $project->post_excerpt }}</p> <a href="{{ get_permalink($project->ID) }}">View Project</a> </article> @endforeach </section> @endif
Notice how the `$projects` variable is simply *available* in the template. The template doesn't care *how* `$projects` got there; it just knows it needs to display them. This drastically improves readability, makes testing the data fetching logic (`ProjectsComposer`) separate from the presentation, and enhances the reusability of your Blade templates.
This technique is a cornerstone of building robust, maintainable Sage themes. By consistently separating data retrieval from presentation using View Composers and Blade, you're not just writing code; you're crafting an organized, programmatic codebase that scales, adapts, and remains a joy to work with, rather than a constant source of frustration and refactoring. Embrace the Sage way, and free your templates from data-fetching burdens!