Why Exclude Sticky Posts from the Main Loop
In WordPress development, you might display sticky posts separately (e.g., via a custom block or widget) outside the main loop on your homepage. To prevent duplicate sticky post listings, you need to exclude them from the default main query, which normally shows sticky posts before recent posts.
Recommended Solution
While you may have seen solutions using query_posts(), this function is strongly discouraged because it replaces the main query entirely, often breaking pagination, plugin compatibility, and causing other side effects.
The correct approach is to use WordPress's pre_get_posts action hook, which safely modifies the main query parameters before execution.
Core Code
Add this code to your theme's functions.php file:
function exclude_sticky_posts($query) {
// Only run for the front-end main query
if ( is_admin() || ! $query->is_main_query() ) {
return;
}
// Apply only to the homepage
if ( $query->is_home() ) {
// Ignore sticky posts, show them in normal order
$query->set( 'ignore_sticky_posts', 1 );
}
}
add_action( 'pre_get_posts', 'exclude_sticky_posts' );
Code Explanation
is_admin(): Prevents the code from affecting the WordPress admin area.$query->is_main_query(): Ensures only the site's primary query is modified, not secondary queries (widgets, menus, etc.).$query->is_home(): Restricts the rule to the site's front page.$query->set( 'ignore_sticky_posts', 1 ): The key parameter. Setting it to1ortruetells WordPress not to force sticky posts to the top; all posts (including stickies) will follow normal sorting (by date, menu order, etc.).
Extended Applications
To exclude sticky posts on other pages (like category archives), modify the conditional. For example, for category pages:
if ( $query->is_category() ) {
$query->set( 'ignore_sticky_posts', 1 );
}
You can combine conditions or apply to all archive pages:
// Exclude sticky posts on homepage and all archives (category, tag, author, date)
if ( $query->is_home() || $query->is_archive() ) {
$query->set( 'ignore_sticky_posts', 1 );
}
Important Notes
- This method only changes the display order. Sticky posts retain their status and will still appear at the top in other main queries where
ignore_sticky_postsis not set. - If you call sticky posts separately elsewhere (using
WP_Queryorget_posts), you can control them with parameters like'post__in' => get_option( 'sticky_posts' ); they won't be affected by the main query modification. - Before editing
functions.php, consider creating a child theme or backing up the file.