Timber 和 Twig 重新点燃我对 WordPress 的热爱

Avatar of TJ Fogarty
TJ Fogarty

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

我在职业生涯中很大一部分时间都在使用 WordPress,并从中了解到两件事:流行会导致轻视,仅仅因为其他人的批评而否定某些东西,错失了机会。

WordPress 和我一开始相处得很好,但随着时间的推移,我们变得越来越疏远。并不是我们在一起的时间越来越少,而是感觉我们只是在按部就班地进行。激情正在消退,但我仍然知道这是我工作的重要组成部分。有时需要改变,而这正是 Timber 重新将我们联系在一起的契机。

我知道 WordPress 并非对所有人或所有事物来说都是完美的工具,但还有什么工具是完美的呢?它有自己的时间和空间,我希望能够为你指明一些你可能错过的道路。

什么是 Twig?

Twig 是一种很棒的 PHP 模板语言。不要被名字迷惑;它一点也不脆弱。

如果你曾经见过任何 JavaScript 模板语言,比如 HandlebarsMoustache,那么它看起来会很熟悉。如果没有,也不要担心;Twig 非常棒,它提供了简洁、易于理解的语法来使用。看看他们主页上的这个示例

<?php echo $var ?>
<?php echo htmlspecialchars($var, ENT_QUOTES, 'UTF-8') ?>
{{ var }}
{{ var|escape }}
{{ var|e }}         {# shortcut to escape a variable #}

告诉我这没有激发你的兴奋!

要输出一个变量,你只需用双花括号括起来,省略美元符号,例如:{{ var }}。你也可以访问变量的属性,例如:{{ user.name }}

控制结构出现在 {% ... %} 块中,使用起来也很友好

{% for post in posts %}
  {{ post.title }}
{% endfor %}

你可以从他们的 文档 中了解更多信息。

想象一下,像这样编写你的 WordPress 模板…

什么是 Timber?

Timber 是将 WordPress 与 Twig 结合在一起的插件。除了使用 Twig 的好处之外,它还允许你将 PHP 与 HTML 模板分离。这反过来又为开发主题提供了更轻松的环境,我们稍后会探讨这一点。

让我们看看文档中的一个示例,然后逐步解析它

$context = Timber::get_context();
$context['post'] = new TimberPost(); // It's a new TimberPost object, but an existing post from WordPress.
Timber::render('single.twig', $context);

`single.twig` 文件

<article>
  <h1 class="headline">{{post.post_title}}</h1>
  <div class="body">
    {{post.content}}
  </div>
</article>

从 `single.php` 开始,我们首先要做的是使用 Timber::get_context(); 获取主题的上下文。这个对象将包含诸如菜单、wp_headwp_footer 之类的内容。稍后我们将看看如何添加其他内容,如果你需要在主题中全局访问其他内容。你将经常使用这行代码。

接下来,我们需要获取我们要在模板中显示的帖子。使用 new TimberPost(); 将找出要获取哪个帖子。

最后,我们想要显示一些内容。Timber 的 render 函数将调用我们的 Twig 文件并传递我们刚刚收集的数据。

最后一点爆炸性消息,我希望不要太突然:Timber 内置支持 Advanced Custom Fields。

为什么要使用 Twig?

使用 WordPress 一段时间后,你可能会发现自己难以在 PHP 和 HTML 之间混乱的舞蹈中辨别方向。这并不是说所有主题都是这样,但你可以看到这种情况很容易发生。

我发现 Timber 很棒的一点是,它通过在两者之间创造空间来缓解了这个问题。你永远不会将 PHP 与 HTML 混在一起,但它们仍然可以相互通信。你可能会发现对话更有意义,因为这使 WordPress 的最佳部分有机会闪耀。

例如,我们的 `single.php` 文件只有 3 行,而这仅仅是用来处理数据。当数据到达我们的视图时,我们很高兴知道我们拥有所需的一切 - 剩下的就是标记它。

入门

安装

所以让我们开始吧!如果你愿意,可以使用 composer 安装它,但为了简洁起见,我将通过 **插件 > 添加新插件** 安装它,并搜索 Timber 和 Twig 的关键字。或者,你可以从 插件目录 中获取它,并上传到你的网站。

入门主题

Timber 带有一个基础入门主题,非常适合快速上手。安装插件后,你会发现以下文件夹,可以将其复制到你的主题文件夹中。它应该位于 `wp-content/plugins/timber/timber-starter-theme` 中。或者,如果你只是想看一看,可以 浏览入门主题存储库

你会注意到,乍一看这里没有什么不寻常的地方。魔法在哪里?在这一点上感到担忧是正常的,所以让我们深入研究一下。

functions.php

`functions.php` 文件的用途在很大程度上保持不变。你可以像往常一样使用它,无论是声明自定义帖子类型,还是定义自定义函数。但是,使用 Timber Starter Theme,你会注意到其中有一个类声明在等待。这个类最值得注意的方法是 add_to_context

从这里我们可以添加我们希望在整个主题中访问的项目。例如,如果我在管理面板中创建了一个名为 primary-menu 的菜单,我可以将其添加到全局上下文中,如下所示

$context['primary_menu'] = new TimberMenu('primary-menu');

现在我可以像这样访问它

<nav role="navigation">
  <ul>
  {% for item in primary_menu.get_items %}
    <li class="{{item.classes | join(' ')}}">
      <a href="{{item.get_link}}">{{item.title}}</a>
    </li>
  {% endfor %}
  </ul>
</nav>

还不错吧!另一个我想分享的例子是使用 多环境配置 之类的东西。这将创建一个常量来表示当前环境,例如开发、预发布或生产。我可以通过将以下内容添加到 add_to_context 方法中,轻松地将这些信息提取到我的主题中

$context['env'] = WP_ENV;

在我的模板中,我可以调用 {{ env }} 来告诉我我的网站正在运行哪个环境。

扩展和块

让我们看看 `index.php`。

$context = Timber::get_context();
$context['posts'] = Timber::get_posts();
$templates = array( 'index.twig' );
if ( is_home() ) {
  array_unshift( $templates, 'home.twig' );
}
Timber::render( $templates, $context );

好的,我们之前已经看到过大部分内容。这里有一些额外的内容,比如有一个模板数组。所有这些操作只是在 is_home() 返回 true 时将 `home.twig` 添加到数组的开头。

假设 is_home() 返回 false,那么它将告诉它渲染 `index.twig`。Twig 文件位于 `views` 目录中,所以我们将从那里开始,在我们的 `index.twig` 文件中

{% extends "base.twig" %}

{% block content %}
  {% for post in posts %}
    {% include 'tease.twig' %}
  {% endfor %}
{% endblock %}

这里要介绍几个新内容,分别是 extendsblock。如果你不确定它们的功能,我相信你很快就会明白的。

当我们调用 extends 时,我们表示“对我在这个模板中声明的任何内容使用此布局”。然后在 `base.twig` 中,你会看到这样的内容

<!doctype html>
<html>
  <head>
  ...
  </head>
  <body>
  ...
  {% block content %}
    No content found!
  {% endblock %}
  </body>
</html>

通常在 WordPress 中,我们可能只是在每个模板中包含页脚和页眉,但在这里它们都在同一个文件中,我们告诉我们的模板进行扩展。

你可以随意命名你的块。那串“未找到内容!” 只有在 content 块中没有提供任何内容时才会显示。在 Timber Starter Theme 中,你会看到他们为页眉和页脚的部分声明了额外的块,但重要的是使用对你来说有意义的东西。

自定义模板

说够了,现在该自己动手做模板了!本教程将使用Advanced Custom Fields,以及 Timber + Twig 的一些额外功能,肯定会让你感到满意。

我们将创建一个非常简单的示例页面,该页面包含一个横幅图像,一些文字横跨其上。如果需要,这是一个英雄元素。我们的英雄将向我们展示 Twig 的表现力,并挑战我们对 WordPress 的认知模型。我们假设我们的英雄元素已使用 Advanced Custom Fields 定义。您可以使用以下方法调用自定义字段:post.get_field('field_name');。如果您使用的是 WordPress 自己的自定义字段,则可以像这样使用:post.field_name

两种方法可以创建自定义页面模板,由于在我的情况下,我并不总是知道最终的 URL,所以我将采用“自定义 PHP 文件”的方法。最后,让我们开始输入内容吧!

base.twig

对于我们的基本布局,我将 Timber 的入门主题布局文件与 HTML5 Boilerplate 的 index 文件结合起来

<!doctype html>
<html class="no-js" {{site.language_attributes}}>
  <head>
    <meta charset="{{site.charset}}">

    <title>   
      {% if wp_title %}
        {{ wp_title }} - {{ site.name }}
      {% else %}
        {{ site.name }}
      {% endif %}
    </title>
    
    <meta name="description" content="{{site.description}}">
    
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <link rel="stylesheet" href="{{ site.theme.link }}/style.css">
  </head>
  <body>
    
    <nav role="navigation">
      <ul>
        {% for item in primary_menu.get_items %}
          <li class="nav-item {{item.classes | join(' ')}}">
            <a class="nav-link" href="{{item.get_link}}">{{item.title}}</a>
          </li>
        {% endfor %}
      </ul>
    </nav>
      
    <div class="wrapper">
      {% block content %}
       No content found!
      {% endblock %}
    </div>

  </body>
</html>

调用{{ site.theme.link }}会非常有用,如果您使用的是 Wiredep + Gulp,您可以查看此代码段,了解如何将其融入您的工作流程。

自定义模板文件

如我们已经看到,您的 PHP 文件将非常简单。在your-custom-page.php中几行代码就足够了

<?php
/*
 * Template Name: Your Custom Page
 */

$context = Timber::get_context();
$post = new TimberPost();
$context['post'] = $post;
Timber::render( 'your-custom-page.twig', $context );

这就是我们所需要的!我们的英雄your-custom-page.twig文件在等着我们…

{% extends 'base.twig' %}

{% block content %}

<section>
  <h1>{{ post.get_field('hero_title') }}</h1>
  
  <img src="{{ TimberImage(post.get_field('hero_image')).src }}" alt="{{ TimberImage(post.get_field('hero_image')).alt }}">
</section>

{% endblock %}

我们在这里使用TimberImage来获取有关图像所需的信息。在这种情况下,它是 URL 和 alt 文本。

我们可以将其保留在那里… 但既然我们已经开始行动了,我们将利用resize过滤器。它需要 3 个参数:宽度、高度和裁剪。我们只指定宽度。

让我们重构我们的英雄图像,使其更具响应性

<img alt="{{ TimberImage(post.get_field('hero_image')).alt }}"
  srcset="
    {{ TimberImage(post.get_field('hero_image')).src | resize(1600)}} 1600w,
    {{ TimberImage(post.get_field('hero_image')).src | resize(1000)}} 1000w,
    {{ TimberImage(post.get_field('hero_image')).src | resize(700)}} 700w
 "
  src="{{ TimberImage(post.get_field('hero_image')).src | resize(1000)}}"
  sizes="100vw"
>

是的,您可以做到。

结论

WordPress 有很多东西可以提供,我承认自己一直把它当作理所当然。热爱你的工作本身就是一种回报,我认为花点时间用新的方式来处理某件事,是一个培养新技能和重新激发动力的绝佳机会。我无法告诉你我用 WordPress 构建了多少网站,但我可以告诉你我第一次使用 Timber 时,我的思想发生了怎样的改变。

资源