oEmbed в WordPress
oEmbed — это открытый формат, созданный для упрощения встраивания содержимого одной веб-страницы в другую. В роли контента могут выступать: фотографии, видеоролики, ссылки и другие типы контента.
oEmbed контент — это видео, аудио, HTML и другие коды на вашем сайте, которые были встроены из другого сайта. Например, если в WP вставить ссылку на видео youtube она превратиться в iframe с видео роликом.
Читайте также: Шорткоды в WordPress.
Как это работает
В основе работы класса WP_Embed{} лежит класс WP_oEmbed{} - именно он содержит список зарегистрированных oEmbed провайдеров и он занимается запросом (получением), обработкой Discovery ссылки в head части HTML.
На очень ранней стадии еще до хука mu_plugin_loaded инициализируется класс WP_Embed:
$GLOBALS['wp_embed'] = new WP_Embed();
В конструкторе WP_Embed::__construct() создаются следующие хуки:
function __construct() {
// Hack to get the [embed] shortcode to run before wpautop().
add_filter( 'the_content', array( $this, 'run_shortcode' ), 8 );
add_filter( 'widget_text_content', array( $this, 'run_shortcode' ), 8 );
// Shortcode placeholder for strip_shortcodes().
add_shortcode( 'embed', '__return_false' );
// Attempts to embed all URLs in a post.
add_filter( 'the_content', array( $this, 'autoembed' ), 8 );
add_filter( 'widget_text_content', array( $this, 'autoembed' ), 8 );
// After a post is saved, cache oEmbed items via Ajax.
add_action( 'edit_form_advanced', array( $this, 'maybe_run_ajax_cache' ) );
add_action( 'edit_page_form', array( $this, 'maybe_run_ajax_cache' ) );
}
Обработка oEmbed URL на фронте
Контент записи или виджета text проверяется на наличие шоткода [embed] или на наличие URL на отдельной строке. Для этого, как видно из кода выше, на хуке the_content запускаются два метода:
-
WP_Embed::run_shortcode( $post_content ) — обрабатывает шоткод
[embed]. -
WP_Embed::autoembed( $post_content ) — обрабатывает URL (на отдельной строке), как шорткод
[embed].Далее каждый найденный URL (на отдельной строке или в шорткоде) передается в метод WP_Embed::shortcode( $attr, $url ). Далее:
-
Проверяется внутренний обработчик | Embed
URL передается в метод WP_Embed::get_embed_handler_html( $rawattr, $url ). Этот метод проверяет переданный URL, на внутренние обработчики, которые регистрируются функцией wp_embed_register_handler().
- Если обработчик найден, то URL передается в функцию-обработчик и результат возвращается. Работа метода WP_Embed::shortcode() на этом прекращается.
- Если обработчик не найден, то WP_Embed::shortcode() продолжает проверку oEmbed (внешних) обработчиков.
-
Проверяется внешний обработчик | oEmbed
- Если для URL есть кэш, то парсинг прерывается - результат берется из кэша.
-
Если кэша нет, то URL передается в функцию wp_oembed_get( $url, $attr ), затем в метод WP_oEmbed::get_provider(), далее с этим URL сравниваются все зарегистрированные провайдеры (WP_oEmbed::$providers) и если есть совпадение, делается запрос чтобы получить oEmbed вставку с другого сайта (за этот запрос отвечает класс WP_oEmbed). В конце, неважно какой результат, обработка URL кэшируется.
При таком варианте кэш создается только при первом запросе (когда его нет) и он не обновляется. Обновление кэша происходит только при обновлении записи в админке.
-
Обработка oEmbed URL в админке
Также oEmbed кэш создается и (важно) обновляется при обновлении записи на странице редактирования записи в админке. Делается это AJAX запросом. Создается такой AJAX запрос только в момент обновления записи в адмнике - см. WP_Embed::maybe_run_ajax_cache().
- wp_ajax_oembed_cache()
- WP_Embed::cache_oembed( $post_id )
- Далее, обработка идет по описанный выше схеме, контент поста передается в методы: WP_Embed::run_shortcode( $post_content ) и WP_Embed::autoembed( $post_content ).
- WP_Embed::cache_oembed( $post_id )
Для примера, рассмотрим как WordPress обрабатывает ссылки на другие сайты на WordPress, чтобы встроить контент другого сайта. Общий принцип всего этого описан выше, а ниже рассмотрим как это работает в админке.
Блочный редактор
При вставке ссылки в блочный редактор срабатывает js событие, отправляющее ajax запрос методом GET на роут домен/wp-json/oembed/1.0/proxy, который регистрирует метод WP_oEmbed_Controller::register_routes(). Пример отправляемых данных:
url: https://oddstyle.ru/instrukciya-po-rabote-s-wordpress-rukovodstvo-dlya-novichkov _locale: user
Ответ генерирует метод WP_oEmbed_Controller::get_proxy_item():
{
"version":"1.0",
"provider_name":"Блог про WordPress",
"provider_url":"https://oddstyle.ru",
"author_name":"Дмитрий",
"author_url":"https://oddstyle.ru/author/admin",
"title":"Инструкция по работе с WordPress. Руководство для новичков",
"type":"rich",
"width":600,
"height":338,
"html":"
<blockquote class=\"wp-embedded-content\" data-secret=\"X2b9CmjdiG\">
<a href=\"https://oddstyle.ru/instrukciya-po-rabote-s-wordpress-rukovodstvo-dlya-novichkov\">Инструкция по работе с WordPress. Руководство для новичков</a>
</blockquote>
<iframe
class=\"wp-embedded-content\"
sandbox=\"allow-scripts\"
security=\"restricted\"
style=\"position: absolute; clip: rect(1px, 1px, 1px, 1px);\"
title=\"«Инструкция по работе с WordPress. Руководство для новичков» — Блог про WordPress\"
src=\"https://oddstyle.ru/instrukciya-po-rabote-s-wordpress-rukovodstvo-dlya-novichkov/embed#?secret=X2b9CmjdiG\"
data-secret=\"X2b9CmjdiG\"
width=\"600\"
height=\"338\"
frameborder=\"0\"
marginwidth=\"0\"
marginheight=\"0\"
scrolling=\"no\"
></iframe>
"
}
Данные кешируются в таблицу *_options.
Визуальный редактор
При использовании визуального редактора при вставки ссылки срабатывает JS событие, запускающее ajax запрос методом post на файл admin-ajax.php, где на хуке wp_ajax_parse_embed отрабатывает одноимённая функция wp_ajax_parse_embed().
Пример отправляемых данных:
post_ID: 31 type: embed shortcode: [embed]https://oddstyle.ru/instrukciya-po-rabote-s-wordpress-rukovodstvo-dlya-novichkov[/embed] maxwidth: 549 action: parse-embed
Содержимое поля shortcode передаётся в WP_Embed::run_shortcode(). Что происходит дальше читайте выше в секции "Как это работает".
Пример возвращаемых данных:
{
"success":true,
"data":{
"body":"
<blockquote class=\"wp-embedded-content\" data-secret=\"mf3DjZabsV\">
<a href=\"https://oddstyle.ru/instrukciya-po-rabote-s-wordpress-rukovodstvo-dlya-novichkov\">Инструкция по работе с WordPress. Руководство для новичков</a>
</blockquote>
<iframe
class=\"wp-embedded-content\"
sandbox=\"allow-scripts\"
security=\"restricted\"
style=\"position: absolute; clip: rect(1px, 1px, 1px, 1px);\"
title=\"«Инструкция по работе с WordPress. Руководство для новичков» — Блог про WordPress\"
src=\"https://oddstyle.ru/instrukciya-po-rabote-s-wordpress-rukovodstvo-dlya-novichkov/embed#?secret=mf3DjZabsV\"
data-secret=\"mf3DjZabsV\"
width=\"549\"
height=\"309\"
frameborder=\"0\"
marginwidth=\"0\"
marginheight=\"0\"
scrolling=\"no\"
></iframe>
",
"attr":{
"width":549,
"height":824
},
"head":"<script src=\"https://wp-test.ru/wp-includes/js/wp-embed.js\"></script>",
"sandbox":true
}
}
Данные кешируются в таблицу wp_postmeta или wp_posts.
Кэширование oEmbed запроса
Для кэширования запросов могут быть использованы метаполя записи (поста) или таблица wp_posts.
Если шоткод или ссылка вызывается из контента поста, то кэш будет сохраняться в метаполя текущей записи.
Если текущий записи нет, то кэш будет сохраняться в таблицу wp_posts под типом записи oembed_cache.
Кэш актуален 1 день (86400 секунд). Это значение можно изменить через хук oembed_ttl.
ВАЖНО! Проверка времени жизни и обновление кэша происходит только при обновлении записи со страницы редактирования записи в админке. С фронта кэш не обновляется. Запуск обновления кэша в админке инициализируют эти хуки:
add_action( 'edit_form_advanced', array( $this, 'maybe_run_ajax_cache' ) ); add_action( 'edit_page_form', array( $this, 'maybe_run_ajax_cache' ) );
Если по какой-то причине не удалось получить HTML встраивания, например вернулся 404 ответ или другой отличный от 200, то в кэш вместо html, будет добавлен маркер {{unknown}}.
oEmbed Безопасность
Встраивание чужого кода на свой сайт открывает возможность XSS атаки. Так, например, полученный код может содержать хакерский код, который может получить куки вашего сайта да и вообще, может делать кучу всего.
Чтобы обезопасить себя от подобного рода дыр в безопасности, WordPress выводит встраивание в теге <iframe>. А также очищает полученный код iframe от нежелательных атрибутов. В частности код встраивания допускает следующие HTML теги, которые проверяются функцией wp_kses():
$allowed_html = array( 'a' => array( 'href' => true, ), 'blockquote' => array(), 'iframe' => array( 'src' => true, 'width' => true, 'height' => true, 'frameborder' => true, 'marginwidth' => true, 'marginheight' => true, 'scrolling' => true, 'title' => true, ), ); $html = wp_kses( $html, $allowed_html );
Как мы видим код встраивания может содержать только три тега и ограниченное число параметров для этих тегов.
Смотрите код функции wp_filter_oembed_result(), которая по умолчанию повешена на хук oembed_dataparse и применяется абсолютно ко всем полученным кодам для встраивания.
WordPress как поставщик oEmbed
C версии 4.4. WordPress сам стал поставщиком/провайдером oEmbed формата. Теперь, записи одного сайта WP можно встроить в другой сайт.
Чтобы это сделать, нужно в контент поста добавить URL записи. Сделать это можно двумя способами:
- Добавить URL на отдельную строку.
- Вставить URL в шоткод
[embed]. Например[embed]http://dom.com/adress[/embed].
WordPress автоматически обработает указанный URL (определит является ли тот oEmbed провайдером), встроит данные и создаст кэш запроса, чтобы не делать этот запрос каждый раз при загрузке страницы.
Встраивания представляют из себя краткую версию страницы. Например если добавить /embed в конец URL любой записи, то мы попадем на страницу встраивания (которая должна появится на другом сайте при встраивании). Вот пример такой страницы: https://wp-kama.ru/handbook/codex/oembed/embed.
Пример того, как выглядит встраивание:
oEmbed в WordPress
Как изменить HTML код встраивания?
Для этого нужно создать в теме файл embed.php - подробнее про иерархию шаблона.
Если такого файла в теме нет, то за код встраивания отвечают файлы:
В каждом из этих файлов есть хуки, которые можно использовать для изменения отдельных частей HTML страницы встраивания.
Функции oEmbed
- get_post_embed_url() — Получает URL, который нужно использовать в iframe для встраивания указанной записи на другом сайте (oEmbed формат).
- get_post_embed_html() — Получает готовый HTML код oEmbed встраивания указанной записи. Предполагается использовать этот код для встраивания записи на другом ресурсе.
- is_embed() — Проверят является ли запрос запросом на страницу встраивания записи (embed).
- wp_embed_register_handler() — Регистрирует Embed обработчик. Это обработчик, который превращает ссылку в контенте в HTML код.
- wp_oembed_get() — Встраивает объект по УРЛ. Пытается получить HTML код из переданного УРЛ на основе поддерживаемых oEmbed WordPress.
- wp_oembed_add_provider() — Добавляет oEmbed провайдера. Это URL который будет парсится в контенте для вывода HTML кода с другого сайта.
- wp_oembed_remove_provider() — Removes an oEmbed provider.
См. Полный список Embed функций.
Хуки oEmbed
- embed_cache_oembed_types - позволяет изменить типы записей для которых нужно обрабатывать oembed ссылки (шоткоды).
- oembed_ttl — позволяет изменить TTL (time to live) время жизни кэша.
- embed_oembed_html — позволяет изменить уже закэшированный HTML.
- oembed_dataparse — Позволяет изменить контент (HTML) создаваемый при встраивании URL, поддерживаемых oEmbed.
- embed_oembed_discover — Позволяет указать нужно ли переходить по URL и искать
<link>тег встраивания на удаленном сайте.
См. Полный список хуков.
Поддерживаемые провайдеры
Ниже список oEmbed провайдеров, которых WordPress поддерживает из коробки. Дополнительные провайдеры можно добавить в этот список с помощью функции wp_oembed_add_provider().
| Provider | Flavor | Since |
|---|---|---|
| Dailymotion | dailymotion.com | 2.9.0 |
| Flickr | flickr.com | 2.9.0 |
| Scribd | scribd.com | 2.9.0 |
| Vimeo | vimeo.com | 2.9.0 |
| WordPress.tv | wordpress.tv | 2.9.0 |
| YouTube | youtube.com/watch | 2.9.0 |
| Crowdsignal | polldaddy.com | 3.0.0 |
| SmugMug | smugmug.com | 3.0.0 |
| YouTube | youtu.be | 3.0.0 |
| twitter.com | 3.4.0 | |
| instagram.com | 3.5.0 | |
| instagr.am | 3.5.0 | |
| Slideshare | slideshare.net | 3.5.0 |
| SoundCloud | soundcloud.com | 3.5.0 |
| Dailymotion | dai.ly | 3.6.0 |
| Flickr | flic.kr | 3.6.0 |
| Spotify | spotify.com | 3.6.0 |
| Imgur | imgur.com | 3.9.0 |
| Meetup.com | meetup.com | 3.9.0 |
| Meetup.com | meetu.ps | 3.9.0 |
| Animoto | animoto.com | 4.0.0 |
| Animoto | video214.com | 4.0.0 |
| Issuu | issuu.com | 4.0.0 |
| Mixcloud | mixcloud.com | 4.0.0 |
| Crowdsignal | poll.fm | 4.0.0 |
| TED | ted.com | 4.0.0 |
| YouTube | youtube.com/playlist | 4.0.0 |
| Tumblr | tumblr.com | 4.2.0 |
| Kickstarter | kickstarter.com | 4.2.0 |
| Kickstarter | kck.st | 4.2.0 |
| Cloudup | cloudup.com | 4.3.0 |
| ReverbNation | reverbnation.com | 4.4.0 |
| VideoPress | videopress.com | 4.4.0 |
| reddit.com | 4.4.0 | |
| Speaker Deck | speakerdeck.com | 4.4.0 |
| twitter.com/timelines | 4.5.0 | |
| twitter.com/moments | 4.5.0 | |
| facebook.com | 4.7.0 | |
| twitter.com/user | 4.7.0 | |
| twitter.com/likes | 4.7.0 | |
| twitter.com/lists | 4.7.0 | |
| Screencast | screencast.com | 4.8.0 |
| Amazon | amazon.com (com.mx, com.br, ca) | 4.9.0 |
| Amazon | amazon.de (fr, it, es, in, nl, ru, co.uk) | 4.9.0 |
| Amazon | amazon.co.jp (com.au) | 4.9.0 |
| Amazon | amazon.cn | 4.9.0 |
| Amazon | a.co | 4.9.0 |
| Amazon | amzn.to (eu, in, asia) | 4.9.0 |
| Amazon | z.cn | 4.9.0 |
| Someecards | someecards.com | 4.9.0 |
| Someecards | some.ly | 4.9.0 |
| Crowdsignal | survey.fm | 5.1.0 |
| Instagram TV | instagram.com | 5.1.0 |
| Instagram TV | instagr.am | 5.1.0 |
| TikTok | tiktok.com | 5.4.0 |
Удаление просроченного oEmbed Кэша
Для очистки Базы Данных на больших сайтах возможно есть смысл периодически запускать такую функцию, чтобы удалять просроченный кэш.
/**
* Remove expired oEmbed Cache.
*
* @param int $ttl The cache lifetime in seconds.
*
*/
function kama_delete_expired_oembed_cache( $ttl = MONTH_IN_SECONDS ){
global $wpdb;
// META
$query_data = $wpdb->get_results(
"SELECT * FROM $wpdb->postmeta WHERE meta_key LIKE '_oembed_time_%' ORDER BY meta_value+0 DESC"
);
$res = [];
foreach( $query_data as $data ){
$post = get_post( $data->post_id );
$info = date( 'd-m-Y', $data->meta_value ) ." - $post->ID: $post->post_title";
if( time() > $data->meta_value + $ttl ){
$oembed_meta_key = str_replace( '_oembed_time_', '_oembed_', $data->meta_key );
delete_post_meta( $data->post_id, $data->meta_key );
delete_post_meta( $data->post_id, $oembed_meta_key );
$res['DELETED'][] = $info;
}
else {
$res['NOT DELETED'][] = $info;
}
}
// POSTS
$min_allowed_date = date( 'Y-m-d H:i:59', time() - $ttl );
$posts = $wpdb->get_results(
"SELECT * FROM $wpdb->posts WHERE post_type = 'oembed_cache' AND post_modified_gmt < '$min_allowed_date'
ORDER BY post_modified_gmt DESC"
);
foreach( $posts as $post ){
$res['DELETED POSTS'][] = $post->post_modified_gmt;
wp_delete_post( $post->ID, 'force_delete' );
}
return $res;
}
$res = kama_delete_expired_oembed_cache();
print_r( $res );
Внутренний embed обработчик (с кэшированием)
Для начала замечу, что это хак - WP на такое не рассчитан. Но благодаря хукам, можно это сделать.
Для этого используем хук pre_oembed_result из метода WP_oEmbed::get_html():
// ...
$pre = apply_filters( 'pre_oembed_result', null, $url, $args );
if ( null !== $pre ) {
return $pre;
}
// ...
Нужно зарегистрировать внутренний обработчик через функцию wp_embed_register_handler(). Но в функции обработчике вернуть false и перенести функцию обработчик в упомянутый хук pre_oembed_result.
Т.е. код будет примерно такой:
add_action( 'init', 'myembed_provider_register' );
add_filter( 'pre_oembed_result', 'myembed_provider_handler', 10, 3 );
function myembed_provider_register(){
wp_embed_register_handler(
'myembed',
'~https://foo\.bar\.com/(\w+)~i',
'__return_false'
);
}
function myembed_provider_handler( $null, $url, $args ){
$html = '{{unknown}}';
// обрабатываем $url делаем HTTP запрос. См. WP HTTP API
// Возвращаем iframe или HTML код
return $html;
}
oEmbed для произвольного текста
Если нам нужно обработать шорткод [embed] или авто-встраивание ссылки в тексте. То этот текст нужно будет обработать отдельно. Базовая обработка с помощью функций do_shortcodes() или apply_shortcodes() oEmbed не включает. И по умолчанию такая обработка делается только для хука the_content.
Соответственно у нас есть 2 варианта:
Вариант 1
Простой, но может не подходить из-за излишней нагруженности хука the_content - на нём обычно висит куча всего, что может оказаться лишним.
$text = ' Some text to check custom shortcode adding. [embed]https://my-youtube.com/watch?v=lWzMBLoLIAc[/embed] https://my-youtube.com/watch?v=uDQwKtkXV-0 '; $text = apply_filters( 'the_content', $text ); echo $text;
Вариант 2: Точечный подход
Делаем с текстом только то что нам нужно:
$text = ' Some text to check custom shortcode adding. [embed]https://my-youtube.com/watch?v=lWzMBLoLIAc[/embed] https://my-youtube.com/watch?v=uDQwKtkXV-0 '; $text = $GLOBALS['wp_embed']->run_shortcode( $text ); // shortcode $text = $GLOBALS['wp_embed']->autoembed( $text ); // oEmbed URLs //$text = apply_shortcodes( $text ); $text = wpautop( $text ); echo $text;
oEmbed в комментариях WordPress
Код ниже позволяет использовать oEmbed в комментариях WordPress.
Правка для работы с AJAX:
Отключение oEmbed
Читайте в отдельной статье

