Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

It's possible to make a site totally inaccessible via feeds (RSS, Atom, RDF) with a function like this:

function itsme_disable_feed() {
    wp_die( __( 'No feed available, please visit the <a href="'. esc_url( home_url( '/' ) ) .'">homepage</a>!' ) );
}
add_action('do_feed', 'itsme_disable_feed', 1);
add_action('do_feed_rdf', 'itsme_disable_feed', 1);
add_action('do_feed_rss', 'itsme_disable_feed', 1);
add_action('do_feed_rss2', 'itsme_disable_feed', 1);
add_action('do_feed_atom', 'itsme_disable_feed', 1);
add_action('do_feed_rss2_comments', 'itsme_disable_feed', 1);
add_action('do_feed_atom_comments', 'itsme_disable_feed', 1);

But that disables feeds for the entire site i.e. the main feed, feeds for categories, tags, comments, posts, pages, custom post types, etc.

How do I disable just the main feed and the main comments feed of the site? i.e. only make site.com/feed/ and site.com/comments/feed/ inaccessible.

Simply hiding feed using something like this (below) isn't an option:

remove_action( 'wp_head', 'feed_links_extra', 3 );
remove_action( 'wp_head', 'feed_links', 2 );
share|improve this question
    
Please send 404 Not Found or 410 Gone before exiting. :) –  sam Oct 28 '13 at 17:24
add comment

6 Answers

up vote 3 down vote accepted

Very, very quick unscientific research suggests that there is only one query_var set for the main feed. Other feeds such as category, tag, author feeds have more than one query_var. Thus the following should kill the main feed but leave others intact.

add_filter(
  'pre_get_posts', 
  function($qry) {
    if ($qry->is_feed()) {
      $fvars = array_filter($qry->query_vars);
      if (1 == count($fvars)) {
        wp_die( __( 'No feed available, please visit the <a href="'. esc_url( home_url( '/' ) ) .'">homepage</a>!' ) );
      }
    }
  },
  1
);

To remove the main comment feed, you need a small edit to check for the presence of $fvars['withcomments'].

add_filter(
  'pre_get_posts', 
  function($qry) {
    if ($qry->is_feed() ) {
      $fvars = array_filter($qry->query_vars);
      if (1 == count($fvars) || isset($fvars['withcomments'])) {
        wp_die( __( 'No feed available, please visit the <a href="'. esc_url( home_url( '/' ) ) .'">homepage</a>!' ) );
      }
    }
  },
  1
);

Be warned: Barely tested. Possibly buggy. Caveat emptor. No refunds.

share|improve this answer
    
I think he wants to keep comment feeds that aren't the main comment feed. –  sam Oct 29 '13 at 17:32
    
I believe this should meet that criteria. –  s_ha_dum Oct 29 '13 at 18:14
    
Won't (1 == count($fvars) || isset($fvars['withcomments']) === true for any comment feed, not just the main one? –  sam Oct 29 '13 at 19:02
add comment

You can try to play with this demo snippet:

function itsme_disable_feed() {
    if( isset( $_GET['q'] ) )
    {
        // input
        $q = filter_input( INPUT_GET, 'q', FILTER_SANITIZE_URL );
        $q = parse_url( $q, PHP_URL_PATH );
        $q = preg_replace( '/[^a-z0-9\/]/i', '', $q );

        // blacklist
        $feed_blacklist = array( '/feed/', '/comments/feed/' );

        // disable the feed for blacklisted queries
        if( in_array( strtolower( $q ), $feed_blacklist, TRUE ) )
            wp_die( __( 'No feed available, please visit the <a href="'. esc_url( home_url( '/' ) ) .'">homepage</a>!' ) );

    }
}

where you have to modify the $feed_blacklist to your needs.

share|improve this answer
    
Please escape that input :) –  kaiser Oct 20 '13 at 2:43
1  
Coding on Saturday evening can be fun ;-) You're absolutely right about that, but usually I don't hand out snippets without input sanitasion, but in this case I decided to skip it (hence I called it a demo snippet) since it's "only" used in comparison. But in hindsight it should "always" be sanitised because someone might copy/paste it and use it for other purpose. Thanks for the reminder ;-) –  birgire Oct 20 '13 at 9:45
    
Why does it test $_GET['q']? –  sam Oct 28 '13 at 17:33
1  
@sam My general practice to avoid PHP notices if the array key doesn't exists. –  birgire Oct 28 '13 at 18:31
    
I don't understand why $_GET['q'] would contain '/feed/' (or anything else). –  sam Oct 29 '13 at 17:30
add comment

using rewrite rules you can disable a url pattern that match main feed.

add_filter('rewrite_rules_array', 'rewrite_rules_array_feed_disable');
function rewrite_rules_array_feed_disable($rules){
    unset($rules['feed/(feed|rdf|rss|rss2|atom)/?$']);
    unset($rules['(feed|rdf|rss|rss2|atom)/?$']);
    return $rules;
}
share|improve this answer
add comment

This is a modded version of @s_ha_dum answer.

I'm agree with him that when in main feed the only variable setted is 'feed' (for posts feed) and 'withcomments' for main comment feed, but instead of relying on current query object variables, and filter the many empty defaults using array_filter, I think that - probably - is more reliable looking at $wp->query_vars: an array that contain only the query variables effectively used to run the query:

add_action('pre_get_posts', 'no_main_feeds', 1);

function no_main_feeds( $q ) {
  if ( is_feed() || is_comment_feed() ) {
    $vars = $GLOBALS['wp']->query_vars;
    unset( $vars['feed'], $vars['withcomments'] );
    if ( empty($vars) ) wp_die( 'No feed available' );
  }
}

The check for is_comment_feed() is actually needless, because when in main comment feed is_feed() is true, but I think it makes code intentions more clear, probably is also more future proof, and finally it doesn't hurt...

Unlike other answers here it (should) works with any permalink structure and also if pretty permalinks are disabled at all.

share|improve this answer
1  
Won't unset( $vars['feed'], $vars['withcomments'] ); affect all feeds? –  sam Oct 28 '13 at 20:40
1  
Just noticed that I inset the $vars variable, not the query variables. –  G. M. Oct 29 '13 at 16:38
add comment
add_filter('request', 'itsme_disable_main_feeds');

function itsme_disable_main_feeds($q)
{
    $exit_msg   = 'No feed available. Please visit the <a href="%s">homepage</a>.';
    $exit_title = 'No Feed Available';

    if (    !empty($q['feed'])         && count($q) === 1
         || !empty($q['withcomments']) && count($q) === 2 ) {

        $exit_msg = sprintf($exit_msg, esc_url( home_url('/') ));
        wp_die( $exit_msg, $exit_title, array('response' => 404) );
    }

    return $q;
}
share|improve this answer
add comment

The hook callback needs to check if it's a tag feed, or if it's a category feed or may be if it's a author feed. You can get a lot of information about the feed being produced if you add this two line in the callback. i.e function itsme_disable_feed(){ ... }

global $wp_query;
die(print_r($wp_query->query_vars));

You will notice that for a tag feed, or a category feed or a comment feed or even for an author feed there are certain parameters which contain values. Just do a check so that if those parameters have any value associated with it, you will do nothing. And if not, which means it's a main feed, you will call die().

Hope it helps.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.