Как подружить WordPress и Twig

Twig — компилирующий обработчик шаблонов с открытым исходным кодом, написанный на языке программирования PHP

Что такое шаблонизатор?

Шаблонизатор(в web) — программное обеспечение, позволяющее использовать html-шаблоны для генерации конечных html-страниц. Основная цель использования шаблонизаторов — это отделение представления данных от исполняемого кода. Часто это надо для обеспечения функции параллельной работы программиста и дизайнера-верстальщика. Использование шаблонизаторов часто улучшает читаемость кода и внесение изменений во внешний вид, когда проект целиком выполняет один человек.

Wikipedia

Самая важная функцию шаблонизатора это отделение представления данных от исполняемого кода. Именно этого в темах WordPress не хватает совсем. В файлах шаблонов страниц можно без труда добавить какой угодно код и это сильно соблазняет написать говнокод.

Кроме всего прочего большинство шаблонизаторов сокращают синтаксис кода.

Шаблонизаторы для PHP

На момент написания статьи самые популярные шаблонизаторы для php были:

  • Twig(Symfony)
  • Blade(Laravel)
  • Smarty(просто старый:))

Все они достаточно похожи между собой. Вы можете выбрать тот, который вам нравится больше. Мой выбор пал на Twig.

Установка и подключение twig

В теме устанавливаем twig через composer:

composer require "twig/twig:^2.0" 

Далее в functions.php где-то вначале добавляем

require_once get_template_directory(). '/vendor/autoload.php';

Использование twig-шаблонов

Для удобства я сделал абстактный класс, который дает функция работать с twig-шаблонами. Данный в конструкторе описывает как должен работать twig и в каких директориях искать шаблоны. Также он имеет в себя единственный публичный способ render, который и подключает сам шаблон.

<?phpuse Twig\Environment;use Twig\Error\LoaderError;use Twig\Error\RuntimeError;use Twig\Error\SyntaxError;use Twig\Loader\FilesystemLoader;use Twig\TwigFunction;abstract class Twig_Controller {protected $environment;public function __construct( array $directories) {$loader = new FilesystemLoader( $directories);$this->environment = new Environment( $loader, ['debug' => true]);if( current_user_can( 'administrator')) {$this->twig->addExtension( new DebugExtension());}}public function render( string $template, array $params) {echo $this->environment->render( $template. '.twig', $params);}}

Сейчас для работы с шаблонами нам необходимо просто наследовать этот Twig_Controller.

Заменить php-шаблоны на twig-шаблоны

Мы можем для этого использовать два хука template_redirect или template_include. Первый отрабатывает раньше и далее появляются данные в global $wp_query, $post и т.д. Попробуем переопределить шаблоны для всех страниц:

class Controller extends Twig_Controller {public function __construct() {parent::__construct( [ get_template_directory(). '/views/' ]);add_filter( 'template_include', [ $this, 'template_include' ]);}public function template_include( string $template) {if( is_page()) {global $post;$this->render( 'page', ['post' => $post,]);}}}

Сейчас вместо page.php будет подключаться page.twig. Как поменялся синтаксис?

Было:

<?php get_header()?><div id="primary" class="content-area"> <main id="main" class="site-main"> <div class="entry-header"> <h1><?php the_title()?></h1>        <div class="corner__bottom corner--double"></div>        </div><!--.entry-header -->        <article id="post-{{ post.ID }}" <?php post_class( $class)?>>            <div class="entry-content">                <?php the_content()?>            </div><!--.entry-content -->        </article><!-- #post-<?php the_ID() ?> -->    </main></div><?php get_footer() ?>

Стало:

{% include 'header.twig' %}<div id="primary" class="content-area">    <main id="main" class="site-main">        <div class="entry-header">            <h1>{{ post.post_title }}</h1>        </div><!-- .entry-header -->        <article id="post-{{ post.ID }}" {% do action('mx_post_class') %}>            <div class="entry-content">                {% do filter('the_content', post.post_content ) %}            </div><!-- .entry-content -->        </article><!-- #post-{{ post.ID }} -->    </main></div>{% include 'footer.twig' %}

Особо ничего не изменилось, но сейчас данные во вьюшку могут попасть только через наш контроллер. Никаких лишних данных там не будет и соответсвенно основная задача шаблонизаторов выполняется.

Все нужные данные на фронте можно без труда добавить в template_include. Т.к. наш контроллер мы добавили на хук template_include у нас есть global $wp_query, $post и остальные «прелести» WordPress’а.

Расширяем Twig под WordPress

Все же для полноценной работы не хватает хуков. Для того чтобы их добавить необходимо в twig зарегистрировать необходимые возможности.

В Twig_Controller создаем способ register_functions и вызываем его в конце конструктора:

public function register_functions() {$this->twig->addFunction( new TwigFunction( 'action', function ( $context ) {$args = func_get_args();array_shift( $args );$args[] = $context;call_user_func_array( 'do_action', $args );}, array( 'needs_context' => true ) ) );$this->twig->addFunction( new TwigFunction( 'filter', function ( $context ) {$args = func_get_args();array_shift( $args );$args[] = $context;echo call_user_func_array( 'apply_filters', $args );}, array( 'needs_context' => true ) ) );}

Конфликт версий

Будьте готовы к тому, что версия 1.x.x не совместима с версией 2.x.x. Решить проблему можно без проблем путем добавления неймспейсов в twig-шаблон и вынесением библиотеки из vendor’a. Неймспейсы можно без проблем добавить путем утилы:
https://github.com/OnTheGoSystems/twig-scoper .

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *