View Composers: Serving Up Clean CPT Data in Sage 10
If you’ve spent any time developing custom WordPress themes, you know the struggle: how do you get data from your custom post types (CPTs) and their associated custom fields into your templates without turning them into a tangled mess of `WP_Query` loops and `get_field()` calls? The traditional WordPress approach often blurs the lines between data retrieval and presentation, leading to unmaintainable, hard-to-read code. This is precisely where Sage, and specifically its elegant View Composers powered by Acorn, shine brightest.
Forget the shortcode soup and database bloat of page builders like Divi or Elementor, where every piece of content becomes an abstract block managed in a visual editor, divorcing it from sane, programmatic control. With Sage, we embrace a structured, MVC-like approach. Our Blade templates should be *purely* presentation. They should know nothing about *how* the data was fetched, only that it’s there, ready to be displayed. View Composers are the unsung heroes that make this separation possible, allowing you to route clean, pre-processed data to your templates.
Let’s walk through a concrete example. Imagine we have a custom post type called `project` and each project has custom fields like `client` and `status`. Instead of querying these directly in `single-project.blade.php`, we’ll use a View Composer.
First, create a new composer file, typically in `app/View/Composers/Project.php`:
namespace App\View\Composers;
use Roots\Acorn\View\Composer;
class Project extends Composer { /** * List of views served by this composer. * * @var array */ protected static $views = [ 'single-project', 'partials.content-single-project', // If you break it into partials ];
/** * Data to be passed to view before rendering. * * @return array */ public function with() { $post = get_post(); // Get the current global post object
// Ensure we're dealing with a 'project' post type if (! $post || $post->post_type !== 'project') { return []; }
return [ 'project' => (object) [ 'id' => $post->ID, 'title' => get_the_title($post), 'content' => apply_filters('the_content', $post->post_content), 'client' => get_field('client', $post->ID), // Using ACF example 'status' => get_field('status', $post->ID), 'link' => get_permalink($post), 'thumbnail' => get_the_post_thumbnail($post, 'large'), ], ]; } }
This `Project` class extends `Roots\Acorn\View\Composer`, leveraging Acorn's dependency injection container to handle its lifecycle. The `$views` array tells Sage that this composer should provide data to `single-project.blade.php` (and any other views listed). The `with()` method is where the magic happens: we fetch the current post, extract relevant data, including custom fields using `get_field()` (a common function for ACF users), and package it into a clean object. This object, `$project`, is then made available to our specified Blade templates.
Now, our `single-project.blade.php` template becomes incredibly clean and focused on presentation:
@extends('layouts.app')
@section('content') <article @php(post_class())> <header> <h1 class="entry-title">{{ $project->title }}</h1> @if($project->thumbnail) <figure>{{ $project->thumbnail }}</figure> @endif </header>
<div class="entry-content"> <p>Client: {{ $project->client }}</p> <p>Status: {{ $project->status }}</p> {!! $project->content !!} </div>
<footer> <a href="{{ $project->link }}">View Project</a> </footer> </article> @endsection
Notice the difference: no `get_post()`, no `the_title()`, no `get_field()` directly in the template. Just `$project->title`, `$project->client`, and so on. The template is purely concerned with *how* to display `$project`, not *how to get* `$project`. This is a massive win for separation of concerns.
The benefits here are substantial: your templates are lean and readable, your data fetching logic is centralized and testable within PHP classes, and your overall codebase gains a level of organization that is simply not possible with conventional WordPress theme development or page builder solutions. Sage, through Acorn and its well-designed View Composers, provides the tools to build truly modern, maintainable WordPress applications that developers actually enjoy working on. It’s about bringing programmatic sanity back to your projects.