Skip to content

Custom Feeds in WordPress

So, turns out it is possible to move or copy WordPress “archives” without having to resort to custom page templates and all sorts of WP_Query wizardry. But, what about … feeds?

WordPress won’t “autogenerate” a feed to go with our “new” archive. (How would it, even?) What we could do, however, is define new routes for that as well. And ensure our previous “filter” does not target the “new” feed. And use the wp_head action to output feed links on the relevant pages. Not so easy.

(WordPress does in fact autogenerate a whole lot of things. Just a matter of tacking, e.g., ?post_type=post&feed=rss2 onto your homepage URL. It’s the pretty permalinks that don’t always come for free.)

But, what if I used—because that’s what I do—Custom Post Types, e.g., for “notes”?

In this new scenario—let’s forget about the whole “custom” blog archive for a bit, and focus only on post types—where my note archive lives at /notes/, WordPress will automatically create a “note-only” RSS feed at /notes/feed/. Perfect! All while my default, “main” feed (at /feed/) continues to list (only) the latest articles. Très easy!

What if I still wanted a feed that combines both, though? A “stream” feed?

Well, I could fairly easily add notes to my main feed:

add_filter( 'request', function( $request ) {
  // Add our CPT to the main feed, or rather, to feeds without an explicit post type, only.
  if ( isset( $request['feed'] ) && ! isset( $request['post_type'] ) ) {
    $request['post_type'] = array( 'post', 'my_note_cpt' );

  return $request;
}, 9 );

Note: There might be other ways to accomplish this (hook into pre_get_posts?) but the approach above has proven to be quite robust.

But then I’d lose my “post-only” (or article-only) feed.

Okay, let’s think for a bit. Let’s say I have single-post URLs start with /articles/ (my so-called permalink “front”). Why don’t we move the article feed to … /articles/feed/ instead? (And keep the change above, so that the “main” feed, at /feed/, still covers both articles and notes.)

add_filter( 'generate_rewrite_rules', function( $wp_rewrite ) {
  if ( empty( $wp_rewrite->front ) ) {
    // Do nothing.
    return $wp_rewrite;

  $feed_rules = array(
    trim( $wp_rewrite->front, '/' ) . '/feed/?$' => 'index.php?post_type=post&feed=rss2',

  $wp_rewrite->rules = $feed_rules + $wp_rewrite->rules;

  return $wp_rewrite;
} );

Note: We have to flush permalinks after first adding this to a must-use plugin or our functions.php. Also, this bit of code won’t do anything if our permalink “front” is empty.

Now, let’s announce all three feeds on at least the homepage. (By default, the homepage will announce the main feed, while, e.g., the notes page announces both the main and notes feeds. Category archives will announce the main and category feeds, and so on.)

add_action( 'wp_head', function() {
  // Remove default feed links.
  remove_action( 'wp_head', 'feed_links', 2 );
  // But keep category, comments, etc. feed links.
  // remove_action( 'wp_head', 'feed_links_extra', 3 );

  // And add our own.
  <link rel="alternate" type="application/rss+xml" title="My Site" href="<?php echo esc_url( get_bloginfo( 'rss2_url' ) ); ?>">
  <link rel="alternate" type="application/rss+xml" title="My Site &raquo; Articles Feed" href="<?php echo esc_url( home_url( 'articles/feed/' ) ); ?>">
  if ( ! is_post_type_archive( 'my_note_cpt' ) ) :
    // Output the notes feed on all pages except the ones where it's automatically added.
    <link rel="alternate" type="application/rss+xml" title="My Site &raquo; Notes Feed" href="<?php echo esc_url( home_url( 'notes/feed/' ) ); ?>">
}, 1 );

Note: We could make this snippet a bit “smarter,” too. Refer to the permalink “front” rather than have it hardcoded. Next time.

Last remark: we did not cover Atom or other feed formats. In fact, I sometimes just disable these (with the help of another filter or two). Make my life a bit easier. Most, if not all, feed aggregators support RSS just fine.

WordPress offers a great deal of features right out of the box, and for most users that’s fine, but once you start tweaking (deeply), it’s often beneficial to really think about what you actually need and disable some of the things you don’t.