В этом уроке я собираюсь объяснить технику, которая позволяет вам использовать файл шаблона для всех ваших потребностей HTML! Вам больше не нужно будет «выводить» строки из ваших функций или беспокоиться о том, чтобы вставлять и выключать PHP только для того, чтобы вывести некоторую разметку.
Я провел много лет, используя MVC-фреймворки (такие как Zend и в настоящее время Laravel), где лучше всего отделить вашу «логику программирования» (функции или методы) от вашего «представления» (итоговой разметки HTML). Это всегда приводит к созданию более удобной базы кода, и на самом деле ее гораздо проще писать. Наличие этого фона побудило меня придумать подобное решение при разработке плагинов для WordPress! Ничего особенного — это всего лишь маленький «помощник», который позволит вам удалить все фрагменты HTML-кода и неудобно «убегать» из ваших функций и безопасно поместить их в свой собственный файл «шаблона».
Итак, я надеюсь, что этот урок звучит интересно для вас, и без лишних слов, давайте начнем!
Шаг 1 Понимание того, что мы собираемся улучшить
Давайте начнем этот урок, посмотрев, что именно мы собираемся улучшить.
Очень часто можно увидеть что-то подобное в плагине: (этот фрагмент взят из одного из моих учебных пособий на этом сайте: p)
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
add_shortcode( ‘faq’, function() {
$posts = get_posts( array( // Get the FAQ Custom Post Type
‘numberposts’ => 10,
‘orderby’ => ‘menu_order’,
‘order’ => ‘ASC’,
‘post_type’ => ‘faq’,
));
$faq = ‘<div id=»wptuts-accordion»>’;
foreach ( $posts as $post ) { // Generate the markup for each Question
$faq .= sprintf( ( ‘<h3><a href=»»>%1$s</a></h3><div>%2$s</div>’ ),
$post->post_title,
wpautop( $post->post_content )
);
}
$faq .= ‘</div>’;
return $faq;
});
|
Что с этим не так?
Ну ничего, правда. Но это может быть чище, легче масштабировать и более легко обслуживать!
Работая сверху вниз, мы видим, что все в одной функции:
- Запрос к базе данных для сообщений определенного типа
- Присвоение строки HTML переменной
- Выполнение цикла и конкатенация дальнейшей разметки в строку
- Возврат созданной строки
Теперь вы вполне можете посмотреть на это и подумать: «Большое дело! Это всего лишь несколько строк HTML, в чем проблема?» В некоторых отношениях у вас есть право думать так. Но помните, на данный момент всего 17 строк кода — что происходит, когда вы расширяете / улучшаете плагин? Что происходит, когда ваш плагин увеличивается до 50/100/1000 строк кода (или больше!). Будете ли вы все еще счастливы, если HTML-строки будут разбиты вокруг вашей функции в разных местах? Что происходит, когда вы хотите вывести некоторый HTML, который нуждается в некотором неловком «экранировании» для правильной работы в вашем PHP-коде?
Надеюсь, вы видите, что такой подход к созданию и выводу HTML-разметки может стать очень проблематичным! Не говоря уже о том, что становится очень сложно поддерживать и улучшать HTML, когда он просто разбросан.
Итак, учитывая все это, я взял на себя сменить способ вывода HTML в WordPress. Навсегда.
Шаг 2 Создание плагина View Renderer
Хорошо, давайте разберемся с этим.
Создайте файлы и папки
- Создайте новую папку плагинов с именем View
- Внутри этой папки создайте файл плагина view_renderer.php
- Теперь создайте файл с именем View.php — это будет наш класс
Включить класс
Наш плагин прост, он просто включает в себя класс View
чтобы мы могли использовать его в любом из наших других плагинов.
1
2
3
|
/* view_renderer.php */
include(‘View.php’);
|
Хорошо, теперь, когда мы включили класс View
, пришло время его создать.
Класс просмотра
Здесь у нас есть класс View
с единственной статической функцией render
(это позволит нам использовать синтаксис View::render( $template )
из любого места в наших плагинах), и он принимает два параметра:
-
$filePath
— путь к файлу шаблона. Не забывайте, что мы собираемся сохранить наши шаблоны в папке View, которую мы создали ранее -
$viewData
— Любые переменные, к которым мы хотели бы иметь доступ внутри шаблона (подробнее об этом позже)
Скопируйте приведенный ниже код в View.php :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
<?php
/** View.php **/
class View {
/**
* ————————————-
* Render a Template.
* ————————————-
*
* @param $filePath — include path to the template.
* @param null $viewData — any data to be used within the template.
* @return string —
*
*/
public static function render( $filePath, $viewData = null ) {
// Was any data sent through?
( $viewData ) ?
ob_start();
include ( $filePath );
$template = ob_get_contents();
ob_end_clean();
return $template;
}
}
?>
|
Так что же здесь происходит?
-
Прежде всего мы проверяем, имеет ли
$viewData
viewData значение (т.$viewData
Отправили ли мы что-нибудь для использования в шаблоне?). Если это произойдет, мы извлекаем содержимое (подробнее об этом позже) -
Затем мы используем выходной буфер PHP. Это позволяет нам анализировать файл PHP и сохранять содержимое в переменную
-
Наконец мы возвращаем строку
Примечание: не забудьте активировать плагин сейчас из панели администратора
Кажется довольно просто, да? Точно! Но хотя это, кажется, очень простая маленькая функция, на самом деле она дает нам возможность писать наши плагины суперорганизованным, масштабируемым и поддерживаемым способом. Пожалуйста, позвольте мне продемонстрировать …
Шаг 3 Пример из реального мира
Давайте создадим простой плагин под названием Slider
** Примечание: это только для демонстрационных целей. Не стесняйтесь использовать свой собственный плагин здесь.
- Создайте папку с именем Slider
- В этой папке создайте файл с именем Slider.php
- Скопируйте приведенный ниже код в Slider.php
01
02
03
04
05
06
07
08
09
10
|
<?php
/*
Plugin Name: Slider
Plugin URI: http://wp.tutsplus.com
Description: Generic Slider plugin to demonstrate View Renderer.
Author: Shane Osbourne
Version: 0.1
Author URI: http://wp.tutsplus.com/author/shaneosbourne/
*/
?>
|
Добавить шорткод
Хорошо, теперь мы собираемся добавить шорткод, который будет извлекать последние 5 сообщений и отображать их в списке с заголовком и содержимым. (Для краткости мы добавим наш класс плагина и наши хуки действий в один и тот же файл плагина, но, пожалуйста, не делайте этого в «реальной жизни»: p)
1
2
3
4
5
6
7
8
|
/**
* Add the Shortcode (PHP 5.3 and above)
*/
add_shortcode( ‘slider’, function() {
return Slider::display();
} );
|
Это позволит нам просто использовать [slider]
в любом сообщении / странице и вывести результат Slider::display()
Добавьте метод Slider Class & display()
1
2
3
4
5
6
7
8
|
class Slider {
public static function display() {
// Return HTML HERE.
}
}
|
Получите последние 5 сообщений.
1
2
3
4
5
6
7
8
|
/*
* Get the latest 5 posts
*/
public static function display() {
$posts = get_posts( array( ‘numberposts’ => 5 ) );
}
|
Теперь у нас есть массив объектов post
и мы готовы создавать наш HTML, проходя через них. Но мы не собираемся просто начинать вставлять HTML-строки в нашу функцию здесь! Вместо этого мы собираемся передать массив объектов в файл шаблона и сгенерировать весь HTML без риска.
Создать шаблон
- Создайте папку с именем templates
- Внутри этой папки создайте файл с именем 01.template.php
Этот шаблон будет содержать всю нашу разметку и позволит нам получить доступ к данным, которые мы отправим ему позже.
Отправка данных в шаблон
Каждый раз, когда мы хотим использовать какие-либо переменные в наших шаблонах, мы можем просто отправить их, установив значение в массиве $viewData
. Любой, кто знаком с использованием сред MVC, будет чувствовать себя как дома с таким подходом.
1
|
$viewData = array( ‘posts’ => $posts );
|
Ключ массива здесь (‘ posts
‘) важен, потому что именно так мы будем ссылаться на данные внутри шаблона. (Вы можете называть это как хотите, но придерживайтесь того, что имеет смысл.)
Создание шаблона
Итак, мы рассмотрели, как извлечь последние 5 сообщений и как отправить этот массив объектов в шаблон, теперь пришло время конкретизировать файл шаблона.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
<div>
<ul>
<?php foreach ($posts as $post ) : ?>
<!— Loop —>
<li>
<h1><?= $post->post_title ?></h1>
<p><?= $post->post_content ?></p>
</li>
<!— Loop End —>
<?php endforeach;
</ul>
</div>
|
Ах! Насколько приятно иметь всю эту разметку в отдельном файле, вне нашей логики поиска и программирования данных? Отлично, я знаю! Наиболее важной частью этого подхода является то, что мы когда-либо «обращаемся» к данным только из переменных в шаблоне. Вся «логика» должна выполняться внутри метода, который вызывает шаблон. Это приводит к очень приятному рабочему процессу, поскольку у вас есть полное разделение проблем .
Представьте, как легко будет сейчас, когда вы будете готовы использовать этот плагин. Больше не нужно объединять строки и экранировать символы внутри функций.
Возврат обработанного шаблона
Хорошо, мы рассмотрели все составные части, давайте посмотрим, как все это сходится, чтобы позволить нам визуализировать шаблон и вернуть строку (которую мы затем можем вернуть к нашему шорткоду):
- Сначала нам нужно сохранить ссылку на наш шаблон в статическом свойстве
- Затем нам нужно проверить, что класс
View
существует - Затем мы генерируем полный путь к нашему файлу шаблона, захватывая ссылку на текущий каталог плагина и конкатенируя наше статическое свойство
$template
- Наконец, мы вызываем наш метод
View::render()
и передаем ему два необходимых параметра
В этом случае мы возвращаем результат обработанного шаблона, потому что так работают шорткоды . Но если вместо этого вам нужно было отобразить результаты (например, когда вы создаете страницу администратора, обратный вызов ожидает, что ваш вывод будет распечатан напрямую), просто замените return на echo .
Метод display()
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
class Slider {
static $template = ‘/templates/01.template.php’;
public static function display() {
if ( class_exists( ‘View’ ) ) {
// Get the last 5 posts
$posts = get_posts( array( ‘numberposts’ => 5 ) );
// Set view Data
$viewData = array(
‘posts’ => $posts
);
// Get the full path to the template file.
$templatePath = dirname( __FILE__ ) .
// Return the rendered HTML
return View::render( $templatePath, $viewData );
}
else {
return «You are trying to render a template, but we can’t find the View Class»;
}
}
}
|
Я надеюсь, что вы сможете оценить уровень организации, который вам даст такой подход! Теперь ваша функция отображения отвечает только за сбор необходимых данных и возврат результата обработанного шаблона.
Продолжая
Наш пример выше настолько же прост, насколько это возможно. Несмотря на это, это все еще значительно улучшенный рабочий процесс. Теперь давайте посмотрим на другой пример, который показывает, насколько он может быть полезным.
Скажем, например, ваш плагин использует собственный мета-блок. Для этого нам необходимо:
- Добавьте функцию конструктора в класс
Slider
- Добавить метод для добавления метабокса к каждому сообщению
- Добавьте метод обратного вызова, чтобы отобразить HTML для мета-блока
- Добавьте соответствующий хук в файл плагина, чтобы создать экземпляр класса только при добавлении / редактировании сообщений
- Наконец, мы добавим файл шаблона, как мы делали ранее, и добавим его как свойство в начале класса
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
class Slider {
static $metaBox = ‘/templates/metabox.template.php’;
public function __construct() {
add_action( ‘add_meta_boxes’, array( $this, ‘add_some_meta_box’ ) );
}
/**
* Adds the meta box container
*/
public function add_some_meta_box() {
add_meta_box(
‘some_meta_box_name’,
‘Some Meta Box Headline’,
array( $this, ‘render_meta_box_content’ ),
‘post’,
‘advanced’,
‘high’,
);
}
/**
* Render Meta Box content
*/
public function render_meta_box_content() {
/** From the Codex **/
echo ‘<h1>TEST OUTPUT — this gets rendered inside the meta box.</h1>’;
}
} // class
// add the action hook
function call_Slider() {
return new Slider();
}
if ( is_admin() )
add_action( ‘load-post.php’, ‘call_Slider’ );
|
Взгляните на метод render_meta_box_content
там. Это прекрасная возможность использовать View Renderer! Представьте себе более реалистичный пример, подобный этому:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
/**
* Render Meta Box content
*/
public function render_meta_box_content( $post ) {
$name = get_post_meta( $post->ID, «name» );
$fieldName = static::$fieldName;
echo ‘<h3>Your name: </h3>’;
echo ‘<label for=»‘ . $fieldName . ‘»>Name: </label>’;
echo ‘<input id=»‘ . $fieldName . ‘» name=»‘ . $fieldName . ‘» value=»‘ . $name . ‘» placeholder=»Enter your name here» />’;
echo ‘<button class=»button»>Update</button>’;
}
|
Urg! Конечно, он выполняет свою работу, но так сложно это сделать! Как насчет того, чтобы вместо этого мы использовали наш View Renderer?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
/**
* Render Meta Box content
*/
public function render_meta_box_content( $post ) {
$viewData = array(
‘name’ => get_post_meta( $post->ID, ‘name’ ),
‘field’ => static::$fieldName
);
$templatePath = dirname( __FILE__ ) .
echo View::render( $templatePath, $viewData );
}
|
И в файле шаблона:
1
2
3
4
|
<h3>Your name: </h3>
<label for=»<?= $field ?>»>Name: </label>
<input id=»<?= $field ?>» name=»<?= $field ?>» value=»<?= $name ?>» placeholder=»Enter your name here» />
<button class=»button»>Update</button>
|
В этом примере это может показаться очень небольшим преимуществом. Но поверьте мне, если вы будете таким образом разделять свои интересы, вы очень быстро станете гораздо лучшим разработчиком WordPress.
Вывод
Я думаю, что к настоящему времени у вас, вероятно, есть хорошее понимание того, чего мы пытаемся достичь здесь, и я призываю вас попробовать использовать эту технику при создании плагинов в будущем. Надеюсь, вы найдете «разделение интересов» полезным для вас.
Примечания к учебнику:
- Хотя мы превратили View Renderer в плагин, вы можете легко добавить его в существующие плагины. Это избавит вас от необходимости убедиться, что плагин активирован, прежде чем использовать его где-либо.
- Вы не ограничены сценариями использования, описанными в этом руководстве, его можно использовать везде, где вы обычно выводите HTML (как насчет использования файла шаблона для вывода некоторого встроенного JavaScript-кода или как-то по конкретным правилам CSS, основанным на варианты извлекаются из базы данных?)
Мне было бы интересно узнать, какие применения вы нашли для этой техники, поэтому, пожалуйста, поделитесь в комментариях 🙂