By doing a simple:
add_feed( 'schedule', 'my_schedule_feed' );
I have created a feed at /feed/schedule/
... easy.
But when I go to /schedule/
(which is a page) it is now showing the feed!
Looking at the rewrite rules I see this:
[feed/(feed|rdf|rss|rss2|atom|schedule)/?$] => index.php?&feed=$matches[1]
[(feed|rdf|rss|rss2|atom|schedule)/?$] => index.php?&feed=$matches[1]
This seems really odd. Why would WordPress overwrite existing page rules with the feed, instead of just using only the /feed/
base as expected?
Update: I have tried this as suggested by this answer, and flushing the permalinks, but while it shows up in the rewrites, it does not show the feed at /feed/schedule/
function add_feed_rewrites( $wp_rewrite ) {
$feednames = array( 'schedule', 'calendar' );
$feeds = implode( '|', $feednames);
$feed_rule = array(
'feed/(' . $feeds . ')/?$' => 'index.php?&feed=$matches[1]'
);
$wp_rewrite->rules = array_merge( $wp_rewrite->rules, $feed_rule );
}
add_filter( 'generate_rewrite_rules', 'add_feed_rewrites' );
add_action( 'do_feed_schedule', 'my_schedule', 10, 2 );
add_action( 'do_feed_calendar', 'my_calendar', 10, 2 );
Any ideas on how to get this working without the initial conflict?
By doing a simple:
add_feed( 'schedule', 'my_schedule_feed' );
I have created a feed at /feed/schedule/
... easy.
But when I go to /schedule/
(which is a page) it is now showing the feed!
Looking at the rewrite rules I see this:
[feed/(feed|rdf|rss|rss2|atom|schedule)/?$] => index.php?&feed=$matches[1]
[(feed|rdf|rss|rss2|atom|schedule)/?$] => index.php?&feed=$matches[1]
This seems really odd. Why would WordPress overwrite existing page rules with the feed, instead of just using only the /feed/
base as expected?
Update: I have tried this as suggested by this answer, and flushing the permalinks, but while it shows up in the rewrites, it does not show the feed at /feed/schedule/
function add_feed_rewrites( $wp_rewrite ) {
$feednames = array( 'schedule', 'calendar' );
$feeds = implode( '|', $feednames);
$feed_rule = array(
'feed/(' . $feeds . ')/?$' => 'index.php?&feed=$matches[1]'
);
$wp_rewrite->rules = array_merge( $wp_rewrite->rules, $feed_rule );
}
add_filter( 'generate_rewrite_rules', 'add_feed_rewrites' );
add_action( 'do_feed_schedule', 'my_schedule', 10, 2 );
add_action( 'do_feed_calendar', 'my_calendar', 10, 2 );
Any ideas on how to get this working without the initial conflict?
If you don't want to use add_feed()
, then you can use add_rewrite_rule()
:
add_action( 'init', function () {
add_rewrite_rule(
'^feed/(schedule|calendar)/?$',
'index.php?feed=$matches[1]',
'top'
);
} );
add_action( 'do_feed_schedule', function () {
header( 'Content-Type: text/plain' ); // dummy type just for testing
echo 'Yay, it works!';
} );
add_feed()
..Why would WordPress overwrite existing page rules with the feed, instead of just using only the
/feed/
base as expected?
So that example/schedule
would serve your custom feed, just like standard feed URLs such as example/feed
. But WordPress does create the (proper) rules having the feed/
base for custom feed URLs like example/feed/schedule
.
Therefore you shouldn't use schedule
as the slug of your Page, or if you have/need to, then you can alter the feed rewrite so that the example/schedule
will serve the Page instead of your feed:
If you know the exact rule/RegEx:
add_filter( 'rewrite_rules_array', function ( $rules ) {
$rules2 = [];
foreach ( $rules as $regex => $query ) {
if ( '(feed|rdf|rss|rss2|atom|schedule)/?$' === $regex ) { // it has 'schedule'
$rules2['(feed|rdf|rss|rss2|atom)/?$'] = $query; // so let's remove it
} else {
$rules2[ $regex ] = $query;
}
}
return $rules2;
} );
Otherwise, try something dynamic like this:
add_filter( 'rewrite_rules_array', function ( $rules ) {
global $wp_rewrite;
$feeds = $wp_rewrite->feeds; // original feeds
$pages = [ 'schedule', 'calendar' ]; // page slugs list
$feeds2 = array_diff( $feeds, $pages );
$rules2 = [];
$feeds = implode( '|', $feeds );
$feeds2 = implode( '|', $feeds2 );
foreach ( $rules as $regex => $query ) {
if ( '(' . $feeds . ')/?$' === $regex ) {
$rules2[ '(' . $feeds2 . ')/?$' ] = $query;
} else {
$rules2[ $regex ] = $query;
}
}
return $rules2;
} );
Note that I use the foreach
so that the rule stays in its original position. And another possible option is that just move the rule to a position after the Page rewrite rules. But I haven't yet tried that and the above code should be enough as a workaround..
And if I'm not mistaken, here's the code which WordPress use to generate the rule that's being altered in the above function:
// Create query for /(feed|atom|rss|rss2|rdf) (see comment near creation of $feedregex).
$feedmatch2 = $match . $feedregex2;
$feedquery2 = $feedindex . '?' . $query . '&feed=' . $this->preg_index( $num_toks + 1 );
See the source on Trac.