WordPress is an open-source platform that is known for its flexibility, allowing developers to customize almost every aspect of the platform to suit specific needs. One of the most useful tools for developers is the pre_get_posts in WordPress. This hook allows you to modify main query conditions under specific circumstances, thereby enabling smooth post-page-custom post-type output control.
This article covers pre_get_posts action implementation strategies alongside WordPress core compatibility and retains pagination functionality. By the end, you’ll have a clear understanding of how to modify the main query dynamically and safely.
What is pre_get_posts in WordPress?
The pre_get_posts action is triggered just before WordPress executes the main query. The main query determines what content to display on the current page, such as posts on the home page, a single post, or an archive. By hooking into pre_get_posts, you can modify this query before WordPress retrieves the results from the database.
For example:
- The platform modifies the quantity of posts which appear per page.
- Filtering posts by category or tag.
- Displaying specific custom post types on an archive page.
- Excluding certain posts from the main query.
Why Use pre_get_posts Instead of Other Methods?
Historically, developers used query_posts() to modify queries, but this approach has significant drawbacks. Using query_posts() overwrites the main query and creates a secondary query, which can break functionality like pagination and lead to performance issues.
These action solves problems by allowing you to modify the original query safely without overwriting it. This method ensures that WordPress correctly handles pagination and other features.
Step-by-Step Guide to Using pre_get_posts
1. Hook into pre_get_posts
To use pre_get_posts, you must hook into it using the add_action() function in your theme’s functions.php file or a custom plugin. Here’s a basic example:
add_action('pre_get_posts', 'modify_main_query');
function modify_main_query($query) {
    // Always check if it's the main query
    if (!$query->is_main_query()) {
        return;
    }
    // Example: Modify the home page query
    if ($query->is_home()) {
        $query->set('posts_per_page', 5);
    }
}
2. Check if the Query is the Main Query
One of the most critical steps is ensuring you’re modifying only the main query and not any secondary queries. Use $query->is_main_query() to verify this.
if (!$query->is_main_query()) {
    return;
}
This validation process helps you focus on WordPress main query, which is responsible for paginating content on the current display page. In the absence of this check, you could make modifications to other queries which would result in unpredictable behavior.
Example Scenarios for pre_get_posts
Let’s dive into some common use cases for modifying the main query.
1. Modify the Number of Posts on the Home Page
To change the number of posts displayed on the home page:
add_action('pre_get_posts', 'custom_home_page_query');
function custom_home_page_query($query) {
    if ($query->is_main_query() && $query->is_home()) {
        $query->set('posts_per_page', 10); // Display 10 posts per page
    }
}
2. Display a Custom Post Type on an Archive Page
If you have a custom post type (e.g., “products”) and want to include it on your archive page:
add_action('pre_get_posts', 'add_custom_post_type_to_archive');
function add_custom_post_type_to_archive($query) {
    if ($query->is_main_query() && $query->is_post_type_archive('products')) {
        $query->set('posts_per_page', 12); // Display 12 products per page
    }
}
3. Exclude a Specific Category from the Blog
To exclude posts from a specific category (e.g., “Uncategorized”) on the blog page:
add_action('pre_get_posts', 'exclude_category_from_blog');
function exclude_category_from_blog($query) {
    if ($query->is_main_query() && $query->is_home()) {
        $query->set('cat', '-1'); // Exclude category with ID 1
    }
}
4. Include Multiple Categories in an Archive
To display posts from multiple categories:
add_action('pre_get_posts', 'include_categories_in_archive');
function include_categories_in_archive($query) {
    if ($query->is_main_query() && $query->is_archive()) {
        $query->set('category__in', [2, 3, 4]); // Include categories with IDs 2, 3, and 4
    }
}
5. Modify Search Results
You can customize search results to include specific post types or exclude certain content:
add_action('pre_get_posts', 'customize_search_results');
function customize_search_results($query) {
    if ($query->is_main_query() && $query->is_search()) {
        $query->set('post_type', ['post', 'page']); // Include posts and pages in search
        $query->set('posts_per_page', 15); // Limit search results to 15 per page
    }
}
Important Considerations When Using pre_get_posts
Target Only the Front-End Queries
Always ensure that your modifications apply only to the front end by excluding admin queries:
if (is_admin()) {
    return;
}
Without this check, your changes might affect queries in the WordPress admin area, potentially causing errors or unexpected results.
- Preserve Pagination
When modifying query variables, ensure you don’t inadvertently break pagination. Setting posts_per_page or paged incorrectly can disrupt the pagination links. - Avoid Overloading the Query
Adding too many conditions or complex filters can slow down the query and affect your site’s performance. Test your modifications thoroughly to ensure they don’t introduce unnecessary load on the database. - Do Not Use query_posts()
As mentioned earlier, avoid using query_posts() because it overwrites the main query, breaks pagination, and can lead to performance issues. The pre_get_posts action is a safer and more efficient alternative.
Debugging and Testing
When working with pre_get_posts, debugging is essential to ensure your changes are applied correctly. Here are some tips:
Log the Query
Use the error_log() function to check the query variables:
error_log(print_r($query, true));
Enable Debug Mode
Set WP_DEBUG to true in your wp-config.php file to display PHP errors and warnings:
define('WP_DEBUG', true);
Use Plugins
Plugins like Query Monitor or Debug Bar can help you inspect queries and understand how your changes affect the output.
Frequestly Asked Questions:
Conclusion
Through the pre_get_posts action, users can modify WordPress queries without damaging core features such as pagination. By targeting main queries while avoiding query_posts() breakdown and conducting thorough tests, content displays that match your site requirements become achievable. Whether you’re working with custom post types, categories, or taxonomies, pre_get_posts offers a clean, efficient way to control how content is displayed on your site.
About the writer
Hassan Tahir wrote this article, drawing on his experience to clarify WordPress concepts and enhance developer understanding. Through his work, he aims to help both beginners and professionals refine their skills and tackle WordPress projects with greater confidence