Change of query var in pre_get_posts not maintained

I’m creating a plugin that adds a custom feed. I am using a pre_get_posts filter to change the posts_per_page query var to -1 (to get all items of a custom post type). However, if I dump the $wp_query in the render function, posts_per_page remains the default. I tested also changing posts_per_rss to -1, and I do see that as changed in the query (though it, of course, doesn’t have any effect on the resulting posts). I also tried changing my theme to a default one and testing, but I had the same results. Can anyone explain why I can’t change the posts_per_page query var?

defined( 'ABSPATH' ) OR exit;

if(!class_exists('My_Custom_Feeds'))
{

    class My_Custom_Feeds { 

        protected $feed_slug = 'theslug';

        function __construct() {

            add_action( 'init', array($this, 'mcf_add_feed'));
            add_filter( 'pre_get_posts', array($this, 'mcf_pre_get_posts'));
        }

        function mcf_add_feed() {
            add_feed($this->feed_slug, array($this, 'mcf_render'));
        }

        function mcf_render(){

            //just output query to ensure it is as expected - but it's not
            global $wp_query;
            var_dump($wp_query);
            exit();
        }

        function mcf_pre_get_posts( $query ) {

            if ( $query->is_main_query() && $query->is_feed( $this->feed_slug ) ) {

                // modify query here to show all posts
                $query->set( 'posts_per_page', -1);
                $query->set( 'posts_per_rss', -1);
            }
        }
    }
}
if ( class_exists('My_Custom_Feeds') ){

    $my_custom_feeds = new My_Custom_Feeds();
}

Update one:
Realized I was using add_filter instead of add_action for pre_get_posts. I’ve updated that, though I still see the same issue.

add_action( 'pre_get_posts', array($this, 'mcf_pre_get_posts'));

Update two (and final):
Per @ialocin’s answer, I realized changing the posts_per_page query var is futile since it is overwritten by the posts_per_rss option in a feed query (my scenario). So, the answer is to use a filter to alter that option. (-1 is not a valid posts_per_rss value, thus the arbitrary one used below.)

function mcf_posts_per_rss( $option_name ) {
    global $wp_query;
    if ( $wp_query->is_main_query() && $wp_query->is_feed( $this->feed_slug ) ) {
            return 100; //arbitrarily large value that, while not ideal, works for me
    }
    return $option_name;
}

Then in my plugin class constructor I added the following (and removed the pre_get_posts action):

add_filter( 'pre_option_posts_per_rss', array( $this, 'mcf_posts_per_rss') );

3 Answers
3

The init hook runs well before pre_get_posts so dumping the query at that point– on init— isn’t going to reflect anything that will be done much later. I don’t think there is anything wrong with your code, you misunderstand the sequence of actions. What you expect to happen isn’t what actually happens.

Leave a Comment