Over a million developers have joined DZone.

Some further thoughts on templating WordPress

· Web Dev Zone

Make the transition to Node.js if you are a Java, PHP, Rails or .NET developer with these resources to help jumpstart your Node.js knowledge plus pick up some development tips.  Brought to you in partnership with IBM.

In the last post, we looked at getting a Twig generated WordPress theme up and running. I’ll soon begin looking at styling it with SASS and then getting it JavaScript dependencies loaded via Require.js, but first, I’d like to clean up the template code a little. See, last time we were doing something like this to get the posts:

{% for post in posts %}
	{% set format = site.get_post_format() %}
	{% include format 
              ? "content-" ~ format ~ ".html.twig" 
              : "content.html.twig" %}
{% else %} 
	{% include "content-none.html.twig" %}
{% endfor %>

Where “posts” was a php iterator that used the WordPress loop. We were also using a proxy class to access wordpress functions in the template. While this works, I wasn’t too happy with the situation in general. The template was making too many decisions and calling functions. Templates shouldn’t be heavy on logic, because their only purpose should be to display stuff, not to decide what gets displayed.

It also fails to address another problem that I find annoying in wordpress – the content tree is generated during the construction of the page, not before it. That means that certain information isn’t normally available while building the header, for example. In the past, I’ve used a workaround which involves multiple queries and resetting the loop, but this time, I wanted it built into the theme.

The solution is as simple as iterating through the loop completely before starting to render the templates. In this way, we can build up everything the template needs beforehand, so it does not need to make any additional calls. Data is accessible all through the template, and the template itself becomes much simpler. Here’s the part of index.php where we’re building up the content:

if (have_posts()) {
    while (have_posts()) {
        the_post();

        $additional_classes = (is_sticky() && is_home() && !is_paged()) ? "featured" : "";

        $p = array(
            'id' => get_the_ID(),
            'template' => $site->get_format(),
            'title' => get_the_title(),
            'permalink' => get_permalink(),
            'author' => get_the_author(),	
            'classes' => get_post_class($additional_classes),
            'date' => get_the_time(get_option('date_format'))
        );

        if (is_single()) {
            $p['content'] = get_the_content();				
            $meta['description'] = get_the_excerpt();
        } else {
            $p['content'] = get_the_excerpt();

            if (has_post_thumbnail()) {
                $image_attributes = wp_get_attachment_image_src(get_post_thumbnail_id(), 'thumbnail');
                $p['thumbnail'] = $image_attributes[0];
            }
        }

        if ($editable) {
            $p['editlink'] = get_edit_post_link();	
        }

        array_push($content, $p);
    }
}

In the excerpt above, you can see that we’re pulling data in from wordpress itself, and adding some metadata of our own. For example,

'template' => $site->get_format()

tells the post which template file it should use, for example, content.html.twig, summary-gallery.html.twig, and so on. The template doesn’t need to make any decisions. We’re also taking the opportunity to make the fields consistent. In

	if (is_single()) {
		$p['content'] = get_the_content();				
		$meta['description'] = get_the_excerpt();
	} else {
		$p['content'] = get_the_excerpt();
		...
	}

We’re setting the post content to the value of content if we’re showing a single post, or the value of the summary if we’re showing a list of posts. Both the summary and the full post templates will receive a ‘content’ property that represents their primary content:

<article id="post-{{ p.id ?: "0" }}" class="{{ p.classes|join(" ") ?: "post no-results not-found" }}">
	<header class="entry-header row-fluid">
		<h1 class="entry-title">
			{% block articleHeader %}
				<a href="{{ p.permalink }}" title="{{ site.text('Permalink to %s')|format(p.title)|e }}" rel="bookmark">{{ p.title }}</a>
			{% endblock %}
		</h1>
	</header>

	<div class="entry-content row-fluid">{% block articleContent %}{{ p.content|raw }}{% endblock %}</div>

	<footer class="entry-meta row-fluid">
		{% block articleFooter %}
			<div class="meta">{{ site.text('Posted on <span class="date">%s</span>'|format(p.date))|raw }} {{ site.text('by <span class="author">%s</span>')|format(p.author)|raw }}</div>
			{% if meta.editable %}<a href="{{ p.editlink }}" class="edit">{{ site.text("Edit") }}</a>{% endif %}
		{% endblock %}
	</footer>
</article>

content-master.html.twig

<article
	id="post-{{ p.id }}" 
	class="{{ p.classes|join(" ") }} summary row-fluid">

	<a href="{{ p.permalink }}" title="{{ site.text('Permalink to %s')|format(p.title)|e }}" rel="bookmark">

	{% if p.thumbnail %}
		<img src="{{ p.thumbnail }}" class="thumbnail span2" title="{{ p.title()|e }}" />
	{% else %}
		<div class="no thumbnail span2">{{ site.text("no thumbnail") }}</div>
	{% endif %}

	<article class="summary span8">
		<header class="entry-header row-fluid">
			<h1 class="entry-title">
				{% block articleHeader %}{{ p.title }}{% endblock %}
			</h1>
		</header>

		<section class="entry-content row-fluid">
			{% block articleContent %}{{ p.content|raw }}{% endblock %}
		</section>

		<footer class="entry-meta row-fluid">
			{% block articleFooter %}
				{% if meta.editable %}
					<a href="{{ p.editlink }}" class="edit">{{ site.text("Edit") }}</a>
				{% endif %}
			{% endblock %}
		</footer>
	</article>
</a>
</article>

summary-master.html.twig

While the main template now simply looks like this:

{% extends "master.html.twig" %}
{% block pageContent %}

{% for p in posts %} {% include p.template %} {% else %} {% include “content-none.html.twig” %} {% endfor %}

{% endblock %}

index.html.twig

The only function I’m still calling directly is site.text, which wraps the wordpress __ function for text localization. This is intentional as I’m planning to replace it at a later stage. Most plugins and systems which are used to support localization depend scan the theme files for uses of that function, and wrapping it in this way can prevent them from working properly. I’ll probably make some sort of localization file for the theme which sets up the localized values, but it’s not something I’ll be looking at right now.

Next up: Styling the template



Learn why developers are gravitating towards Node and its ability to retain and leverage the skills of JavaScript developers and the ability to deliver projects faster than other languages can.  Brought to you in partnership with IBM.

Topics:

Published at DZone with permission of Karl Agius, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}