Bridging WordPress Data to Blade: A View Composer for Custom Projects
When I first stumbled into WordPress development years ago, the common approach often felt like a wild west of WP_Query calls sprinkled directly into template files, with functions.php growing into an unmanageable beast. It worked, sure, but scalability and maintainability? Forget about it. That's why discovering Sage was such a revelation for me. It transformed how I build WordPress sites, bringing a much-needed MVC-like structure and a developer-first mindset to a platform often criticized for its spaghetti code. Today, I want to share one of my favorite Sage features that really helps keep things clean: View Composers, specifically for bringing custom post type data gracefully into your Blade templates.
One of Sage's core philosophies, powered by Laravel's Blade templating engine, is to keep your templates strictly focused on presentation. No database queries, no complex logic—just HTML with a sprinkle of simple loops and conditionals. This separation of concerns is beautiful. But if your Blade template needs data, say, a list of custom "Project" posts, how do you get it there without breaking that clean separation? Enter View Composers.
A View Composer acts as a middleman. It hooks into the lifecycle of a specific view (or set of views) and allows you to prepare and inject data into that view *before* it's rendered. This keeps your data retrieval and processing logic out of the template file itself, creating a far more organized and testable codebase. Imagine trying to achieve this kind of clean data routing in a drag-and-drop page builder like Divi or Elementor – it's a constant battle against their inherent database bloat and UI limitations, often forcing you to use shortcodes or messy inline PHP that completely defeats the purpose of clean architecture. With Sage, it's programmatic and elegant.
Let's walk through a concrete example. Say we have a "Projects" custom post type, and we want to display the five most recent projects on our `page-projects.blade.php` template.
First, we define our View Composer. In a typical Sage setup using Acorn, you'd put this in `app/View/Composers/ProjectComposer.php`:
```php <?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 = [ 'page-projects', 'partials.content-page-projects', // If you're using a partial ];
/** * Data to be passed to view before rendering. * * @return array */ public function with() { return [ 'projects' => $this->getProjects(), ]; }
/** * Retrieve the latest projects. * * @return array */ protected function getProjects() { $query_args = [ 'post_type' => 'project', 'posts_per_page' => 5, 'post_status' => 'publish', 'orderby' => 'date', 'order' => 'DESC', // Add any other query arguments you need ];
$projects_query = new WP_Query($query_args);
return $projects_query->posts; } } ```
This `ProjectComposer` class is straightforward. We tell it which views (`page-projects.blade.php` and potentially `partials.content-page-projects.blade.php`) it should "compose" for using the `$views` property. The `with()` method returns an associative array, where keys become variables available in your Blade template. Inside `getProjects()`, we perform our standard WordPress query using `WP_Query`. We retrieve the posts and return them.
Now, in your `page-projects.blade.php` (or `partials.content-page-projects.blade.php`), accessing this data is incredibly clean:
```blade <div class="projects-list"> @if (!empty($projects)) @foreach ($projects as $project) <article class="project-item"> <h2><a href="{{ get_permalink($project->ID) }}">{{ $project->post_title }}</a></h2> <p>{{ get_the_excerpt($project->ID) }}</p> {{-- Add more project details here --}} </article> @endforeach @else <p>No projects found.</p> @endif </div> ```
Notice how `page-projects.blade.php` doesn't know *how* `$projects` was fetched, only that it's available. This is the power of separation. Your template is pure presentation. If you need to change the query (e.g., fetch 10 projects instead of 5, or filter by category), you modify the `ProjectComposer`, not the Blade template. This keeps your codebase organized, easy to debug, and incredibly maintainable. It's a far cry from the unmanageable complexities that can arise from page builders that embed data queries directly into their "modules" or database records, leading to a sprawling mess that’s hard to version control or reason about.
For me, this simple technique encapsulates why Sage, with its Acorn-powered dependency injection and Blade templating, is the premier choice for modern WordPress development. It empowers you to build robust, clean, and truly maintainable sites, making the development process a joy rather than a constant battle against bloat.