Skip to content
On this page

Tips for Writing Views

Here are some more general tips for writing dry, maintainable and re-usable views. We're using Plates here for our examples, but the concepts are applicable whichever templating library you choose.

Foreach is a partial smell

  • If you're using a foreach, think about whether the element you're repeating should be spun off into its own partial.
ORIGINAL
php
// views/foo.plate.php
// in practise you probably won't bother doing this for something so trivial!
<?php foreach ($elements as $element):?>
<div>
    <h3><?=$element['foo']?></h3>
    <p><?=$element['bar']?></p>
</div>
<?php endforeach?>
REFACTOR
php
// views/foo.plate.php
<?php foreach ($elements as $element):?>
<?=$v->render('partials/bar', $element)?>
<?php endforeach?>

// views/partials/bar.plate.php
<div>
    <h3><?=$foo?></h3>
    <p><?=$bar?></p>
</div>

Repetition demands abstraction

  • It's useful to think in terms of generic and re-usable components, and look for ways to simplify. So if you wind up with several similar partial elements, consider whether they could be further abstracted, and where you could pass in config/variables instead. For example you might have cards representing different custom post types, all with image, title and body variables and elements, and maybe the only difference might be a css class to identify the post type. In this case, you might not need a different partial for every post type - just a generic card element view, into which you pass the css class along with the image, title and body variables.
ORIGINAL
php
// views/partials/foo-card.plate.php
<div class="card foo">
    <img src="<?=$imageUrl?>">
    <h3><?=$title?></h3>
    <p><?=$bodyText?></p>
</div>

// views/partials/bar-card.plate.php
<div class="card bar">
    <img src="<?=$imageUrl?>">
    <h3><?=$title?></h3>
    <p><?=$bodyText?></p>
</div>

// views/partials/baz-card.plate.php
<div class="card baz">
    <img src="<?=$imageUrl?>">
    <h3><?=$title?></h3>
    <p><?=$bodyText?></p>
</div>
REFACTOR
php
// we introduce $type and now we just need a single view
// views/partials/generic-card.plate.php
<div class="card $type">
    <img src="<?=$imageUrl?>">
    <h3><?=$title?></h3>
    <p><?=$bodyText?></p>
</div>

No variable assignment, yes, even iterators

  • You don't need a count iterator; with sequential arrays you can use the key in foreach key => value. If it's not a sequential array, then reformat the variable in your controller.
php
// views/foo.plate.php
<?php $i=0?>
<?php foreach ($elements as $element):?>
<span>This is element no. <?=$i?></span>
<p><?=$element['text']?></p>
<?php $i++?>
<?php endforeach?>
php
// views/foo.plate.php
<?php foreach ($elements as $key => $element):?>
<span>This is element no. <?=$key?></span>
<p><?=$element['text']?></p>
<?php endforeach?>

Helpers ftw

  • Create helper functions and/or service class methods if you need to grab or compute additional data within a view template that can't really be resolved at the controller stage or with standard control structures.
helpers.php
php
function ad_hoc_foo($postId) {
    // retrieve and compute something
    $post  = get_post($postId);
    $value = $post->get_something();
    return (new VendorSpace\FooBar)->get($value) * 10;
}
foo.plate.php
php
<?php foreach ($things as $thing):?>
<?=ad_hoc_foo($thing['postId'])?>
<?php endforeach?>
  • These functions should normally return values rather than actually echo anything out (i.e. in WordPress terms, you should be implementing get_the_foo(), not the_foo()) It's a view's job to output/echo html, not a function's. Use your best judgement here, but remember that one of the main points is that we're trying to keep view HTML and PHP logic consistently separate for clarity and code readability and avoid weird side effects. Of course many native WP functions - e.g. wp_nav_menu, wp_footer - which you will likely be using within view templates, absolutely do behave like view template render calls, and you'll see it in WordPress code snippets all over the internet, but we don't need to replicate this legacy of bad coding practise 😃
  • While we're on the topic of WordPress code snippets, never use template style php in your helpers.php functions or class methods. It's difficult to read and recent versions of php don't really deal with it very well - it often causes hard to find parsing bugs, especially if you have a bunch of them in the same file. Avoid it at all costs - if you're copy pasta-ing something off Stack Exchange, make sure you refactor it as required.
  • If you really do have to output html via a function, for example maybe you need to interact with WordPress core, or a plugin that follows that pattern, then you should use a view, don't echo it out directly. (Tip: you might want to think about whether you might be better off using a Controller class here)
php
<?php
// helpers.php
// bad
function ad_hoc_foo() {
    echo "<div>Avoid this, html output belong in views.</div>";
}

// worse
function ad_hoc_foo() { ?>
    <div>
        Never do this!
        It often confuses the hell out of the php parser
        and you get weird bugs
    </div>
<?php }
php
<?php
// the view calls the function (i.e. get pattern)
// helpers.php
function ad_hoc_foo() {
    return "This is a preferable pattern";
}

// views/foo.plate.php
<div>
    <?=ad_hoc_foo()>
</div>

// the function calls the view (i.e. render/controller pattern)
// helpers.php
function ad_hoc_foo() {
    echo view('foo');
}

// views/foo.plate.php ?>
<div>
    Do this if you absolutely need your function to output something.
    For example if it doesn't get called by a view.
</div>

Context variable or helpers?

  • Think about whether to define your variables in the controller or use existing functions directly in the view and about the trade offs. For example in an acf context, you could call get_field in controller and assign it to a variable, or you could just call get_field directly in the view. If it returns a complex array with sub fields, then you're probably better off doing it in the controller so you can assign it to a variable. If it's a single field value then calling it directly in the view is probably fine. The trade off there is in terms of clarity of having explicit context variable declarations in the controller for that specific view, against the simplicity of just calling it at the point you need it.

Made by Moussa Clarke @ Sanders Web Works with ❤️