← All posts

No More Messy Queries in Blade: Sage View Composers to the Rescue

No More Messy Queries in Blade: Sage View Composers to the Rescue

One of the reasons I champion Sage for WordPress development is its unwavering commitment to clean architecture. While other themes descend into a chaotic blend of database operations and presentation logic, or worse, become bloated page builder monstrosities like Divi or Elementor that lock you into unmaintainable UIs, Sage keeps things sharp and organized. It embraces an MVC-like pattern, ensuring your templates are purely for presentation, your data is handled cleanly, and your dependencies are managed with modern tools like Acorn. Today, I want to walk through a simple yet powerful technique that embodies this philosophy: using Sage View Composers to deliver data to your Blade templates.

Imagine you're building a homepage that needs to display a list of "Featured Products" from a custom post type. In a traditional WordPress theme, you might drop a `WP_Query` directly into your `front-page.php` or even a partial, fetch the data, and then loop through it right there. This works, but it clutters your presentation layer with data fetching logic, making the template harder to read, harder to test, and less reusable. It's exactly the kind of tight coupling Sage aims to avoid.

This is where View Composers shine. A View Composer acts as a middleman, preparing data that specific Blade views will need, completely separate from the view itself. It's like having a dedicated chef preparing all the ingredients *before* they even hit the display plate.

Let's create a `FeaturedProductsComposer` to handle our scenario. First, create a new file at `app/View/Composers/FeaturedProductsComposer.php`:

<?php

namespace App\View\Composers;

use Roots\Acorn\View\Composer;

class FeaturedProductsComposer extends Composer { /** * List of views served by this composer. * * @var array */ protected static $views = [ 'partials.featured-products', ];

/** * Data to be passed to view before rendering. * * @return array */ public function with() { $args = [ 'post_type' => 'product', 'posts_per_page' => 3, 'meta_key' => 'is_featured', 'meta_value' => '1', 'post_status' => 'publish', ];

$query = new \WP_Query($args);

$products = []; if ($query->have_posts()) { while ($query->have_posts()) { $query->the_post(); $products[] = (object) [ 'id' => get_the_ID(), 'title' => get_the_title(), 'link' => get_permalink(), 'image' => get_the_post_thumbnail_url(get_the_ID(), 'medium'), ]; } wp_reset_postdata(); }

return [ 'featuredProducts' => $products, ]; } }

In this Composer, we define `$views` as `partials.featured-products`. This tells Sage that this Composer should run whenever the `partials.featured-products` Blade template is about to be rendered. Inside the `with()` method, we perform our `WP_Query`, fetch the desired "Product" posts marked as featured, process them into a clean array of objects containing just the data our template needs (ID, title, link, image), and then return this data. Notice we call `wp_reset_postdata()` to clean up after our custom query, which is crucial for WordPress integrity.

Now, our `resources/views/partials/featured-products.blade.php` template becomes incredibly simple and focused purely on displaying data:

<section class="featured-products"> <h2>Our Featured Products</h2> @if (!empty($featuredProducts)) <div class="product-grid"> @foreach ($featuredProducts as $product) <div class="product-card"> <a href="{{ $product->link }}"> @if ($product->image) <img src="{{ $product->image }}" alt="{{ $product->title }}"> @endif <h3>{{ $product->title }}</h3> </a> </div> @endforeach </div> @else <p>No featured products available at the moment.</p> @endif </section>

To include this partial on your homepage, simply use `@include('partials.featured-products')` in your `resources/views/front-page.blade.php`. Because the Composer is automatically discovered by Acorn and assigned to the specified view, the `$featuredProducts` variable will be available to the `partials.featured-products` template without any further effort on your part.

This approach offers tremendous benefits. Your Blade templates remain lightweight and readable, free from the noise of database queries. Data fetching logic is encapsulated and reusable within its Composer. This separation of concerns makes your codebase more maintainable, easier to debug, and inherently more testable, aligning perfectly with Sage's vision for a modern, programmatic WordPress development experience. Embrace View Composers, and watch your Sage themes become even cleaner and more robust.