Why I use macros for everything

Code

December 24, 2021
UIKit needed
Make sure to activate the UIkit CSS/JS setting in Toolbox Settings

Okay, so I get that this is a pretty spammy title. But Twig macros are just awesome to use all over your templates. They're like the CSS-classes of HTML.

What is a macro?

A macro is a re-usable piece of code, sort of what a function is in PHP. A macro can be used directly in your template:


{% for i in 0..5 %}
    {{ _self.the_number( i ) }}
{% endfor %}


{% macro the_number( number ) %}
<div>The current number is {{ number }}</div>
{% endmacro %}


Notice the _self variable there, before calling the named macro. This means we are calling a macro that resides in our current template.

Code output:

The current number is 0
The current number is 1
The current number is 2
The current number is 3
The current number is 4
The current number is 5

Ready for more?

The example above is a very common pattern. But applied to WordPress posts, this is a something that you'd probably want applied across your entire site. A card layout for instance:

The concept is similar. This example first sets the posts variable with some dummy data, but right after we see the same pattern. It opens an <div> element and iterates over the posts, calling each iteration item. Then, it calls the 'card' macro, which is defined in the same template.

The macro takes one variable, the 'item'. Note that everything else is scoped, which means that no other values that exist outside the macro are available.


<div class="uk-child-width-1-2@s uk-grid-match" uk-grid>
{% for item in posts %}
    {{ _self.card( item ) }}
{% endfor %}
{% macro card( item ) %}
	<a href="{{ item.link }}" class="uk-link-reset">
		<div class="uk-card uk-card-default uk-height-1-1">
			<div class="uk-background-cover uk-height-small uk-panel uk-flex uk-flex-center uk-flex-middle" style="background-image: url({{ item.thumbnail|default( 'https://picsum.photos/seed/200/300' ) }});">
			</div>
			<div class="uk-card-body">
				<h3 class="uk-card-title">{{ item.title }}</h3>
				{{ item.preview.length(20).read_more( '' ) }}
			</div>
		</div>
	</a>
{% endmacro %}
</div>


How is this helpful?

In itself, this isn't much different from building a loop and adding the html markup and twig notation, right? So when is this really starting to make sense?

Just like CSS classes, you can use macros over and over again. If you have a CSS classname called "makeitsnap" for instance, which makes your text bigger and in neon-color:


.makeitsnap {
    color: #FF6EFF;
    font-size: 2em;
}

Make It Snap

Everytime you want to make this appear the same, you can just add the classname to a span or div element to change the appearance. Should you ever need to change the color, you would do that for the classname and it would change everywhere.

Using macros that are outside of our template

To really take advantage of macros, you can use the ones that are outside of our template. Let's take our card example, and put that in a separate template:

Using the Twig Templates CPT, create a template called "card_macro" (make sure the slug has this value) and paste the following code inside the template:


{# stored as Twig Template Post with slug 'card_macro' #}
{% macro render( item ) %}
	<a href="{{ item.link }}" class="uk-link-reset">
		<div class="uk-card uk-card-default uk-height-1-1">
			<div class="uk-background-cover uk-height-small uk-panel uk-flex uk-flex-center uk-flex-middle" style="background-image: url({{ item.thumbnail|default( 'https://picsum.photos/seed/200/300' ) }});">
			</div>
			<div class="uk-card-body">
				<h3 class="uk-card-title">{{ item.title }}</h3>
				{{ item.preview.length(20).read_more( '' ) }}
			</div>
		</div>
	</a>
{% endmacro %}


Notice that I changed the name of the macro to 'render'. This is because we will be using this macro in a way that mimics component rendering. Now let's head back to our original template, add the macro and call it:


{% import 'card_macro.twig' as Card %}
<div class="uk-child-width-1-2@s uk-grid-match" uk-grid>
{% for item in posts %}
    {{ Card.render( item ) }}
{% endfor %}

</div>


On the very first line, we are importing the macro-file as 'Card', with a capital 'C'. This is helpful for identifying the 'components' from regular variables, so it's certainly a practice that I would like to recommend.

In the loop, we are rendering the only macro available in 'Card', which is called 'render'.

Now, if we want to make a change to the Card layout, we would go to the 'card_macro' template and save it.

Using the card on other template parts

Now that we've set a base for our card, we can re-use this design on various other parts of our site. The beauty of it all is that - if we decide to change the layout of our card - it changes that sitewide!

We can use it in a modal for instance:


{% import 'card_macro.twig' as Card  %}
<!-- This is a button toggling the modal with the default close button -->
<div class="uk-text-center">
    <button class="uk-button uk-button-default uk-margin-small-right" type="button" uk-toggle="target: #modal-close-default">
    OPEN MODAL
    </button>
</div>

<!-- This is the modal with the default close button -->
<div id="modal-close-default" class="uk-flex-top" uk-modal>
    <div class="uk-container-small uk-modal-dialog uk-margin-auto-vertical">
    {% for item in posts %}
    {{ Card.render( item ) }}
    {% endfor %}
    </div>
</div>


You've learned
You have learned how to use macros in your templates and how to use them as separate templates. This way you can import often used bits of code, so they can be maintained globally and updated all at once when needed.

Beaverplugins

Web ninja with PHP/CSS/JS and Wordpress skills. Also stand-in server administrator, father of four kids and husband to a beautiful wife.
Always spends too much time figuring out ways to do simple things even quicker. So that you can benefit.