Attention Interested in functions, hooks, classes, or methods? Check out the new WordPress Code Reference!

Plugin API/Action Reference/pre get posts


This hook is called after the query variable object is created, but before the actual query is run.

The pre_get_posts action gives developers access to the $query object by reference (any changes you make to $query are made directly to the original object - no return value is necessary).


<?php add_action'pre_get_posts''your_function_name' ); ?>


Argument is Passed by Reference

The $query object is passed to your function by reference. You do not need to declare globals or return a value. Any changes you make to the object from inside your function are made to the original immediately.

Page Requests

pre_get_posts should not be used to alter the query for single Page requests (page templates) because 'is_page', 'is_singular', 'pagename' and other properties (depending if pretty permalinks are used) are already set by the parse_query() method. See: Query Overview.

Similarly, pre_get_posts will not work if used in template files (e.g., archive.php), since they are called after the query has been completed.

Unless you are intimately familiar with these settings and are willing to coordinate them, it's suggested that you alter the main query for single page requests by using a new WP_Query in the page template itself.

You can check out the following post regarding the use of pre_get_posts on true pages and static front pages where we alter the pagination through pre_get_posts and the filters availble in the WP_Query class and using post injection in order to make pre_get_posts work

Identifying Target Queries

When using pre_get_posts, be aware of the query you are changing. One useful function is is_main_query(), which can help you ensure that the query you are modifying is only the main query. Use it in combination with other conditional tags to only alter the main query on the pages you want.

A Warning About Admin Usage

This filter can also be used to affect admin screen queries. Be sure to check if your modification is affecting your post edit screens. For example, just checking is_main_query() and is_post_type_archive('movie') will also change the query for the edit.php?post_type=movie admin screen, unless you also check for !is_admin()

A Warning About Conditional Functions

pre_get_posts runs before WP_Query has been setup. Some template tags and conditional functions that rely on WP_Query will not work. For example, is_front_page() will not work, although is_home()will work. In such cases, you will need to work directly with the query vars, which are passed to the pre_get_posts hook as an argument ($query in examples on this page).

Offsets & Pagination

Using the offset argument in any WordPress query can break pagination. If you need to use offset and preserve pagination, please keep in mind that you will need to handle pagination manually. Read the codex article Making Custom Queries using Offset and Pagination for more information.


Exclude categories on your main page

This is how you can exclude categories of posts from displaying in your blog. For example, if you have 2 categories of posts (uncategorized '1' and another '1347') that you don't want to display on your 'home' blog page, you can use the following in your plugin or theme to omit these categories:

function exclude_category( $query ) {
    if ( $query->is_home() && $query->is_main_query() ) {
        $query->set( 'cat', '-1,-1347' );
add_action( 'pre_get_posts', 'exclude_category' );

Show Only One Category on Home Page

Place this code in functions.php to cause the home page to display posts only from one category.

function my_home_category( $query ) {
    if ( $query->is_home() && $query->is_main_query() ) {
        $query->set( 'cat', '123' );
add_action( 'pre_get_posts', 'my_home_category' );

Change "123" to the category ID you wish to display.

Exclude Single Posts by ID From Home Page

Excludes an array of single post ID's from your home page

function exclude_single_posts_home($query) {
  if ($query->is_home() && $query->is_main_query()) {
    $query->set('post__not_in', array(7,11));

add_action('pre_get_posts', 'exclude_single_posts_home');

Exclude Pages from Search Results

Often when readers of your blog search for something, it is most likely to be in posts rather than pages. So, you might like to exclude pages in your search results. It is possible to create an action hook that limits the search results by showing only results from posts.

The following example demonstrates how to do that:

function search_filter($query) {
  if ( !is_admin() && $query->is_main_query() ) {
    if ($query->is_search) {
      $query->set('post_type', 'post');


Include Custom Post Types in Search Results

function search_filter($query) {
  if ( !is_admin() && $query->is_main_query() ) {
    if ($query->is_search) {
      $query->set('post_type', array( 'post', 'movie' ) );


Only Display Search Results After Specific Date

Uses the date_query from WP_Query. In this example, only returns results after 1/1/2013

add_action( 'pre_get_posts', 'date_search_filter' );
function date_search_filter($query) {

if ( ! is_admin() && $query->is_main_query() ) {
    if ($query->is_search) {

$query->set( 'date_query', 
    [    [
    'after'     => 'January 1st, 2013',
    'inclusive' => true,
    ]    ] 

Changing the number of posts per page, by post type

WordPress includes a single global setting for controlling the number of posts that appear on one loop page (under "Blog pages show at most" in the admin"). It is possible to create an action hook that changes / overrides the posts_per_page setting on a case-by-case basis. Best of all, this is done before the query is even executed (so there is no performance cost)!

The following example demonstrates how to override the page size ('posts_per_page') for archives of specific post types:

function hwl_home_pagesize( $query ) {
    if ( is_admin() || ! $query->is_main_query() )

    if ( is_home() ) {
        // Display only 1 post for the original blog archive
        $query->set( 'posts_per_page', 1 );

    if ( is_post_type_archive( 'movie' ) ) {
        // Display 50 posts for a custom post type called 'movie'
        $query->set( 'posts_per_page', 50 );
add_action( 'pre_get_posts', 'hwl_home_pagesize', 1 );

Changing the number of posts per page on a feed

You can override the number of posts to show up in a specific feed using the posts_per_rss setting.

function bdn_feed_set_posts_per_rss( $query ) {

	if( !$query->is_main_query() || !is_feed() )
	//set conditional

	$query->set( 'posts_per_rss', 50 );


Sample WP_Query Object

For reference, this is one possible example of the WP_Query object ($query) exposed by this hook. For more detail, you can also review the WP_Query codex page.

WP_Query Object
    [query_vars] => Array
            [page] => 
            [pagename] => blog
            [error] => 
            [m] => 0
            [p] => 0
            [post_parent] => 
            [post_type] =>
            [subpost] => 
            [subpost_id] => 
            [attachment] => 
            [attachment_id] => 0
            [name] => 
            [static] => 
            [page_id] => 0
            [second] => 
            [minute] => 
            [hour] => 
            [day] => 0
            [monthnum] => 0
            [year] => 0
            [w] => 0
            [category_name] => 
            [tag] => 
            [cat] => 
            [tag_id] => 
            [author_name] => 
            [feed] => 
            [tb] => 
            [paged] => 0
            [comments_popup] => 
            [meta_key] => 
            [meta_value] => 
            [preview] => 
            [s] => 
            [sentence] => 
            [fields] => 
            [category__in] => Array

            [category__not_in] => Array

            [category__and] => Array

            [post__in] => Array

            [post__not_in] => Array

            [tag__in] => Array

            [tag__not_in] => Array

            [tag__and] => Array

            [tag_slug__in] => Array

            [tag_slug__and] => Array


    [tax_query] => 
    [meta_query] => 
    [post_count] => 0
    [current_post] => -1
    [in_the_loop] => 
    [comment_count] => 0
    [current_comment] => -1
    [found_posts] => 0
    [max_num_pages] => 0
    [max_num_comment_pages] => 0
    [is_single] => 
    [is_preview] => 
    [is_page] => 
    [is_archive] => 
    [is_date] => 
    [is_year] => 
    [is_month] => 
    [is_day] => 
    [is_time] => 
    [is_author] => 
    [is_category] => 
    [is_tag] => 
    [is_tax] => 
    [is_search] => 
    [is_feed] => 
    [is_comment_feed] => 
    [is_trackback] => 
    [is_home] => 1
    [is_404] => 
    [is_comments_popup] => 
    [is_paged] => 
    [is_admin] => 
    [is_attachment] => 
    [is_singular] => 
    [is_robots] => 
    [is_posts_page] => 1
    [is_post_type_archive] => 
    [query_vars_hash] => 41032f87127fba65fb6743b1e97d8662
    [query_vars_changed] => 
    [thumbnails_cached] => 
    [query] => Array
            [page] => 
            [pagename] => blog

    [queried_object] => stdClass Object
            [ID] => 16
            [post_author] => 1
            [post_date] => 2012-01-31 17:23:57
            [post_date_gmt] => 2012-01-31 17:23:57
            [post_content] => 
            [post_title] => Blog
            [post_excerpt] => 
            [post_status] => publish
            [comment_status] => open
            [ping_status] => open
            [post_password] => 
            [post_name] => blog
            [to_ping] => 
            [pinged] => 
            [post_modified] => 2012-01-31 17:23:57
            [post_modified_gmt] => 2012-01-31 17:23:57
            [post_content_filtered] => 
            [post_parent] => 0
            [guid] => 



Code Documentation

  • Class: WP_Query - Detailed Overview of class WP_Query
  • Class: WP_Comment_Query - Class for comment-related queries
  • Class: WP_User_Query - Class for user-related queries
  • Object: $wpdb - Overview on the use of the $wpdb object
  • Function: set_query_var()
  • Function: get_query_var()
  • Function: query_posts() - Create additional custom query
  • Function: get_post() - Take an ID of an item and return the records in the database for that article
  • Function: get_posts() - A specialized function that returns an array of items
  • Function: get_pages() - A specialized function that returns an array of pages
  • Function: have_posts() - A condition that determines whether the query returned an article
  • Function: the_post() - Used to automatically set the loop after a query
  • Function: rewind_posts() - Clears the current loop
  • Function: setup_postdata() - Sets the data for a single query result within a loop
  • Function: wp_reset_postdata() - Restores the previous query (usually after a loop within another loop)
  • Function: wp_reset_query()
  • Function: is_main_query() - Ensures that the query that is being changed is only the main query
  • Action Hook: pre_get_posts - Change WordPress queries before they are executed
  • Action Hook: the_post - Modify the post object after query
  • Filter Hook: found_posts - Changes the value of the object found_posts WP_Query