Skip to content
Sage
v10.8.2
  • Sage page

Composers

Composers, also sometimes called View Composers, are essentially identical to the Laravel system of the same name. They allow you to pass data to views (blade templates), scoping that data to that view (and any views it subsequently includes). If you're familiar with Sage 9's data filters, or the Controller package often used with Sage 9, then Composers are a similar concept, but much more powerful: Instead of only allowing data binding to top-level WordPress templates, Composers allow you target any view.

Construction

Note

Composers are autoloaded, which means their naming needs to conform to the PSR-4 standard.

If you're using WP-CLI, you can create composers from the command line:

wp acorn make:composer ExampleComposer

This would create a Composer called ExampleComposer in app/View/Composers/.

If you're not using WP-CLI, the most basic Composer looks like this:

// app/View/Composers/ExampleComposer.php

namespace App\View\Composers;

use Roots\Acorn\View\Composer;

class ExampleComposer extends Composer
{}

This composer doesn't do anything yet, though, so let's give it some functionality.

class ExampleComposer extends Composer
{
    /**
     * This tells the Composer that it should bind data to the 'example'
     * partial.
     */
    protected static $views = [
        'partials.example',
    ];
    
    /**
     * This will make the variable `$roots` available in the 'example' partial
     * with the value described here.
     */
    public function with()
    {
        return [
            'roots' => "Tools for modern WordPress development",
        ];
    }
}

Because that variable is scoped to example.blade.php, we'll also see the following behavior:

<!-- resources/views/content.blade.php -->
{{ $roots }}
<!-- Throws an error because the variable is not defined -->

@include('partials.example')
<!-- resources/views/partials/example.blade.php -->
<h1>{{ $roots }}</h1>
<!-- <h1>Tools for modern WordPress development</h1> -->

@include('partials.example2')
<!-- resources/views/partials/example2.blade.php -->
<div>{{ $roots }}</div>
<!-- <div>Tools for modern WordPress development</div> -->
<!-- Variable is defined in this context because it inherits 
    it from example.blade.php -->

Data sources

We've seen how data can be bound to views, but we only returned a hard-coded string. Usually you'll want something more involved than that.

WordPress

Composers are executed in a context where WordPress functions like get_the_ID() and the_post() will return expected values, so you can retrieve data from WordPress much like you normally would.

Inherited data

Inside of a Composer, you can easily access data that has been passed to or inherited by the view through the data property:

class Example2 extends Composer 
{
    ...
    public function with()
    {
        return [
            'better_roots' => str_replace(
                'modern', 
                '*awesome*', 
                $this->data->get('roots')
            ),
        ];
    }
}
<!-- resources/views/partials/example2.blade.php -->
<div>{{ $better_roots }}</div>
<!-- <div>Resources for *awesome* WordPress development</div> -->

"Automatic" view selection

You can always define what view a Composer will be bound to using the $views property to list the name(s) of the views. However, if your Composer will target only a single view, you can save yourself a few lines of code. Sage will attempt to match Composers to views based on some simple file path logic: If your view and Composer share the same path segments and name, they'll be automatically bound together.

For example, if your view is a partial at /resources/views/partials/page-header.blade.php, a Composer at /app/View/Composers/PageHeader.php will be automatically bound to it. In other words:

  • Match paths below /resources/views and /app/View.
  • Convert the kebab-case of view file names to the PascalCase of Composers.

with() vs override()

You've seen with() used above to pass data to views, but it has a more aggressive sibling calling override() which does the same thing--except that it will replace data inherited by, or passed to, the view while with() will not.

<!-- /resources/views/page.blade.php -->
@include('partials.example', ['roots' => "Resources for modern WordPress development"])

<!-- /resources/views/partials/example.blade.php -->
<h1>{{ $roots }}</h1>
<!-- <h1>Resources for modern WordPress development</h1> -->

Using with():

class Example extends Composer
{
    public function with()
    {
        return [
            'roots' => "An amazing stack!",
        ];
    }
}
<!-- /resources/views/partials/example.blade.php -->
<h1>{{ $roots }}</h1>
<!-- <h1>Resources for modern WordPress development</h1> -->
<!-- The same output! -->

Using override():


class Example extends Composer
{
    public function override()
    {
        return [
            'roots' => "An amazing stack!",
        ];
    }
}
<!-- /resources/views/partials/example.blade.php -->
<h1>{{ $roots }}</h1>
<!-- <h1>An amazing stack!</h1> -->

Contributors

Last updated

Support Roots

Help us continue to build and maintain our open source projects. We’re a small team of independent developers and every little bit helps.

Sponsor Roots on GitHub