fetch_feed()WP 2.8.0

Получает внешний фид и разбирает его на данные (парсит его).

Функция нужна, чтобы получить RSS фид в виде SimplePie объекта и закэшировать результат.

Для получения и парсинга фида fetch_feed() использует популярный класс SimplePie. Фид кэшируется и кэш в последствии обновляется каждые 12 часов.

Данные кэшируются в базу данных во временные опции.

Если установлен плагин постоянного объектного кэширования, то функция будет кэшировать не в БД, а в хранилище для объектного кэша.

Есть очень похожая функция fetch_rss( $url )

Подробнее о методах класса SimplePie читайте в документации (англ.).

Возвращает

SimplePie\SimplePie|WP_Error.

  • SimplePie - объект данных о фиде.
  • WP_Error - в случае ошибки.

Использование

fetch_feed( $url );
$url(строка) (обязательный)
Ссылка (УРЛ) на фид который нужно получить. В результате по этой ссылке будет получен создан объект (массив) SimplePie.

Примеры

0

#1 Получим 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>
0

#2 Еще пример: получим 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>';
	}
}
0

#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;
}
0

#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;
} );
0

#5 Очистка кэша всех фидов в 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 ) );
}

Заметка: если на сайте включено объектное кэширование, то этот код не сработает.

0

#6 Как распарсить фид из локального файла

Вообще библиотека 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-запросом невозможно). В этом случае можно скачивать такой фид через какой-нибудь безголовый браузер и класть в файл, а затем парсить фид из файла.

Список изменений

С версии 2.8.0 Введена.

Код fetch_feed() WP 6.7.1

function fetch_feed( $url ) {
	if ( ! class_exists( 'SimplePie\SimplePie', false ) ) {
		require_once ABSPATH . WPINC . '/class-simplepie.php';
	}

	require_once ABSPATH . WPINC . '/class-wp-feed-cache-transient.php';
	require_once ABSPATH . WPINC . '/class-wp-simplepie-file.php';
	require_once ABSPATH . WPINC . '/class-wp-simplepie-sanitize-kses.php';

	$feed = new SimplePie\SimplePie();

	$feed->set_sanitize_class( 'WP_SimplePie_Sanitize_KSES' );
	/*
	 * We must manually overwrite $feed->sanitize because SimplePie's constructor
	 * sets it before we have a chance to set the sanitization class.
	 */
	$feed->sanitize = new WP_SimplePie_Sanitize_KSES();

	// Register the cache handler using the recommended method for SimplePie 1.3 or later.
	if ( method_exists( 'SimplePie_Cache', 'register' ) ) {
		SimplePie_Cache::register( 'wp_transient', 'WP_Feed_Cache_Transient' );
		$feed->set_cache_location( 'wp_transient' );
	} else {
		// Back-compat for SimplePie 1.2.x.
		require_once ABSPATH . WPINC . '/class-wp-feed-cache.php';
		$feed->set_cache_class( 'WP_Feed_Cache' );
	}

	$feed->set_file_class( 'WP_SimplePie_File' );

	$feed->set_feed_url( $url );
	/** This filter is documented in wp-includes/class-wp-feed-cache-transient.php */
	$feed->set_cache_duration( apply_filters( 'wp_feed_cache_transient_lifetime', 12 * HOUR_IN_SECONDS, $url ) );

	/**
	 * Fires just before processing the SimplePie feed object.
	 *
	 * @since 3.0.0
	 *
	 * @param SimplePie\SimplePie $feed SimplePie feed object (passed by reference).
	 * @param string|string[]     $url  URL of feed or array of URLs of feeds to retrieve.
	 */
	do_action_ref_array( 'wp_feed_options', array( &$feed, $url ) );

	$feed->init();
	$feed->set_output_encoding( get_bloginfo( 'charset' ) );

	if ( $feed->error() ) {
		return new WP_Error( 'simplepie-error', $feed->error() );
	}

	return $feed;
}