WordPress как на ладони

Шорткоды в 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 — удалится.

Экранирование

Экранирование нужно, когда шорткод зарегистрирован, но его не нужно обрабатывать, а нужно показать как есть. Не зарегистрированный шорткод и так не будет обрабатываться.

Для экранирования нужно обрамить шорткод еще одними квадратными скобками:

[[name attributes]]

[[name attributes]Любой HTML или Шорткоды.[/name]]

Другой вариант: заменить символы [] их HTML сущностями &#91; &#93;. Например [name] можно записать так: &#91;name&#93;.

Вложенные шорткоды

Если в Контентном шорткоде есть вложенный шорткод, он не будет обработан. Потому что парсинг шорткодов срабатывает один раз для контента.

Пример вложенных шорткодов:

[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=&#8221;24&#8221;]
	  [tag_c color=&#8221;red&#8221;]
   [/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

--

9 комментариев
    Войти