Components…but that’s just a bunch of extra files?
I’ll try to summarize why Sage’s blades (which sounds like the name of a fantasy guild) are so powerful with a few lines of code.
First:
lando wp acorn make:component Marquee
If you aren’t using lando, just…don’t use the word lando. Do I really need to spell that part out? Probably. Anyway, this bootstraps a new component and a view file. You’ll see a new blade in resoures/views/components
.
You’ll also see an empty class that starts like this in app/View/Components/Marquee.php
:
// Add ->with(get_object_vars($this)); for block rendering
class Marquee extends Component {
public function render(): View|Closure|string
{
return view('components.marquee')->with(get_object_vars($this));
}
}
Honestly, one thing you have to get over…is the fact that at first it seems like this is a bunch of extra effort just to split things into a lot of damn files. You can do this with a plugin and a partial or you could just make a class in a plugin. What is the point of this?
First, because you can do this inside other blades:
<x-marquee title="..."/>
And yeah, it’ll render the component. Params you pass in (like title
in this case) need to be defined in the component class as public properties and added to the constructor.
And if you think you can do this, too, you’d be right:
<x-marquee title="...">
<x-other-component/>
<button value="Some stupid CTA no one will click on"/>
</x-marquee>
All you have to do is remember to output the $slot
variable in your blade where “children” should render. Still think classic WP partials are better?
Another massively important thing? You can render components server-side like this:
$component = new \App\View\Components\Marquee();
echo $component->render();
The Component can Become a Block!
Here’s something that isn’t obvious based on that above lil’ snippet. Or maybe it is if you’re smarter than me? Because of how this all works, we can now author UI components in one way and use the same code for both static templates and blocks.
When you register PHP-based blocks (with a block.json
file, via ACF Pro), you need a specific a render file that outputs that block. Sage already is component based, so we can just recycle the above in that render file:
$component = new \App\View\Components\Marquee();
echo $component->render();
Then, inside the component itself, guess what? The context isn’t dumb, if you do something like this, it’ll work:
class Marquee extends Component
{
public string $title = 'Title';
/**
* Create a new component instance.
*/
public function __construct($title = '')
{
$this->title = $title;
if (empty($this->title)) {
$this->title = get_field('title');
}
}
}
What does this do…? If I’m passing the Marquee title in a pre-built template, it will be set from the constructor. If I’m rendering it from a block?
Then it’ll grab that title from ACF. And yes, it’ll grab the field attached to the block, not the post that block lives in.
You can do that if you want, too, because $post
is still in context — if you add global $post
, you’ll have access to those post fields like normal.
The point? My component can get the data it needs from ACF, hooks, etc. in the constructor. I don’t need to care about how it obtains it’s data to include it in a view, I can trust that it’ll do that properly and consistently evyerwhere we use it.
This is 85% of What you Need
We’re actually already almost done. Let’s think about it.
- We now have a way to work in a true component-based way. Server and view code is neatly separated (but not rigid and inflexible, either)
- We have an easy way to output any Sage component as a block with very little work and no react!
- We can nest components inside other components (
<x-component-name></x-component-name>
) - We can nest blocks in other blocks just by
<InnerBlocks/>
to my component blade, similar to how$slot
works. Yeah it’s that easy.
But…it isn’t 100%
We still have crap to talk about, wow! Let’s review:
- It’s still boring. Let’s step into (whatever year you’re reading this in) and integrate react. Yes, I mean actual client side react that will render rich UIs using ACF fields without going fully headless.
- You need “stuff” to cleanly handle things like padding and margains set for each block in the WP admin.
- Congrats, you’ve made an empty site. Let’s review data migration, the dark art of WP that few people actually go into detail about. No, just throwing a plugin into things isn’t going to work.
That said, this is where you can diverge and whichever topic you’re still somehow interested in.