Edit 2: Updated Code to account for “Maybe there are no stickied posts” 😉
Edit: I did a boo-boo with the number of posts. Fixed, should work now as intended.
You can do this by using two queries.
<?php
//First, you get all the sticky posts
$stickies = get_option('sticky_posts',array());
//then, get max 2 of them
$stickiessliced =array_slice($stickies,0,2);
$numposts = 3 - count($stickiessliced);
//$numposts is now the number of remaining "normal" posts to be queried
if(count($stickiessliced)){
//only query the stickies if there are some
$sticky_loop = array(
'posts_per_page' => count($stickiessliced),
'orderby' => 'date',
'post__in' => $stickiessliced,
'ignore_sticky_posts' => true
);
//only get sliced sticky posts, ignore everything else
$query = new WP_Query($sticky_loop);
//do the loop for the sticky posts
if ($query->have_posts()): ?>
<?php while ($query->have_posts()): $query->the_post();?>
// loop
<?php endwhile;?>
<?php wp_reset_query();?>
<?php endif;
}
//now get the remaining posts to fill up to three
$main_loop = array(
'posts_per_page' => $numposts,
'orderby' => 'date',
'post__not_in' => $stickies,
//replace $stickiessliced with $stickies to make sure that NO other stickies are queried (as is: the above queried stickies are ignored)
'ignore_sticky_posts' => true
);
$query = new WP_Query($main_loop);
//do the loop for the remaining posts to fill up
if ($query->have_posts()): ?>
<?php while ($query->have_posts()): $query->the_post();?>
// loop
<?php endwhile;?>
<?php wp_reset_query();?>
<?php endif;
?>
This should work like this: if there are 0 to 2 sticky posts, they are queried, looped and then 1 to 3 “normal” posts are queried. If there are more than 2 sticky posts, the first 2 are sliced and then 1 more “normal” post is queried.
Happy Coding!