以下是来自 Charlie Walter 的客座文章。 Charlie 之前曾 为我们撰稿,当他不 让我极度嫉妒 的时候。 现在他回来分享一些完全不同的东西。 我们将学习他了解到的使用模板引擎简化 WordPress 主题设计的方法。
模板引擎非常棒! 它们使复杂的编程语言更容易编写,并包含简化开发过程的功能。
WordPress 是一个让我们了解模板引擎工作原理的自然环境,不仅因为它以模板为驱动,而且因为它依赖于 PHP。 WordPress 本身以其对内容发布者的低进入门槛而闻名,但它需要对 PHP 的了解才能进行大量的自定义,这使得那些想要在基本主题设计之外参与游戏开发的开发者面临着更大的挑战。
模板引擎的工作原理
从最基本的层面上讲,模板引擎是一个包含在项目中的包,它允许我们将一种语言编译成另一种语言。
我把它比作外语能力。 没错,你在高中学习了四年西班牙语,你可能能够在一定程度上阅读和写作,但要将一串复杂的单词组合在一起仍然非常困难。 如果你手机上有一个应用程序可以将你的 西班牙语 翻译成优美的西班牙语,这就像模板引擎对 PHP 所做的那样。
让我们看看 WordPress 循环在普通 PHP 中的基本示例
<?php if ( have_posts() ) : ?>
<?php while ( have_posts() ) : the_post(); ?>
<article>
<h1><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h1>
<?php the_excerpt(); ?>
</article>
<?php endwhile; ?>
<?php else : ?>
<p><?php _e( 'Sorry, no posts matched your criteria.' ) ?></p>
<?php endif; ?>
…以及相同的代码,但使用 Twig
{% for post in posts %}
<article>
<h1>{{post.title}}</h1>
{{ post.excerpt }}
</article>
{% else %}
<p>{{ __('Sorry, no posts matched your criteria.') }}</p>
{% endfor %}
如果这还不值得一只快乐的滑稽企鹅,那我真不知道什么才值得了。

WordPress 的不同模板示例
我将介绍几种可以用来使 WordPress 主题开发变得更有趣的模板引擎。 在每种情况下,我们将概述模板引擎本身,并提供一个关于如何将它与 WordPress 循环一起使用的示例,以及将它们集成到 WordPress 的资源。
Jade-PHP
Jade-PHP 使在 Jade 文件中编写 PHP 成为可能。
等等! Jade 是什么?
Jade 是一种干净的、对空格敏感的语法,它本身就是一种 HTML 模板引擎。 因此,例如,这…
.my-class
a.btn(href="http://charliejwalter.net/") I'm a link
…编译成这个
<div class="my-class">
<a class="btn" href="http://charliejwalter.net/">I'm a link</a>
</div>
虽然 Jade 本身是 HTML 的抽象,但 Jade-PHP 允许我们与 HTML 并行抽象 PHP,使其成为 WordPress 主题开发的理想选择。
设置
WordPress 模板是用 .jade
文件编写的,并保存在其中。 使用 Grunt 和 grunt-jade-php 任务,我们可以将 Jade 文件(.jade
)编译成 WordPress 所需的 PHP 文件(.php
)来执行其任务。
Jade 模板与 WordPress 模板之间存在一对一的关系。 换句话说,在 WordPress 使用 page.php
文件作为默认页面模板的地方,我们将在目录中包含一个 page.jade
文件,我们的 Grunt 任务会将其转换为 PHP 文件。 然后,WordPress 将使用编译后的 PHP 文件,就像我们在其中编写了 PHP 一样,但我们实际上并没有接触过 PHP。 很酷!
注意: 这些 PHP 文件需要放在你通常放它们的地方。
一个缺点是我们必须在本地将 Jade 编译成 PHP,并且当这种情况发生时,Jade-PHP 会为每个模板生成一个完整的 HTML 文档,而不是使用 WordPress 的方法(如 get_header()
和 get_template_part()
)来重复使用模板。 这对于维护来说不是问题,但在性能方面,我们将加载本可以缓存的代码。
我个人将文件结构化为在项目中创建 source
和 compiled
文件夹,以便将所有源文件与编译后的版本分开。 compiled
文件夹是 WordPress 实际上用作主题的文件夹。 但是,不需要编译的文件需要复制到此编译文件夹中。 这可以使用 grunt-contrib-copy
完成。 这也意味着我们可以 watch
这些文件,并连接到 livereload
以实时刷新我们的工作!
├── source
├── header.jade
├── index.jade
├── footer.jade
├── functions.php
├── style.css
├── compiled
├── header.php
├── index.php
├── footer.php
├── functions.php
├── style.css
├── Gruntfile.coffee
└── package.json
WordPress 将尝试将 source
文件夹读取为另一个主题,这将提示出现类似“模板缺失”的错误消息,因为它找不到构建完整主题所需的所有文件。 并非理想,尽管理论上你可以在部署过程中排除源文件以防止这种消息出现。
关于 Jade-PHP 需要注意的一点是,至少在撰写本文时,它缺乏对 Atom、Sublime 或 TextMate 的特定语法高亮显示。 对于某些人来说,这可能是决定性的因素。
Jade-PHP 中的 WordPress 循环
:php
if (have_posts()) :
while (have_posts()) : the_post();
article
h1: a(href= the_permalink())= the_title()
!= the_excerpt()
endwhile;
Jade-PHP 启动主题
下载一个供 WordPress 使用的 Jade-PHP 启动主题。
Jade

我总是发现构建 WordPress 主题非常混乱,因为将 PHP 和 HTML 在同一个标记中组合在一起非常困难。 我们可以使用 Jade 本身来帮助我们完成这项工作。 这里与 Jade-PHP 的主要区别在于我们的资产将是服务器端编译的。 这意味着不需要本地编译,因为它会在模板被访问时动态发生。 此外,这解决了模板编译成完整 HTML 文档的问题,使我们能够利用 Jade 更高级的模板功能,例如将一个模板扩展到另一个模板。
设置
首先,我们需要 Jade 的 PHP 编译器,它可以在 GitHub 上的 Jade 仓库 的“其他语言实现”部分找到。
然后,让我们在主题文件夹中创建 composer.json
文件
{
"require": {
"path-to-project/jade-php": "*"
}
}
现在,运行 Composer 安装。 如果你的 Composer 安装是全局的,那就应该是
composer install
或者,如果 composer 是在项目中本地安装的
php bin/composer install
现在,我们需要在主题目录中创建以下文件
compiler.php
page-data.php
layout.jade
index.jade
functions.php
index.php
注意: 所有 WordPress 主题都需要 style.css
,但我们将它从这个列表和其他列表中省略,因为它与开始使用我们的模板引擎无关。
compiler.php
此文件通过在所有地方都要求它来负责将 Jade 编译器返回到你的模板中。
<?php
require_once('vendor/autoload.php');
use Jade\Jade;
return new Jade();
?>
page-data.php
这是为了将我们想要用于重复使用的常用页面变量提供给程序。
<?php
$data = array(
'wp_title' => wp_title('', false),
'wp_head' => output_buffer_contents(wp_head),
'wp_footer' => output_buffer_contents(wp_footer),
'template_directory_uri' => get_template_directory_uri(),
'stylesheet_url' => get_bloginfo('stylesheet_url'),
'home_url' => esc_url( home_url( '/' ) ),
'blog_title' => get_bloginfo(),
'pages' => get_pages(),
'categories' => get_categories('show_count=0&title_li=&hide_empty=0&exclude=1')
);
// To compensate for WordPress not providing a url for each post
foreach ( $data['pages'] as $page ) {
$page->permalink = get_permalink($page->ID);
}
// To compensate for WordPress not providing a url for each category
foreach ( $data['categories'] as $category ) {
$category->link = get_category_link( $category->term_id );
}
return $data;
?>
layout.jade
将模板扩展到其他模板是 Jade 的一大优势。这使我们能够创建一个可作为网站布局主要构建块的 shell,然后在扩展时对其进行修改。
这可以是任何东西,但可能看起来像这样
doctype
html(lang='en')
head
meta(charset="UTF-8")
title= wp_title('')
link(rel="stylesheet" type="text/css" href= bloginfo('stylesheet_url') media="screen")
- wp_head();
body
header
a(href= esc_url( home_url( '/' ) ))= get_bloginfo()
- get_template_part('nav')
block content
:php
get_sidebar();
wp_footer();
functions.php
大多数 WordPress 主题使用 functions.php
文件。在这种情况下,我们向其中添加一个函数以弥补缺少 get_wp_head()
方法。
<?php
function output_buffer_contents($function, $args = array()){
ob_start();
$function($args);
$contents = ob_get_contents();
ob_end_clean();
return $contents;
}
?>
index.php
这是大多数 WordPress 主题目录中的主要模板或主页。这是一个包含 Jade 编译器和页面数据的 index.php
工作示例
$compiler = include('compiler.php');
$data = include('page-data.php');
$data['posts'] = array();
if ( have_posts() ) :
while ( have_posts() ) : the_post();
array_push($data['posts'], array(
'permalink' => get_permalink(),
'title' => get_the_title(),
'excerpt' => get_the_excerpt()
));
endwhile;
$data['next_posts_link'] = get_next_posts_link('Older');
$data['previous_posts_link'] = get_previous_posts_link('Newer');
endif;
echo $compiler->render('index', $data);
在这里,使用了熟悉的 WordPress 循环,但是我们没有在循环中渲染标记,而是在页面 $data
上的 posts
数组中添加属性,我们希望 Jade 在那里编译和填充内容。
The WordPress Loop in Jade
这是 Jade 中的 WordPress 循环
each post in posts
article
h1
a(href= post['permalink'])= post['title']
!= post['excerpt']
Jade Starter Theme
Mustache

我胡子问你一个问题:你想要在你的模板中使用更少的逻辑吗?Mustache 提供了一种无逻辑的模板方法,它强制你将逻辑与模板分开,从而有效地清理模板。棒极了!
设置
设置与我们渲染 Jade 模板的方式非常相似,因为 它的编译器 可以使用 Composer 安装。
首先,让我们在主题目录中创建 composer.json
文件
{
"require": {
"mustache/mustache": "~2.5"
}
}
运行 Composer 安装,就这样,我们可以在 WordPress 页面模板中添加以下内容以确保编译器运行
echo $mustache->render('index', $data);
现在我们拥有了 Mustache,我们需要在主题文件夹中添加一个 mustache-compiler.php
文件,以便要求编译器加载到我们的模板中,并且这样做无需指定对 views
文件夹的显式路径,我们的源文件将驻留在该文件夹中
<?php
require_once('vendor/autoload.php');
return new Mustache_Engine(array(
'loader' => new Mustache_Loader_FilesystemLoader(get_template_directory() . '/views')
));
?>
The WordPress Loop in Mustache
{{#posts}}
<h1><a href="{{permalink}}">{{{title}}}</a></h1>
{{{excerpt}}}
{{/posts}}
Mustache Starter Theme
下载适用于 WordPress 的 Mustache 启动主题。
Timber

因此,你喜欢本文到目前为止分享的想法,但可能不想经历所有设置。这就是 Timber 的用武之地。
Timber 是 可作为免费的 WordPress 插件使用,这使其可能是我们在此处介绍的模板引擎中最容易安装的。实际上,Timber 本身不是模板引擎,而是依赖于 Twig 来实现,同时充当编写 Twig 文件所需的配置。此外,它还拥有一个库,该库将 WordPress 钩子集成到 Twig 中,使其与在 WordPress 中编写原生 PHP 一样强大。
哦,对了,我们还 有一篇文章 涵盖了开始使用 Timber 的来龙去脉。
设置
下载并安装该插件,直接从 WordPress 插件库中 安装即可。
接下来,我们需要确保主题目录包含以下文件
layout.twig
index.twig
functions.php
index.php
layout.twig
这将是我们网站的主要标记块,其中包含文档 <head>
和网站的基本布局。换句话说,我们可以扩展它到我们所有的 Twig 模板文件中,并在每个模板的基础上更改特定的块。
这是一个使用相当常见的网站布局的基本示例
<!DOCTYPE html>
<html lang='en'>
<head>
<meta charset="UTF-8">
<title>{{wp_title}}</title>
<link rel="stylesheet" type="text/css" href="{{theme.link}}/style.css" media="screen">
{{wp_head}}
</head>
<body>
<header>
{{site.name}}
</header>
{% block content %}
{% endblock %}
{{wp_footer}}
</body>
</html>
用双大括号 {{ }}
包裹的任何内容都是 Timber 将使用 Twig 的编译输出填充的变量。并且,当我们将此模板扩展到其他模板时,我们就可以直接在扩展它的模板中修改每个变量。
functions.php
这是大多数 WordPress 主题附带的标准文件。我们向其中添加的只是有关 Timber 如何配置的说明,以及我们在模板中调用的任何变量的定义。
<?php
add_filter('timber_context', 'add_to_context');
function add_to_context($data){
$data['menu'] = new TimberMenu();
$data['categories'] = Timber::get_terms('category', 'show_count=0&title_li=&hide_empty=0&exclude=1');
return $data;
}
?>
index.php
这通常是 WordPress 主题的主要或主页模板。我们需要调用我们在 functions.php
中定义的变量,以便模板在 Timber 编译 Twig 文件到 PHP 时知道要渲染什么。在这种情况下
<?php
$context = Timber::get_context();
$context['pagination'] = Timber::get_pagination();
Timber::render('index.twig', $context);
?>
The WordPress Loop in Timber
{% for post in posts %}
<article>
<h1>{{post.title}}</h1>
{{post.get_preview}}
</article>
{% endfor %}
Timber Starter Theme
下载适用于 WordPress 的 Timber + Twig 启动主题。
Timber + Jade (…Twade?)
虽然 Timber 自带一个模板引擎,但我们可以配置它使用其他模板引擎来补充 Twig。将两个模板引擎一起使用可能看起来很愚蠢,但是,如果你喜欢 Twig 提供的功能并更喜欢用 Jade 编写代码……嗯,我们可以做到!
设置
我们将使用标准的 Timber 配置,但将 Jade 本地编译成 Twig。人们经常将 Jade 编译成其他语法,例如 AngularJS,那么为什么不能在 Timber 中这样做呢?
以下是我们主题文件夹的结构
├── source
├── views
├── header.twade
├── index.twade
├── footer.twade
├── index.php
├── functions.php
├── style.styl
├── compiled
├── views
├── header.twig
├── index.twig
├── footer.twig
├── index.php
├── functions.php
├── style.css
├── Gruntfile.coffee
└── package.json
再次,WordPress 会尝试将 source
文件夹加载为自己的主题,除非我们在部署时将其排除。
看到那个有趣的 .twade
扩展名了吗?它们只是 Jade 文件,它们被编译(在本地使用 Grunt)成 .twig
文件,这些文件——你猜对了——被 .php
文件读取并编译成 PHP 服务器端代码。
Timber + Jade 中的 WordPress 循环
{% for post in posts %}
h1
a(href="{{post.permalink}}") {{post.title}}
{{post.get_preview}}
{% endfor %}
Timber + Jade 入门主题
下载适用于 WordPress 的 Timber + Jade 入门主题。
Timber + Jade,去掉 Twig
作为上述方法的替代方案,我们可以完全绕过 Twig,将 Jade 的模板功能与 Timber 的简单设置和功能丰富的库相结合。这与 Timber 的设置完全相同,但我们可以在 index.php
中用以下代码截取 Timber::render
。
<?php
$compiler = include 'compiler.php';
$context = Timber::get_context();
$context['pagination'] = Timber::get_pagination();
echo $compiler->render(get_template_directory() . '/views/index.jade', $context);
?>
这使我们能够以以下方式编写 WordPress 循环:
each post in posts
h1
a(href= post->permalink)!= post->title
!=post->get_preview
这是一个入门主题,用于纯 Timber + Jade 组合。
总结
模板引擎非常棒,与 WordPress 配合得很好。就哪种引擎最适合你的技能集和你要构建的网站而言,纯粹是一个个人喜好问题。
需要大量复杂视图的网站可能受益于提供更多模板逻辑的引擎,例如 Timber 或 Jade。经验丰富的 PHP 开发人员可能更喜欢 Mustache,因为它能够将所有逻辑都保留在服务器上。
我已经为这篇文章中提到的所有选项设置了入门主题。请随时使用它们来启动你自己的项目,或者只是进行实验。
主题设计愉快!
嗯,我想知道在 Handlebars 可用的情况下,是否仍然建议使用 Mustache。
无论如何,我既爱又恨 Twig。而原因是一样的!
它很强大!它太强大了!很容易依赖它来处理业务逻辑。这不是使用模板的正确方法。
这就是为什么我认为无逻辑模板引擎是最好的选择:它们可以防止你做出错误的开发选择。
关于 Jade... 我不喜欢位置语言。这主要是我个人的问题,但我更喜欢完全控制 HTML 的奇怪语法及其所有怪癖。
顺便说一句,Jade 的新官方名称是 Pug。
https://github.com/pugjs/jade/issues/2184
熟悉 Laravel Blade 吗?看看 Bladerunner!它是一个开源插件,将 Blade 实现到 WP (L5) 中。
http://bladerunner.aekab.se
我完全支持使用比 PHP 更好的模板引擎,但第一个例子似乎过于偏向 Twig。我觉得 PHP 太复杂了(为什么要使用
WP_Query
?)而 Twig 太简单了(文本翻译在哪里? 标题链接在哪里?)。以下是一个更准确的比较:PHP
Twig
再次,Twig 看起来更漂亮(for-else 折叠很好),但它不是魔法。
我使用 WordPress 已经好几年了,并且已经使用一些可用的入门选项创建了主题。我从来没有意识到这些模板语言是多么的多功能。感觉更像是编写 Ghost 主题,而不是 WordPress 主题。
我今天一直在玩 Timber 和 Twig。我通常使用 Genesis Framework 并创建子主题,但这是一个额外的选择。
我是一名 WordPress 开发人员。我从这篇关于 WordPress 模板的精彩文章中学到了很多东西。