Шорткоды в WordPress
Шорткод (шоткод, shortcode, короткий код) в WordPress — это конструкция в тексте, которая будет обработана и заменена на указанный код/текст. Обрабатывается шорткод специальной PHP функцией, указанной при регистрации шорткода.
Shortcode API — это набор простых функций, которые позволяют разработчикам тем и плагинов создавать свои шорткоды, которые затем можно использовать в контенте для вывода готовых блоков контента. Например, это может быть форма контактов.
Для примера, следующий Шорткод (в контенте записи) добавит фотогалерею:
[gallery]
WordPress обрабатывает только зарегистрированные шорткоды.
Нельзя обрабатывать все конструкции вида [___]
, потому что они могут быть использованы в тексте, но не быть шорткодом.
Видео о шорткодах WordPress
Шорткоды WordPress из коробки
В WordPress по умолчанию регистрируются следующие шорткоды:
Синтаксис шорткода
Шорткоды WordPress используют Квадратные скобки []
, потому что они не являются частью какого-либо языка.
Синтаксис выглядит так:
[name] [name /] [name attribute="value" /] [name attr1='value1' attr2="value2" ] [name]Контент шорткода.[/name] [name attr="value"]Контент шорткода.[/name]
Есть два вида вызова:
-
«self-closing» само-закрываемый шорткод:
[name]
- без параметров.[name id="123" size="medium"]
- с параметрами.
Шорткод можно закрыть слэшем в конце (такой слэш называется self-closing маркером).
[example /]
Пробел перед маркером необязателен. Пробелы после маркера не допускаются. Такой маркер является чисто косметическим и ни на что не влияет.
-
«enclosing» - контентный шорткод:
[name]текст[/name]
- без параметров.[name size="medium"]текст[/name]
- с параметрами.
Контентные шорткоды не могут использовать self-closing маркер.
Имя шорткода
Имя шорткода не может содержать следующие символы: [ ] < > & / ' " - \x00-\x20 \s \n \t
:
- Квадратные скобки:
[]
- Угловые скобки:
< >
- Амперсанд:
&
- Косая черта:
/
- Невидимые символы:
пробел
,перевод строки
,tab
- Непечатные символы:
\x00 - \x20
- Кавычки:
' "
Тире -
разрешается в названии шорткода и оно не вызывает никаких конфликтов! Однако в официальной документации сказано что могут быть конфликты - это устаревшая информация.
Атрибуты шорткода
Атрибуты указывать не обязательно, между именем и атрибутами нужен как минимум один пробел. Если указывается несколько атрибутов, каждый атрибут должен быть разделен по крайней мере одним пробелом.
Каждый атрибут должен соответствовать одному из этих форматов:
[name attribute = 'value'] [name attribute = "value"] [name attribute = value] [name "value" "value2"] [name "value"] [name value]
Пробел допускается до и после знака =
: attr = value
, attr= value
, attr =value
.
Имя атрибута
Может содержать только следующие символы: 0-9 A-Z a-z _ -
(пробелы в именах запрещены):
- Прописные и строчные буквы:
A-Za-z
. - Числа:
0-9
. - Нижнее подчеркивание:
_
. - Дефис:
-
.
Имя атрибута может быть в любом регистре. После парсинга имя всегда будет в нижнем регистре: aTtR=value
тоже что и attr=value
.
Значение атрибута
Значение атрибута не может содержать следующие символы [ ] " '
.
Заметки по значению атрибута:
-
Кавычки атрибута. Двойные кавычки
"
допускаются внутри значений в одинарных кавычках'
и наоборот:[name foo='1 "2" 3' bar="4 '5' 6"]
-
Кавычки атрибута. Конструкция шорткода может использовать двойные или одинарные кавычки для выделения значений атрибута, или вообще их не использоваться, если в значении нет пробела.
[name foo='123' bar=456]
тоже что и[name foo="123" bar="456"]
. -
Атрибут без имени. Имя атрибута можно не указывать. В этом случае имя атрибута будет индекс массива $atts. Например
[name 123]
создаст такие параметры:$atts = array( 0 => 123 )
. Такие «позиционные» атрибуты можно использовать вместе с обычными, а кавычки можно использовать когда значение содержит пробелы или другие необычные символы. -
Квадратные скобки. Так делать нельзя:
[name foo="[value]"]
. -
Экранировать спец-символы в атрибутах можно через кодирование HTML символов (HTML encoding).
-
HTML символы
<
и>
поддерживаются в атрибутах ограничено. Например, этот шорткод не будет правильно работать, из-за символа >:[name value1="35" value2="25" compare=">"]
Версия 4.0 умеет проверять HTML, так что следующий код будет работать:
[name description="<b>Greetings</b>"]
Чтобы полностью поддерживать HTML в атрибутах можно, сначала кодировать вводимые пользователем значения, а затем декодировать при обработке.
-
Удаляемые символы. Следующие символы, если они не экранированы, будут:
- Неразрывный пробел (No-break space):
\xC2\xA0
— заменится пробелом. - Безразмерный Пробел (Zero-width space):
\xE2\x80\x8B
— удалится.
- Неразрывный пробел (No-break space):
Экранирование
Экранирование нужно, когда шорткод зарегистрирован, но его не нужно обрабатывать, а нужно показать как есть. Не зарегистрированный шорткод и так не будет обрабатываться.
Для экранирования нужно обрамить шорткод еще одними квадратными скобками:
[[name attributes]] [[name attributes]Любой HTML или Шорткоды.[/name]]
Другой вариант: заменить символы []
их HTML сущностями [ ]
. Например [name]
можно записать так: [name]
.
Вложенные шорткоды
Если в Контентном шорткоде есть вложенный шорткод, он не будет обработан. Потому что парсинг шорткодов срабатывает один раз для контента.
Пример вложенных шорткодов:
[tag_a] [tag_b size="24"] [tag_c] [/tag_b] [/tag_a]
Еще пример вложенных шорткодов:
[name]Foo: [my_name][/name]
Обработается так:
<span class="caption">Foo: [my_name]</span>
Если нужно обработать шорткод внутри шорткода, то при обработке контента первого шорткода, нужно использовать функцию do_shortcode(), чтобы обработать вложенные шорткоды.
function my_shortcode( $atts, $content ) { return '<span class="caption">' . do_shortcode( $content ) . '</span>'; }
Одинаковое название у вложенных шорткодов
Парсер не сможет обработать вложенные шорткоды с одинаковым названием, потому что уровень вложенности не подсчитывается. Такое ограничение сильно ускоряет обработку шорткодов:
[tag_a] [tag_a] [/tag_a] [/tag_a]
Как это работает
При добавлении шорткода через add_shortcode() шорткод добавляется в глобальную переменную $shortcode_tags (добавляется имя и функция-обработчик).
На хуке the_content срабатывает функция do_shortcode(), которая ищет и обрабатывает все шорткоды в контенте.
Все найденные шорткоды по-очереди передаются в функцию do_shortcode_tag(). Эта функция обрабатывает данные найденные регуляркой и вызывает добавленную в $shortcode_tags функцию-обработчик шорткода (с параметрами $attr, $content, $tag).
То что вернула функция-обработчик заменят шорткод в контенте.
До срабатывания функции do_shortcode() (до парсинга шорткодов), контент обрабатывается тремя ключевыми функциями:
add_filter( 'the_content', 'do_blocks', 9 ); add_filter( 'the_content', 'wptexturize' ); add_filter( 'the_content', 'wpautop' ); add_filter( 'the_content', 'do_shortcode', 11 ); // AFTER wpautop().
do_shortcode() парсит контент одной регуляркой get_shortcode_regex(), поэтому добавление еще одного шорткода никак не замедляет скорость обработки - регулярка все равно будет отрабатывать.
Создание шорткода
Для создания шорткода используется функция add_shortcode(). Она принимает два параметра: имя шорткода и название PHP функции, которая будет обрабатывать шорткод.
Вот самый простой PHP-код который регистрирует новый шорткод [foobar]
:
add_shortcode( 'foobar', 'foobar_shortcode' ); function foobar_shortcode( $atts ){ return 'Привет! Я шорткод.'; }
Теперь [foobar] в контенте записи изменяться на строку: «Привет! Я шорткод.»
Атрибуты шорткода
Давайте добавим поддержку атрибутов шорткоду из примера выше. Для этого используем функцию shortcode_atts():
add_shortcode( 'foobar', 'foobar_shortcode' ); function foobar_shortcode( $atts ) { $atts = shortcode_atts( [ 'name' => 'Noname', 'age' => 18, ], $atts ); return "Меня зовут {$atts['name']} мне {$atts['age']} лет"; }
Теперь [foobar name="Виктор" age="25"]
в контенте измениться на строку: «Меня зовут Виктор мне 25 лет».
shortcode_atts() определяет какие у шорткода могут быть атрибуты, задает им дефолтные значения и удаляет неопознанные атрибуты.
shortcode_atts( $defaults, $atts );
- $defaults
Ассоциативный массив который описывает возможные атрибуты шорткода (это ключи массива) и их дефолтные значения.
ВАЖНО! Ключи массива $defaults должны быть в lower-case. Не используйте camelCase или UPPER-CASE, потому что в $atts ключи всегда в lower-case.
- $atts
Неочищенный массив с данными, которые были указаны в шорткоде. Они будут сравниваться с массивом выше.
$atts будет содержать массив аргументов шорткода, которые были указанны пользователем.
Если указать значение без названия параметра, то они будут добавлены в индексные элементы массива. Например для шорткода
[name value attr="val2" val3]
получим:Array ( [0] => value [attr] => val2 [1] => val3 )
Имена атрибутов (ключи массива $atts) всегда конвертируются в lower-case (нижний регистр), значения никак не обрабатываются. Например, если мы указали шорткод так
[myshortcode FOO="BAR"]
, то в $atts получим[ 'foo' => 'BAR' ]
.
Рассмотрим еще один пример.
Пусть мы указали в контенте шорткод [myname foo="456" bar="something"]
. Тогда:
add_shortcode( 'myname', 'my_shortcode_handler' ); function my_shortcode_handler( $atts ) { /* $atts = [ 'foo' => 456, 'bar' => 'something' ] */ $data = shortcode_atts( [ 'title' => 'My Title', 'foo' => 123, ], $atts ); /* $data = [ 'title' => 'My Title', 'foo' => 456 ] */ }
Из кода видно, что приняли мы одни данные, а получили после обработки другие. Что изменилось?
- Полученное значение $atts['foo'] перезаписало значение по умолчанию.
- Полученный элемент $atts['bar'] был удален, потому что его нет в списке возможных аргументов.
- Недостающий элемент $atts['title'] был добавлен со значением по умолчанию.
Вывод функции обработчика
Возвращаемое значение функции обработчика шорткода вставляется в контент записи вместо самого шорткода.
Результат функции-обработчика шорткода всегда должен возвращаться, а не выводиться на экран. Используйте return
, а не echo
в функции обработчике.
Буферизация вывода
Если в шорткоде используется много HTML кода, то для удобства можно использовать функцию ob_start(), чтобы буферизировать вывод и затем его вернуть:
function my_shortcode(){ ob_start(); ?> <HTML> <here> ... <?php return ob_get_clean(); }
Контентные шорткоды
Примеры выше показывали как создавать «Одиночные» (self-closing) шорткоды: [name]
. Но кроме них есть еще «Контентные» (enclosing) шорткоды: [name]Контент[/name]
.
Для Enclosing шорткода функция-обработчик получит второй параметр содержащей контент.
function my_shortcode( $atts, $content )
Зарегистрированный шорткод всегда можно использовать как Одиночный или Контентный, поэтому при регистрации шорткода желательно всегда указывать значение по умолчанию для второго параметра $content.
Или можно использовать проверку empty( $content )
для разделения обработки данных Контентного и Одиночного шорткодов. Т.е. получается один шорткод можно использовать как два разных, в зависимости от того как он был использован.
Рассмотрим пример:
add_shortcode( 'name', 'my_shortcode' ); function my_shortcode( $atts, $content ) { return '<span class="caption">' . $content . '</span>'; }
Теперь если написать шорткод так:
[name]My Caption[/name]
Получим такой результат:
<span class="caption">My Caption</span>
$content передается в функцию без какой-либо очистки, поэтому в нём может быть HTML:
[name]<a href="<a class="external" href="http://example.com/" rel="nofollow">http://example.com/</a>">My Caption</a>[/name]
Получим:
<span class="caption"> <a href="http://example.com/">My Caption</a> </span>
Иногда наоборот, когда HTML недопустим нужно очищать вывод, удаляя все HTML теги функцией wp_strip_all_tags().
Атрибуты в Контентном шорткоде
В Контентном шорткоде можно также как и в Одиночном, указать атрибуты. Например разрешим атрибут class
:
function my_shortcode( $atts, $content ) { $data = shortcode_atts( [ 'class' => 'caption', ], $atts ); return '<span class="' . esc_attr( $a['class'] ) . '">' . $content . '</span>'; } /* [name class="headline"]My Caption[/name] <span class="headline">My Caption</span> */
Удаление шорткода
Для удаления (де-регистрации) используется Функция remove_shortcode( $name ).
Для удаления шорткода из контента есть функция strip_shortcodes( $content )
Удалять шорткод нужно после того как он был добавлен, поэтому вызывать эту функцию лучше во время события init.
Для примера, давайте представим что плагин регистрирует шорткод [awesome]
, а нам он мешает. Удалим его так:
add_action( 'init', 'unregister_shortcodes', 20 ); function unregister_shortcodes(){ remove_shortcode( 'awesome' ); }
Также в Shortcode API есть функция которая удаляет все зарегистрированные шорткоды разом: см. remove_all_shortcodes().
PHP Функции
add_shortcode() | Добавляет новый шоткод и хук для него. |
shortcode_atts() | Обрабатывает атрибуты (параметры) шорткода: добавляет значения по умолчанию когда нужно и удаляет неподходящие атрибуты. |
remove_shortcode() | Удаляет зарегистрированный шорткод. |
remove_all_shortcodes() | Удаляет все зарегистрированные шоткоды. |
do_shortcode() | Находит в переданном тексте зарегистрированные шорткоды и обрабатывает их. |
apply_shortcodes() | Это новое название (алиас) функции do_shortcode(). |
has_shortcode() | Проверяет есть ли в переданном тексте указанный шоткод. |
shortcode_exists() | Проверяет зарегистрирован ли указанный шоткод. |
strip_shortcodes() | Удаляет/вырезает все шоткоды из переданного текста (контента). |
Заметки
wpautop
Шорткоды обрабатываются после того, как контент записи будет обработан функцией wpautop(). Поэтому, возвращаемая строка из функции-обработчика уже не будет обрабатываться этой функцией.
wpautop() распознает зарегистрированные шорткоды и не обрабатывает их (не добавляет p или br теги вокруг или внутри).
wptexturize
Шорткоды обрабатываются после того, как контент записи будет обработан функцией wptexturize(). Она обрабатывает незарегистрированные шорткоды как обычный текст, и заменяет в нем кавычки.
Чтобы этого не происходило шорткод можно обернуть в тег <code> или <pre>. Текст внутри этих тегов wptexturize() не обрабатывает. Пример:
[name attr=“value”] <code>[name attr="value"]</code>
Или можно добавить шорткод в список не-текстурируемых шорткодов. Делается это через хук no_texturize_shortcodes.
Разные функции для одного шорткода
Если зарегистрировать два шорткода с одинаковыми названиями, но разными функциями-обработчиками, то применяться будет последняя функция. Т.е. сработает шорткод добавленный последним.
add_shortcode( 'name', 'name_shortcode' ); add_shortcode( 'name', 'noname_shortcode' ); function name_shortcode(){ return 'name shortcode'; } function noname_shortcode(){ return 'noname shortcode'; } /* [name] в контенте выведет строку "noname shortcode" */
Одна функция для разных шорткодов
add_shortcode( 'foo', 'my_function' ); add_shortcode( 'bar', 'my_function' );
Если два шорткода используют одну и туже функцию-обработчик, то в коде можно получить название (имя) текущего шорткода - оно передается в функцию-обработчик в третьем параметре:
function my_shortcode( $attr, $content, $tag ){ if( 'foo' === $tag ){ // Обработка шорткода [foo] } elseif( 'bar' === $tag ){ // Обработка шорткода [bar] } }
Смешанный вызов одного шорткода
Парсер не умеет обрабатывать смешанный вызов одно шорткода, когда он вызывается как Self-closed и Enclosing. Например:
[name attr='non-enclosing' /] просто текст [name]текст шорткода[/name]
Вместо того, чтобы распарсить эту строку как два шорткода разделенные строкой просто текст
. Парсер поймет это как единый Контентный шорткод с текстом просто текст [name]текст шорткода
.
Незарегистрированные шорткоды
Некоторые авторы плагинов не регистрируют шорткод, например, чтобы отключить вложенный шорткод до тех пор, пока не будет вызвана функция обработчика родительского шорткода. Это может привести к тому что шорткоды станут нерабочими. Например:
[tag_a unit="north"] [tag_b size="24"] [tag_c color="red"] [/tag_b] [/tag_a]
Если не регистрировать шорткоды tag_b
и tag_c
, то wptexturize() превратит код в следующий, еще до того как шорткод tag_a
будет обработан:
[tag_a unit="north"] [tag_b size=”24”] [tag_c color=”red”] [/tag_b] [/tag_a]
Незарегистрированные шорткоды будут считаться обычным текстом, который не имеет особого значения. Чтобы шорткод имел значение для wptexturize() его можно добавить в список через хук no_texturize_shortcodes:
add_shortcode( 'tag_a', 'my_tag_a_handler' ); add_filter( 'no_texturize_shortcodes', 'ignore_tag_a' ); function ignore_tag_a( $list ) { $list[] = 'tag_a'; return $list; }
Незакрытые шорткоды
В некоторых случаях анализатор шорткодов не может корректно работать с одним шорткодом, который используется как Одиночный и Контентный шорткод. Например в этом случае синтаксический анализатор будет правильно идентифицировать только второй экземпляр шорткода:
[tag] [tag] CONTENT [/tag]
Однако так проанализирует оба:
[tag] CONTENT [/tag] [tag]
Шорткод в атрибуте HTML тега
Начиная с версии 4.2.3 были наложены ограничения на использование шорткодов внутри HTML тегов. Например, следующий шорткод не будет работать корректно, поскольку он вложен в атрибут скрипта:
<a onclick="[tag]">
Обойти это можно создав шорткод, который выводит весь необходимый HTML, а не только одно значение.
[link onclick="tag"]
Тесты Shortcode API
Тесты с интересными примерами ошибок и необычного синтаксиса можно найти по этой ссылке: https://unit-tests.svn.wordpress.org/trunk/tests/shortcode.php
--