How to Move Your WordPress Feeds to a Sub-domain

How to set up a separate sub-domain for your WordPress feeds, just like WebMaster View did.

You can easily offload your feeds to an a external service like Feedburner. But what if you want to serve feeds for categories, tags, authors and single posts, just like WordPress by default does? This article explains how I moved all feeds to This is not offloading, feeds are still in the same server, but this helps you to have separate web logs for feeds and keep your main apache access log uncluttered with feed requests.

Note: To get separate log files, you need to directly edit the apache configuration files and create a virtual-host for feed.<your domain>.com having its own log files, but the same document root as www.<your domain>.com. For this, you need root/sudo access. Otherwise, you can just create a CNAME record for feed.<your domain>.com pointing to www.<your domain>.com.

After DNS propagated, download the following two template files and put it in your active theme’s directory:

See the code: main_feed.php and comment_feed.php


Then copy and add the following code to functions.php in your active theme’s directory.

/* Make the feed cacheable in browsers */

function make_cacheable($wp_last_modified, $offset)
{/* Code copied from wp-includes/classes.php) */
	header("Last-Modified: $wp_last_modified");

	$client_last_modified = empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? '' : trim($_SERVER['HTTP_IF_MODIFIED_SINCE']);
	// If string is empty, return 0. If not, attempt to parse into a timestamp
	$client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0;

	// Make a timestamp for our most recent modification...
	$wp_modified_timestamp = strtotime($wp_last_modified);

	if($client_modified_timestamp >= $wp_modified_timestamp)
		status_header( 304 );
	/* */
	header("Cache-Control: must-revalidate");
	$ExpStr = "Expires: " . gmdate("D, d M Y H:i:s", time() + $offset) . " GMT";

/* New feed url */

function feed_url($url, $feed_domain='') /* TODO: Replace with your feed domain */
	return str_replace(get_bloginfo('url'), $feed_domain, $url);

/* Disable old feeds */

function fb_disable_feed()
	status_header( 404 );
	wp_die( __('No feed available, please visit our <a href="'. get_bloginfo('url') .'">homepage</a>!') );

add_action('do_feed', 'fb_disable_feed', 1);
add_action('do_feed_rdf', 'fb_disable_feed', 1);
add_action('do_feed_rss', 'fb_disable_feed', 1);
add_action('do_feed_rss2', 'fb_disable_feed', 1);
add_action('do_feed_atom', 'fb_disable_feed', 1);

Now add the following to the top of the header.php

if($_SERVER['HTTP_HOST'] == '') /* TODO: Replace with your feed domain */
	if(!is_paged() && (is_home() || is_tag() || is_author() || is_category()))
		include TEMPLATEPATH . '/main_feed.php';exit;
	else if(is_single() && empty($page) && empty($cpage))
		include TEMPLATEPATH . '/comment_feed.php';exit;

Next, you need to change mod_rewrite code in .htaccess:

# Replace 'example' with your domain name
RewriteCond %{HTTP_HOST} ^$ [NC]
RewriteCond %{REQUEST_URI} !^/index\.php$
RewriteCond %{REQUEST_URI} !^/favicon\.ico$
RewriteRule . /index.php [L]

RewriteCond %{HTTP_HOST} ^$ [NC]
# BEGIN WordPress
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress

Add feed auto discovery code to your header.php

/* Change feed domains and site name in the code */
<?php if(is_single()) : ?>
	<link rel="alternate" type="application/rss+xml" title="<?php the_title(); ?> - Comments RSS 2.0 Feed" href="<?php echo feed_url(get_permalink()); ?>" />
<?php elseif(is_tag() || is_category() || is_author()) : ?>
	<link rel="alternate" type="application/rss+xml" title="Tag: <?php the_title(); ?> - RSS 2.0 Feed" href="<?php echo '' . $_SERVER['REQUEST_URI']); ?>" />
<?php endif; ?>
	<link rel="alternate" type="application/rss+xml" title="Site name - RSS 2.0 Feed" href="" />

Don’t forget to disable automatic feed links.

That’s all!

Your comments and feedback are invited

1 2 3