2

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

2

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.

3
  • Thanks for the response. So, is there another action that I should add the feed on other than init? Otherwise, it sounds like I will have to requery in my render function and reset the post data after.
    – Nicole
    Jun 18, 2015 at 17:53
  • 1
    Adding the feed on init isn't the problem. Trying to dump $wp_query at that point is. The query will not be altered until later on pre_get_posts. I don't think the problem is your functionality but that you are trying to test that functionality based on a flawed premise.
    – s_ha_dum
    Jun 18, 2015 at 18:00
  • Got it. But then my original question stands - why can't I change that query var? I continue to get only ten items rendered in the feed.
    – Nicole
    Jun 18, 2015 at 18:49
1

posts_per_rss is not a WP_Query parameter. It is the name of the option that is saved into the database. It can be addresses via the pre_option_{$option_name}:

function wpse191824_posts_per_rss( $option_name ) {
    return 999;
}
add_filter( 'pre_option_posts_per_rss', 'wpse191824_posts_per_rss' );
2
  • Thanks! I'm marking yours as the answer as it sent me down the path to figuring out my issue. I was originally setting posts_per_rss simply as a test, but doing some searching around this option I found out that the posts_per_page query var is overwritten by it if the query is in a feed. I also discovered that -1 is apparently not a valid posts_per_rss value, so I had to set it to an arbitrarily higher value for some scenarios. Will update my original post with the valid code.
    – Nicole
    Jun 18, 2015 at 21:50
  • My pleasure! You are right about the number. I'm guessing it is because the input at the form has min="1" set. Another thing, next time just post your solution as answer. It is how the system works. So you actually should do it - thanks. Then you can also always accept your own answer too. @Nicole Jun 18, 2015 at 22:23
1

Per the discussion/help in this thread, below is the basic code that ended up working for my purposes. Setting the posts_per_page query var was a futile exercise since it is overwritten by the posts_per_rss option in a feed query (my scenario). posts_per_rss is not a query var and must be set a different way, thus the pre_option_posts_per_rss filter added. (-1 is not a valid posts_per_rss value, thus the arbitrary one used below.)

defined( 'ABSPATH' ) OR exit;

if(!class_exists('My_Custom_Feeds'))
{

    class My_Custom_Feeds { 

        protected $feed_slug = 'theslug';

        function __construct() {

            add_filter( 'pre_option_posts_per_rss', array( $this, 'mcf_posts_per_rss') );
            add_action( 'init', array($this, 'mcf_add_feed'));
        }

        function mcf_add_feed() {

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

        function mcf_render(){

            //put rendering stuff here
            exit();
        }

        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, worked for my purposes
            }
            return $option_name;
        }
    }
}
if ( class_exists('My_Custom_Feeds') ) {

    //instantiate class
    $my_custom_feeds = new My_Custom_Feeds();
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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