Apply styling only to first page sticky posts

Strange that stickies aren’t completely unset from the main loop on paged pages but only on the first page. If we look at the source, we will see that stickies are only unset from the main loop if they are on the first page. So we have two options here depending on what you exactly need

OPTION 1

If you need to keep your stickies in the loop on paged pages and just remove the styling, you can make use of the is_paged() condition in conjuction with your condition

if (    is_sticky()
     && !is_paged()
) {
    // Add your styling here
}

OPTION 2.1

Completely remove stickies from paged pages

add_action( 'pre_get_posts', function ( $q )
{
    if (    $q->is_home()       // Only target the home page
         && $q->is_main_query() // Only target the main query
         && $q->is_paged()      // Only target paged pages
    ) {
        // Remove stickies
        $q->set( 'post__not_in', get_option( 'sticky_posts' ) );
    }
});

I’m just thinking that if we use this option that we will need to adjust $found_posts to compensate for pagination on the first page. WP_Query throws us a curveball here as we cannot set post__not_in on page one as this will explicitely remove any sticky post from the sticky posts array if these specific posts aren’t on the first page.

I will investigate this and post anything extra that would be relevant to this issue

EDIT

There is an issue with pagination, so we will need to adjust the $found_posts property to adjust for pagination

add_filter( 'found_posts', function( $found_posts, \WP_Query $q )
{
    if (    $q->is_home()
         && $q->is_main_query()
         && !$q->is_paged()
    ) {
        // Get the sticky posts array
        $stickies = get_option( 'sticky_posts' );

        // Get all the post ID's from the first page
        $ids = $q->posts;

        // Remove all the current ids from the current sticky posts array
        $stickies = array_diff( $stickies, $ids );

        $found_posts = $found_posts - count( $stickies );
    }

    return $found_posts;
}, 10, 2 );

OPTION 2.2

I always tend to use the following right off the back to handle my sticky posts. This completely removes sticky posts from the main query and then it gets added back to via the the_posts filter

add_action( 'pre_get_posts', function ( $q )
{
    if (    $q->is_home()
         && $q->is_main_query()
    ) {
        $q->set( 'ignore_sticky_posts', 1                            );
        $q->set( 'post__not_in',        get_option( 'sticky_posts' ) );

        add_filter( 'the_posts', function( $posts, \WP_Query $q )
        {
            // Only do this for the first page
            if ( $q->is_paged() )
                return $posts;

            $stickies = get_option( 'sticky_posts' );
            // Check if we have stickies
            if ( !$stickies )
                return $posts;

            $args = [
                'posts_per_page' => count( $stickies ),
                'post__in'       => $stickies,
            ];
            $sticky_posts = get_posts( $args );

            // Merge the array
            $posts = array_merge( $sticky_posts, $posts );

            return $posts;
        }, 10, 2 );
    }
});

Leave a Comment