Верх страницы
Обложка к записи Как подружить WordPress и Twig
Время для прочтения: 2 мин. 5 сек.

Как подружить 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, который и подключает сам шаблон.

<?php

use 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.

Автор: Кобзарёв Михаил

Русский разработчик с 20-ти летним стажем. Работаю с PHP, ООП, JavaScript, Git, WordPress, Битрикс, Joomla, Drupal, OpenCart, DLE, Laravel, Moonshine, Symfony, SuiteCRM.

Оптимизирую сайты под Google Page Speed, настраиваю импорты для больших магазинов на WooCommerce + WP All Import. Пишу плагины на заказ. Все мои услуги.

Веду блог о разработке, дайджест в телеграмме и в ВК.

Вы всегда можете нанять меня.

Комментарии
Подписаться
Уведомить о
guest

9 комментариев
Межтекстовые Отзывы
Посмотреть все комментарии
Андрей
Андрей
3 лет назад

Не понял, где создавать Twig_Controller?
Потом его наследование тоже

Андрей
Андрей
3 лет назад
Ответить на  Кобзарёв Михаил

А что при этом остается в index.php? В нем нужно ссылаться на файлы шаблона? И, если я правильно понимаю, консоль ошибок уже встроена или? Как дебаг включить? И еще неясно какими переменными оперировать вместо родных вордпрессовских.

Андрей
Андрей
3 лет назад

Еще вопрос )). Откуда взяться конфликту версий, если твиг, по умолчанию, второй версии устанавливается?

Александр
Александр
3 лет назад

Добрый день.

Появился вопрос. при рендере шаблонов заметил одну особенность, в function.php объявил ряд констант (префикс темы, версия темы и прочее, путь к статике(js,css)).

Но в шаблонах эти константы не видны — выводит null (но при этом, если в page.php прописать var_dump(PREFIX_THEME) все отлично выводится.

Могу предположить, что это связанно с тем, что в методе template_include передается только: global $post.

Не подскажите, как пофиксить данный баг?

Александр
Александр
3 лет назад
Ответить на  Кобзарёв Михаил

Михаил, не могли бы показать на примере, хотя бы самом простеньком или ткнуть в документацию.

Дело в том, что с твигом только только начал знакомится. И документации по настройке твига с WP почти нет(

Предыдущая запись
Следующая запись

Давайте дружить
в Telegram

Авторский блог вашего покорного слуги в Telegram про web, программирование, алгоритмы, инструменты разработчика, WordPress, Joomla, Opencart, Laravel, Moonshine, фильмы и сериалы