Bridging Worlds: Passing External API Data to Blade with Sage View Composers
If you’ve spent any significant time building WordPress themes, you know the struggle: templates riddled with PHP logic, `WP_Query` loops mixed with HTML, and a general entanglement of presentation and data retrieval that makes maintenance a nightmare. This isn't just about personal preference; it’s about writing sustainable, testable code. It's the stark contrast to the database bloat and unmanageable front-end code generated by page builders like Divi or Elementor, which prioritize drag-and-drop over programmatic elegance. This is precisely where Sage, with its MVC-like architecture powered by Blade and Acorn, shines brightest for developers like us.
Sage encourages a clean separation of concerns. Your Blade templates should be exactly what they sound like: templates. Purely presentation-focused, handling how data *looks*, not how it’s *fetched* or *processed*. This is fantastic for standard WordPress data, which often comes pre-packaged via the global `$post` object. But what happens when you need data from an external API, a custom database table, or a complex service layer that sits entirely outside the typical WordPress loop? Shoving that logic directly into your Blade partial would defeat the entire purpose of Sage’s clean architecture.
Enter View Composers. These are Sage’s elegant solution for injecting data into your views, ensuring your templates remain pristine. A View Composer acts as a middleware for your views, allowing you to prepare and inject any data your template needs *before* it’s rendered. It’s the perfect spot to fetch data from custom sources, perform transformations, and make sure your Blade partial receives exactly what it expects, in the format it expects. Let's walk through a concrete example: fetching a list of "trending products" from an external REST API and cleanly displaying them.
First, imagine our Blade partial (`resources/views/partials/trending-products.blade.php`) that will display this list. Notice how it simply assumes the `$trendingProducts` variable will be available and ready for iteration. No data fetching, no complex logic here, just presentation:
@if (! $trendingProducts->isEmpty()) <div class="trending-products-widget"> <h3>Trending Products</h3> <ul> @foreach ($trendingProducts as $product) <li> <a href="{{ $product->url }}"> <img src="{{ $product->image }}" alt="{{ $product->title }}"> <span>{{ $product->title }}</span> <span class="price">{{ $product->price }}</span> </a> </li> @endforeach </ul> </div> @endif
Next, we create our View Composer. This is where the magic happens. In your `app/View/Composers` directory, create `TrendingProductsComposer.php`. This class will be responsible for fetching and preparing the `trendingProducts` data. For this example, we'll simulate an API call with an array, but in a real-world scenario, you’d use `wp_remote_get()` or a dedicated HTTP client injected via Acorn's dependency injection container for robust error handling and better testability:
namespace App\View\Composers;
use Roots\Acorn\View\Composer; use Illuminate\View\View; // For type hinting
class TrendingProductsComposer extends Composer { /** * List of views served by this composer. * * @var array */ protected static $views = [ 'partials.trending-products', ];
/** * Data to be passed to view before rendering. * * @param \Illuminate\View\View $view * @return array */ public function with(View $view) { // Simulate fetching data from an external API $apiRawData = [ ['id' => 1, 'name' => 'Ergonomic Keyboard', 'cost' => 129.99, 'img_url' => 'https://example.com/keyboard.jpg'], ['id' => 2, 'name' => 'Noise-Cancelling Headphones', 'cost' => 249.00, 'img_url' => 'https://example.com/headphones.jpg'], ['id' => 3, 'name' => '4K USB-C Monitor', 'cost' => 399.99, 'img_url' => 'https://example.com/monitor.jpg'], ];
// Transform raw API data into a format suitable for the view $trendingProducts = collect($apiRawData)->map(function ($product) { return (object) [ // Cast to object for easy property access in Blade 'title' => $product['name'], 'url' => '/products/' . $product['id'], // Generate friendly URL 'price' => sprintf('$%.2f', $product['cost']), // Format currency 'image' => $product['img_url'], ]; });
return [ 'trendingProducts' => $trendingProducts, ]; } }
Notice the `protected static $views` property, which tells Sage which view(s) this composer applies to. The `with` method is where we fetch our data, format it, and return an associative array where the keys (`trendingProducts` in this case) become the variables available in our Blade partial. We’re using Laravel's `collect()` helper here for easy data manipulation, a testament to Acorn’s power bringing modern PHP features to WordPress development.
Finally, to include this dynamically populated partial in any of your main templates (e.g., `resources/views/front-page.blade.php`), you simply use Blade's `@include` directive:
@extends('layouts.app')
@section('content') <div class="hero-banner">...</div>
@include('partials.trending-products')
<div class="latest-news">...</div> @endsection
And there you have it. Your main template remains clean, simply asking for the `trending-products` partial. The partial itself remains purely presentational. All the complex data fetching and transformation logic is neatly encapsulated within the `TrendingProductsComposer`. This organized, programmatic codebase is a joy to work with, offering clear separation of concerns, easy testing, and a maintainability level that traditional WordPress themes, or the black box approach of page builders, can only dream of. Sage empowers you to build robust, modern WordPress sites with the development experience you deserve.