Jetpack Infinite scroll conflicting with theme's pre_get_posts custom posts_per_page

I have the current function on my theme using pre_get_posts, currently right at the bottom of my theme’s functions.php file:

function mytheme_portfolio_archive_pages( $query ) {
    if ( is_admin() || ! $query->is_main_query() )

    if ( is_post_type_archive( 'mytheme_portfolio' ) ) {
        // Display 20 posts for a custom post type called 'mytheme_portfolio'
        $query->set( 'posts_per_page', 20 );
add_action( 'pre_get_posts', 'mytheme_portfolio_archive_pages', 1 );

It means I have 20 posts per page if the current archive is of the post type mytheme_portfolio, instead of the default 5 for the blog pages (the number 5 is being set in “Blog pages show at most __ posts” in Settings → Reading).

The above function is working fine when Jetpack Infinite Scroll is deactivated.

Problem is I want to use Jetpack Infinite Scroll with the ‘mytheme_portfolio’ archive. And with it activated, the above function stops working and the Infinite Scroll uses the “Blog pages show at most 5 posts” number from Settings → Reading when it loads new posts. The Infinite Scroll is otherwise working fine but I need to show 20 posts per page, not 5, if I’m on a mytheme_portfolio archive page!

My Jetpack setup code is as follows, just for reference:

    function mytheme_render_infinite_scroll() {
        while ( have_posts() ) : the_post();
                if ('mytheme_portfolio' == get_post_type() && !is_search()) :
                    get_template_part( 'content', 'archive-portfolio' );
                elseif ( is_search() ) :
                else :
                    get_template_part( 'content', get_post_format() );

    function mytheme_jetpack_setup() {
        add_theme_support( 'infinite-scroll', array(
            'container'      => 'content',
            'footer_widgets' => 'footer-widgets',
            'type'           => 'click',
            'render'         => 'mytheme_render_infinite_scroll',
            'wrapper'        => true,
            'posts_per_page' => false
        ) );
    add_action( 'after_setup_theme', 'mytheme_jetpack_setup' );

Thanks so much for any help anyone can give!

EDIT: I found the line in the Jetpack plugin code that’s conflicting, in jetpack/modules/infinite-scroll/infinity.php, line 26…

function __construct() {
    add_action( 'pre_get_posts',                  array( $this, 'posts_per_page_query' ) );

which corresponds to lines 449 – 452 in the same file:

function posts_per_page_query( $query ) {
    if ( ! is_admin() && self::archive_supports_infinity() && $query->is_main_query() )
        $query->set( 'posts_per_page', self::get_settings()->posts_per_page );

If I comment line 26 out my function works. Obviously I don’t want to go changing the plugin’s files, is there a way I can make sure my theme’s posts_per_page argument (initial code block above) is the one that’s used, and not Jetpack’s?

Solutions Collecting From Web of "Jetpack Infinite scroll conflicting with theme's pre_get_posts custom posts_per_page"

You’ve specified a priority of 1 for your pre_get_posts function here:

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

Jetpack doesn’t specify a priority:

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

So that gets added with the default priority for add_action, which is 10:

(int) (optional) Used to specify the order in which the functions associated with a particular action are executed. Lower numbers correspond with earlier execution, and functions with the same priority are executed in the order in which they were added to the action.
Default: 10

So for each of these requests, your code is executed and sets posts per page to 20, then Jetpack’s code is executed and overwrites your value with its own.

To fix this, just specify a lower priority so yours runs later and overwrites Jetpack’s:

add_action( 'pre_get_posts', 'mytheme_portfolio_archive_pages', 20 );