To make this more complete, here is what I have said in comments in reply to the question on hand
Just to quickly explain, WP_Query
fails catastrophically in some cases where empty arrays are passed to some of its parameters, instead of also returning an empty array as we should expect, WP_Query
returns all posts. As for getting the correct stickies, as I said before, you need to get the current category id and use that to filter the sticky posts. Remember, with your approach, you need remove sticky posts from the main query otherwise you will get duplicates
As an alternative solution using hooks and filters on the main query, and working from a similar question/answer, this is what I have come up with: (Code is well commented so it can be followed. CAVEAT: This is untested though, and needs at least PHP 5.4+)
function get_term_sticky_posts()
{
// First check if we are on a category page, if not, return false
if ( !is_category() )
return false;
// Secondly, check if we have stickies, return false on failure
$stickies = get_option( 'sticky_posts' );
if ( !$stickies )
return false;
// OK, we have stickies and we are on a category page, continue to execute. Get current object (category) ID
$current_object = get_queried_object_id();
// Create the query to get category specific stickies, just get post ID's though
$args = [
'nopaging' => true,
'post__in' => $stickies,
'cat' => $current_object,
'ignore_sticky_posts' => 1,
'fields' => 'ids'
];
$q = get_posts( $args );
return $q;
}
add_action( 'pre_get_posts', function ( $q )
{
if ( !is_admin() // IMPORTANT, make sure to target front end only
&& $q->is_main_query() // IMPORTANT, make sure we only target the main query
&& $q->is_category() // Only target category archives
) {
// Check if our function to get term related stickies exists to avoid fatal errors
if ( function_exists( 'get_term_sticky_posts' ) ) {
// check if we have stickies
$stickies = get_term_sticky_posts();
if ( $stickies ) {
// Remove stickies from the main query to avoid duplicates
$q->set( 'post__not_in', $stickies );
// Check that we add stickies on the first page only, remove this check if you need stickies on all paged pages
if ( !$q->is_paged() ) {
// Add stickies via the the_posts filter
add_filter( 'the_posts', function ( $posts ) use ( $stickies )
{
$term_stickies = get_posts( ['post__in' => $stickies, 'nopaging' => true] );
$posts = array_merge( $term_stickies, $posts );
return $posts;
}, 10, 1 );
}
}
}
}
});
FEW NOTES:
This only works with default category
taxonomy. The code can be easily modified (please do that, modify to your needs) to use any taxonomy and its relevant terms
You just add this to functions.php. No need to alter your template files or using custom queries. All you need is the main query with default loop
EDIT
The above code is now tested and working on Wordpress 4.2.1 and PHP 5.4+
the_posts
. filterWP_Query
fails catastrophically in some cases where empty arrays are passed to some of its parameters, instead of also returning an empty array as we should expect,WP_Query
returns all posts. As for getting the correct stickies, as I said before, you need to get the current category id and use that to filter the sticky posts. Remember, with your approach, you need remove sticky posts from the main query otherwise you will get duplicates