← All posts

Taming WordPress Data: A Sage View Composer for Dynamic Project Lists

Taming WordPress Data: A Sage View Composer for Dynamic Project Lists

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 </div> @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.