使用模板引擎简化 WordPress 主题开发

Avatar of Charlie Walter
Charlie Walter

DigitalOcean 为您旅程的每个阶段提供云产品。 立即开始使用 200 美元的免费积分!

以下是来自 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 文件编写的,并保存在其中。 使用 Gruntgrunt-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())来重复使用模板。 这对于维护来说不是问题,但在性能方面,我们将加载本可以缓存的代码。

我个人将文件结构化为在项目中创建 sourcecompiled 文件夹,以便将所有源文件与编译后的版本分开。 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

下载适用于 WordPress 的 Jade 启动主题。

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,因为它能够将所有逻辑都保留在服务器上。

我已经为这篇文章中提到的所有选项设置了入门主题。请随时使用它们来启动你自己的项目,或者只是进行实验。

主题设计愉快!