Handle multiple feeds in fetch_feed().#10631
Handle multiple feeds in fetch_feed().#10631peterwilsoncc wants to merge 18 commits intoWordPress:trunkfrom
fetch_feed().#10631Conversation
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Core Committers: Use this line as a base for the props when committing in SVN: To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
b73e186 to
3ec52a0
Compare
Test using WordPress PlaygroundThe changes in this pull request can previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser. Some things to be aware of
For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation. |
3ec52a0 to
1e227d2
Compare
|
If we simply want to handle multiple feeds, the following approach might work: diff --git a/src/wp-includes/feed.php b/src/wp-includes/feed.php
index 421bee7173..74f0ee77cd 100644
--- a/src/wp-includes/feed.php
+++ b/src/wp-includes/feed.php
@@ -832,7 +832,20 @@ function fetch_feed( $url ) {
$feed->get_registry()->register( SimplePie\File::class, 'WP_SimplePie_File', true );
- $feed->set_feed_url( $url );
+ if ( is_array( $url ) && count( $url ) > 1 ) {
+ $feed->multifeed_url = array();
+ foreach ( $url as $value ) {
+ $feed->multifeed_url[] = $feed->get_registry()->call(
+ SimplePie\Misc::class, 'fix_protocol',
+ array( $value, 1 )
+ );
+ }
+ } elseif ( is_array( $url ) && count( $url ) === 1 ) {
+ $feed->set_feed_url( array_shift( $url ) );
+ } else {
+ $feed->set_feed_url( $url );
+ }
+
/** This filter is documented in wp-includes/class-wp-feed-cache-transien
t.php */
$feed->set_cache_duration( apply_filters( 'wp_feed_cache_transient_lifeti
me', 12 * HOUR_IN_SECONDS, $url ) );However, this may not be the recommended approach. |
|
@t-hamano The hook will still run for each individual URL but it won't run with all of them. IE I'll take a look at your suggested diff. I don't know their plans but I wouldn't be surprised if |
3300255 to
c8f11ac
Compare
| $simplepie_instance->set_output_encoding( get_bloginfo( 'charset' ) ); | ||
|
|
||
| if ( $simplepie_instance->error() ) { | ||
| return new WP_Error( 'simplepie-error', $simplepie_instance->error() ); |
There was a problem hiding this comment.
If an error occurs in one feed, the other feeds will be ignored. As I understand it, SimplePie will continue processing even if an error occurs and merge successful feeds:
I haven't tested it, but how about an approach like this:
foreach ( (array) $url as $feed_url ) {
$simplepie_instance = clone $feed;
$simplepie_instance->set_feed_url( $feed_url );
$simplepie_instance->init();
$simplepie_instance->set_output_encoding( get_bloginfo( 'charset' ) );
if ( ! $simplepie_instance->error() ) {
$feeds[] = $simplepie_instance;
} else {
$errors[] = $simplepie_instance->error();
}
}
if ( empty( $feeds ) ) {
return new WP_Error( 'simplepie-error', $errors );
}We may also need unit tests to ensure that if an error occurs, the rest of the feed still gets processed.
There was a problem hiding this comment.
What is the 6.8 behavior for when a feed encounters an error? We should try to replicate that
There was a problem hiding this comment.
What is the 6.8 behavior for when a feed encounters an error? We should try to replicate that
An error in any feed triggers WP_Error object. If multiple feeds error then the errors are reported for all the affected feeds.
$ wp eval "var_dump( fetch_feed( [ 'http://example.com/news/feed/', 'https://wordpress.org/news/feed/' ] ) );"
phar:///usr/local/src/wp-cli/bin/wp-cli.phar/vendor/wp-cli/eval-command/src/Eval_Command.php(39) : eval()'d code:1:
class WP_Error#2462 (3) {
public $errors =>
array(1) {
'simplepie-error' =>
array(1) {
[0] =>
array(1) {
[0] =>
string(118) "A feed could not be found at `http://example.com/news/feed/`; the status code is `404` and content-type is `text/html`"
}
}
}
public $error_data =>
array(0) {
}
protected $additional_data =>
array(0) {
}
}
$ wp eval "var_dump( fetch_feed( [ 'http://example.com/news/feed/', 'https://example.org/news/feed/' ] ) );"
phar:///usr/local/src/wp-cli/bin/wp-cli.phar/vendor/wp-cli/eval-command/src/Eval_Command.php(39) : eval()'d code:1:
class WP_Error#2462 (3) {
public $errors =>
array(1) {
'simplepie-error' =>
array(1) {
[0] =>
array(2) {
[0] =>
string(118) "A feed could not be found at `http://example.com/news/feed/`; the status code is `404` and content-type is `text/html`"
[1] =>
string(119) "A feed could not be found at `https://example.org/news/feed/`; the status code is `404` and content-type is `text/html`"
}
}
}
public $error_data =>
array(0) {
}
protected $additional_data =>
array(0) {
}
}
I'll try to replicate that,
|
@swissspidy @TobiasBg This is my first time looking at SimplePie code, so I may have missed something, and I'd appreciate any feedback if there is anything. |
Sorry, I'm not familiar with this specific part either :-( |
|
Same here |
There was a problem hiding this comment.
Pull request overview
This PR adds support for passing an array of feed URLs to fetch_feed() to handle multiple feeds. When multiple URLs are provided, the function fetches each feed individually, merges their items using SimplePie's merge_items() method, and returns a single SimplePie object with the combined items.
Changes:
- Modified
fetch_feed()to detect and handle array URLs by fetching each feed individually and merging items - Moved
set_feed_url()call to after array processing to avoid setting URL prematurely - Added test coverage to verify multiple feeds are supported without triggering deprecation warnings
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| src/wp-includes/feed.php | Implements multi-feed support by cloning SimplePie instance for each URL, fetching items, and merging them via SimplePie::merge_items() |
| tests/phpunit/tests/feed/fetchFeed.php | Adds test to verify fetch_feed() accepts array of URLs and doesn't trigger SimplePie deprecation warning |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| $simplepie_instance->set_output_encoding( get_bloginfo( 'charset' ) ); | ||
|
|
||
| if ( $simplepie_instance->error() ) { | ||
| return new WP_Error( 'simplepie-error', $simplepie_instance->error() ); |
There was a problem hiding this comment.
What is the 6.8 behavior for when a feed encounters an error? We should try to replicate that
fcc6c73 to
a2089a2
Compare
|
@aaronjorbin @t-hamano I've added a bunch of tests for various use cases for both multiple and single feed requests. On the 6.8 branch there are two different results for unspecified feeds, Changing the first part of the if elseifs to the following results in the same result on both 6.8 and this branch but I think a WP_Error is the best response. What would you prefer? if ( empty( $url ) ) {
$url = ''; // Allow SP to do it's thing with an unspecified URL.
} elseif ( is_array( $url ) && count( $url ) === 1 ) { |
t-hamano
left a comment
There was a problem hiding this comment.
Thanks for the update! This PR looks very stable to me.
On the 6.8 branch there are two different results for unspecified feeds,
$url = ''and$url = []:
Changing the first part of the if elseifs to the following results in the same result on both 6.8 and this branch but I think a WP_Error is the best response. What would you prefer?
I agree that the ideal behavior would be to return a WP_Error if $url is a falsy value. However, I think doing so could cause confusion for consumers by unintentionally returning a WP_Error for code that previously didn't cause an error.
For now, I'm leaning towards maintaining the behavior of the 6.8 branch.
Done in e1c3bcb |
Co-Authored-By: westonruter <westonruter@git.wordpress.org>
| if ( empty( $url ) ) { | ||
| // Ensure $url is an empty string, even if passed as an empty array. | ||
| $url = ''; | ||
| } elseif ( is_array( $url ) && count( $url ) === 1 ) { |
There was a problem hiding this comment.
Missing yoda here, but not a problem on my side it is ;)
There was a problem hiding this comment.
count() is a function call so yoda isn't required as it's impossible to assign a value to it
audrasjb
left a comment
There was a problem hiding this comment.
LGTM as well, just added a small comment. Probably not a blocker.
4514883 to
c50c9f7
Compare
|
I've pushed c50c9f7 to work around the PHP 8.5 deprecation error. Once simplepie/simplepie#949 is released the commit can be reverted to avoid the duplicate code. |
Handles passing an array to
fetch_feed()by requesting each feed individually and then callingSimplePie\SimplePie::merge_items();on the result before passing the data back in to a SimplePie object.I don't love this so would love some suggestions of anything I am missing.
Trac ticket: https://core.trac.wordpress.org/ticket/64136
This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.