Wednesday, April 16, 2014

Combining PHP template files with associative array models

I've been using Codeigniter for the past 2 years now and I really like it. It might just be the MVC (like) pattern, but it's got a lot of nice built in classes that make building website in PHP a lot quicker, easier and cleaner. So, with my recent exposure to Wordpress, I came to a spot where I was mixing a lot of html with php code, which is something I really hate doing.

Thinking of how, with Codeigniter (and other frameworks), you can combine a *.php template with a data array (or a view model) and render a page I was curious. How does Codeigniter load a php page into a scope with the variables from the supplied data array and spit out the resulting page? After doing a bit of digging I found this nifty function that I ported to my Wordpress theme and now my code looks much cleaner.
function load_template($filename, $data=array()) 
{
    $filename = '/inc/templates/' . $filename . '.php';
    
    if (is_file($filename)) 
    {
        extract($data);
        ob_start();
        
        include( $filename );
        
        $buffer = ob_get_contents();
        @ob_end_clean();
        return $buffer;
    }
    return false;
}
Now with this function you can write a template like...
//inc/templates/biocard.php
<div class="card">
    <div class="photo">
    <?php if( ! empty($image) ) : ?>
        <img src="<?= $image; ?>" alt="<?= $name; ?>" />
    <?php else : ?>
        <img src="/img/missing-user-image.jpg" alt="<?= $name; ?>" />
    <?php endif; ?>
    </div>
    <div class="detail">
        <h4><?= $name; ?></h4>
        <h5><?= $title; ?></h5>
        <?php if( ! empty($email) ) : ?>
            <a class="email" href="mailto:<?= strtolower($email); ?>">Email</a>
        <?php endif; ?>
    </div>
</div>
... and populate it with an associative array:
$model = array(
    'name' => 'Jason',
    'title' => 'Web Developer',
    'email' => 'jason@home.com',
    'image' => 'path/to/profile/image.jpg'
);

return load_template('biocard', $model);