Skip to main content
Beyond the Loop: Sage View Composers for Clean Data Presentation

Beyond the Loop: Sage View Composers for Clean Data Presentation

If you've ever wrestled with WordPress themes built using page builders like Divi or Elementor, you know the feeling.

If you’ve ever wrestled with WordPress themes built using page builders like Divi or Elementor, you know the feeling. The immediate gratification of drag-and-drop quickly devolves into a nightmare of database bloat, inscrutable shortcodes, and an absolute wall when you need to implement any custom, programmatic logic. For developers, this isn’t just inefficient; it’s a roadblock to maintainability, performance, and sanity. This is precisely why tools like Sage exist – to bring modern development practices and a clean architecture to the WordPress ecosystem, making it a joy to build robust, scalable sites.

Sage, built on top of the Roots ecosystem, fundamentally shifts how you approach WordPress theme development. It embraces an MVC-like pattern, leveraging Laravel’s Blade templating engine for your views, Acorn (a WordPress-centric adaptation of Laravel’s service container) for dependency injection, and a structured approach that prioritizes code over click-and-drag. The core idea is simple: keep your presentation utterly separate from your data fetching and application logic. Your Blade templates should only ever concern themselves with displaying data, not retrieving it. So, how do we get that data cleanly into our templates without resorting to new WP_Query() calls scattered throughout index.php? Enter View Composers.

View Composers are a powerful feature in Sage that allow you to inject data into your views before they are rendered. Think of them as middleware specifically for your templates. They let you encapsulate data retrieval and preparation logic in dedicated classes, ensuring your Blade files remain pure, readable, and focused solely on presentation. This isn’t just good practice; it’s transformative for building maintainable WordPress themes. Let’s walk through a concrete example: fetching and displaying related posts on a single post page without cluttering your template.

First, we define our View Composer. This class will live in app/View/Composers. Let’s call it RelatedPostsComposer.php:

namespace App\View\Composers;

use Roots\Acorn\View\Composer;
use WP_Query;

class RelatedPostsComposer extends Composer
{
    /**
     * List of views served by this composer.
     *
     * @var array
     */
    protected static $views = [
        'partials.content-single', // Or any other view where you want related posts
    ];

/**
     * Data to be passed to the view before rendering.
     *
     * @param  array  $data
     * @return array
     */
    public function with($data)
    {
        if (! is_single()) {
            return $data;
        }

global $post;
        $tags = wp_get_post_tags($post->ID);
        $tag_ids = [];

if ($tags) {
            foreach ($tags as $individual_tag) {
                $tag_ids[] = $individual_tag->term_id;
            }

$args = [
                'tag__in'          => $tag_ids,
                'post__not_in'     => [$post->ID],
                'posts_per_page'   => 3,
                'ignore_sticky_posts' => 1,
                'orderby'          => 'rand',
            ];

$related_posts_query = new WP_Query($args);

return array_merge($data, [
                'related_posts' => $related_posts_query,
            ]);
        }

return $data;
    }
}

In this composer, we tell Sage which views it applies to via the $views property – in this case, partials.content-single, which is a common partial for displaying single post content. The with method is where our data magic happens. We check if we’re on a single post, grab its tags, then construct a WP_Query to fetch related posts. Crucially, we merge our related_posts_query into the $data array that will be passed to the view. This ensures our template receives a WP_Query object ready for display.

Now, our Blade partial can consume this data without any heavy lifting. Imagine a resources/views/partials/related-posts.blade.php file:

@if ($related_posts->have_posts())
  <section class="related-posts">
    <h3>Related Articles</h3>
    <ul>
      @while ($related_posts->have_posts()) @php $related_posts->the_post() @endphp
        <li>
          <a href="{{ get_permalink() }}">{{ get_the_title() }}</a>
        </li>
      @endwhile @php wp_reset_postdata() @endphp
    </ul>
  </section>
@endif

Notice the elegance here: the Blade template doesn’t know how related_posts was fetched; it only knows that related_posts is available and has a have_posts() method it can iterate over. The wp_reset_postdata() is still necessary after the loop, but all the complex query logic is entirely absent. This pattern dramatically improves readability, testability, and maintainability.

By leveraging View Composers and Acorn, Sage empowers developers to build WordPress themes with a truly modern, programmatic, and organized codebase. It’s a stark contrast to the unmaintainable database bloat and inline code found in page builder themes. Sage themes are not just faster and more robust; they offer a developer experience that makes building sophisticated WordPress applications genuinely enjoyable. Embrace the clean architecture, ditch the bloat, and start composing your views the Sage way.