fetch_feed()
Получает внешний фид и разбирает его на данные (парсит его).
Функция нужна, чтобы получить RSS фид в виде SimplePie объекта и закэшировать результат.
Для получения и парсинга фида fetch_feed() использует популярный класс SimplePie. Фид кэшируется и кэш в последствии обновляется каждые 12 часов.
Данные кэшируются в базу данных во временные опции.
Если установлен плагин постоянного объектного кэширования, то функция будет кэшировать не в БД, а в хранилище для объектного кэша.
Есть очень похожая функция fetch_rss( $url )
Подробнее о методах класса SimplePie читайте в документации.
Хуки из функции
Возвращает
SimplePie\SimplePie|WP_Error.
Использование
fetch_feed( $url );
- $url(строка) (обязательный)
- Ссылка (УРЛ) на фид который нужно получить. В результате по этой ссылке будет получен создан объект (массив) SimplePie.
Примеры
#1 Еще пример: получим 5 записей фида стороннего сайта
Прочитаем фид http://mysite.com/feed/ и получим из него первые 5 записей.
include_once ABSPATH . WPINC . '/feed.php';
$rss = fetch_feed( 'http://mysite.com/feed/' );
$rss_items = $rss->get_items( 0, $rss->get_item_quantity(5) );
if ( ! $rss_items ) {
echo 'no items';
}
else {
foreach ( $rss_items as $item ) {
echo '<p><a href="' . $item->get_permalink() . '">' . $item->get_title() . '</a></p>';
}
} #2 Получим 5 записей из фида у внешнего сайта
Пример, который получает и выводит на экран ссылки на существующий RSS фид. В примере мы ограничиваем вывод только 5-ю последними записями в фиде.
<h2>Поcледние новости с блога blog.ru</h2>
<?php
// делаем функцию fetch_feed() доступной, обычно эта строка не нужна
include_once ABSPATH . WPINC . '/feed.php';
// Получаем фид и создаем из него SimplePie объект.
$rss = fetch_feed( 'http://blog.ru/feed' );
// Проверяем, что объект успешно создан
if ( ! is_wp_error( $rss ) ) {
// Указываем что максимум мы хотим выводить 5 записей фида
$maxitems = $rss->get_item_quantity( 5 );
// Создаем массив всех записей фида, начиная с первой записи (0 - начало)
$rss_items = $rss->get_items( 0, $maxitems );
}
?>
<ul>
<?php
if( $maxitems == 0 ){
echo '<li>Нет записей.</li>';
}
else {
// Пробегаемся по массиву и выводим ссылку на каждую запись
foreach( $rss_items as $item ){
?>
<li>
<a href="<?= esc_url( $item->get_permalink() ) ?>"
title="<?= esc_attr( 'Posted ' . $item->get_date( 'j F Y | g:i a' ) ) ?>"
>
<?= esc_html( $item->get_title() ) ?>
</a>
</li>
<?php
}
}
?>
</ul> #3 Управление временем жизни кэша фидов
Результат получения фида кэшируется на 12 часов. Чтобы изменить время кэша для функции fetch_feed(), нужно использовать хук wp_feed_cache_transient_lifetime.
add_filter( 'wp_feed_cache_transient_lifetime', 'speed_up_feed', 10, 2 );
function speed_up_feed( $interval, $url ) {
if( 'http://myexample.com/feed/' === $url ){
return 3600; // 1 час
}
return $interval;
} #4 Отключение кэширования на время разработки
По ходу манипуляций с фидом, необходимо отключить кэширования, а то оно будет сильно мешать. Сделать это можно через хук wp_feed_options
// отключаем кэширование фидов. Только если включен режим разработки WP_DEBUG
if( defined('WP_DEBUG') && WP_DEBUG ){
add_action( 'wp_feed_options', function( &$feed ){
$feed->enable_cache(false);
} );
}
ВАЖНО! Обязательно отключите этот код на рабочем сайте. Потому что он может увеличить скорость загрузки страниц сайта в разы!
Кэширование фидов не работает с включенной константой WP_DEBUG
Имейте ввиду, что если включена константа WP_DEBUG, то фид не кэшируется. Срабатывает такой код ядра:
function do_not_cache_feeds(&$feed) {
$feed->enable_cache(false);
}
if ( defined('WP_DEBUG') && WP_DEBUG ) {
add_action( 'wp_feed_options', 'do_not_cache_feeds' );
}
Кэширование в браузере
Также обратите внимание, что кэширование может происходить в браузере, чтобы его обойти обновляйте страницу через ctrl + F5. Или можно добавить такой хук:
// отключим кэширование в барузере для запросов фидов
add_filter( 'wp_headers', function( $headers ){
if( !empty( $GLOBALS['wp']->query_vars['feed'] ) ){
unset( $headers['ETag'], $headers['Last-Modified'] );
}
return $headers;
} ); #5 Как распарсить фид из локального файла
Вообще библиотека SimplePie позволяет передать локальный файл с данными фида, чтобы распарсить этот фид. Но WordPress почему-то отключил эту возможность, переписав конструктор класса SimplePie_File, расширив этот класс своим классом WP_SimplePie_File.
И поэтому, если в fetch_feed() указать путь до локального файла, ничего работать не будет.
Исправить это можно с помощью хука wp_feed_options:
$feed_path = PROJECT_ROOT_DIR . '/_tmp/feed.xml';
add_action( 'wp_feed_options', 'change_simple_pie_options', 10, 2 );
function change_simple_pie_options( $simplepie, $url ){
/**
* INFO: We need to create the TEMP_SimplePie_File class to fetch the feed
* from a local file (not HTTP). To do that, we need to use the native {@see SimplePie_File} class,
* but it is overridden by WP with the {@see WP_SimplePie_File} class, and we cannot change it
* by simply passing the {@see SimplePie_File} class to the {@see SimplePie::set_file_class()} method,
* because the {@see SimplePie_Registry::register()} method has an `is_subclass_of()`
* check, and this check does not pass like: is_subclass_of('SimplePie_File', 'SimplePie_File').
*/
class TEMP_SimplePie_File extends SimplePie_File {}
$simplepie->set_file_class( TEMP_SimplePie_File::class );
$simplepie->set_cache_duration( 0 );
}
$simplepie = fetch_feed( $feed_path );
$items = $simplepie->get_items( 0, 10 );
foreach( $items as $item ){
echo $item->get_title() ."\n";
}
Зачем это может быть нужно? Например:
- У вас есть отдельный сервис, который собирает фиды и кладет их в файлы, которые затем нужно распарсить через WP.
- Вам нужно парсить фид, но этот фид заблокирован (защищен) так, что через PHP получить его невозможно (проверяется поддержка куки — на Cloudflare есть подобная защита, обойти которую стандартным curl-запросом невозможно). В этом случае можно скачивать такой фид через какой-нибудь безголовый браузер и класть в файл, а затем парсить фид из файла.
#6 Как распарсить фид, если у нас уже есть XML-контент
Допустим, мы получили XML-контент фида каким-то способом — например, через wp_remote_get() или curl. В таком случае использовать стандартную функцию WordPress fetch_feed() не получится, так как она требует URL, а не готовый XML.
К сожалению, в WordPress нет встроенной функции, которая позволила бы передать XML-контент напрямую и получить объект SimplePie. Поэтому напишем такую функцию сами:
/**
* Parses the XML feed and returns {@see \SimplePie\SimplePie()} object.
* It works like {@see fetch_feed()}, but here we pass the feed content for parsing, but not the feed URL.
*/
function wpkama_parse_feed( string $xml ): \SimplePie\SimplePie|WP_Error {
if( ! class_exists( \SimplePie\SimplePie::class, false ) ){
require_once ABSPATH . WPINC . '/class-simplepie.php';
}
if( ! class_exists( \WP_SimplePie_Sanitize_KSES::class, false ) ){
require_once ABSPATH . WPINC . '/class-wp-simplepie-sanitize-kses.php';
}
$feed = new \SimplePie\SimplePie();
$feed->get_registry()->register( \SimplePie\Sanitize::class, \WP_SimplePie_Sanitize_KSES::class, true );
$feed->set_raw_data( $xml );
$feed->enable_cache( false );
$feed->init();
$feed->set_output_encoding( get_bloginfo( 'charset' ) );
if( $feed->error() ){
return new WP_Error( 'simplepie-error', $feed->error() );
}
return $feed;
} #7 Очистка кэша всех фидов в WordPress
Для запуска кода, нужно добавить в URL параметр ?clear_feeds_cache.
// Очистка кэша всех фидов в WordPress
if( isset( $_GET['clear_feeds_cache'] ) ){
global $wpdb;
$cleared = $wpdb->query( "DELETE FROM $wpdb->options WHERE option_name LIKE '\_transient%\_feed\_%'" );
die( var_dump( $cleared ) );
}
Заметка: если на сайте включено объектное кэширование, то этот код не сработает.
Список изменений
| С версии 2.8.0 | Введена. |