This same exact question was asked earlier this week or over the weekend, and it had me thinking. Here is the idea that I came up with.
If you look at the source code of the WP_Query
class, you will see that sticky posts is only added to the first page of the home page. There is also no filter supplied to change this behavior in order to set the required templates according to your liking.
There are many ways to display sticky posts on other templates through widgets, custom queries, shortcodes (which I will not recommend due to the fact that using do_shortcode()
is slower that using the function itself) or custom functions where you need to display them. I have opted to go with using the_posts
filter and pre_get_posts
action.
HERE’S HOW:
-
Get the post ID’s saved as sticky posts with
get_option( 'sticky_posts' )
-
Remove this posts from the main query with
pre_get_posts
. As stickies are included on the home page, we will exclude the home page. We will also exclude normal pages -
Inside a custom function, run a custom query with
get_posts
to get the posts set as sticky posts. -
Merge the returned array of sticky posts with the current returned posts of the main query with
array_merge
-
Hook this custom function to
the_posts
filter
Here is the code: (Requires PHP 5.4+)
add_action( 'pre_get_posts', function ( $q )
{
if ( !is_admin()
&& $q->is_main_query()
&& !$q->is_home()
&& !$q->is_page()
) {
$q->set( 'post__not_in', get_option( 'sticky_posts' ) );
if ( !$q->is_paged() ) {
add_filter( 'the_posts', function ( $posts )
{
$stickies = get_posts( ['post__in' => get_option( 'sticky_posts' ), 'nopaging' => true] );
$posts = array_merge( $stickies, $posts );
return $posts;
}, 10, 2);
}
}
});