How7oHow7o
  • Home
  • Tools
    • All Tools
    • Image Tools
    • Text & String Tools
    • Video Tools
    • Developer Tools
    • PDF Tools
    • Calculators & More
  • Prank Screens
  • Learn
  • Blog
  • Contact
Reading: How to Apply pre_get_posts on Custom Post Types in WordPress
Share
Notification Show More
Font ResizerAa
How7oHow7o
Font ResizerAa
  • Tools
  • Prank Screens
  • Learn
  • Blog
Search
  • Home
  • Tools
    • All Tools
    • Image Tools
    • Text & String Tools
    • Video Tools
    • Developer Tools
    • PDF Tools
    • Calculators & More
  • Prank Screens
  • Learn
  • Blog
  • Contact
Follow US
© 2024–2026 How7o. All rights reserved.
How7o > Free Laravel, PHP, WordPress & Server Tutorials > Web Development > How to Apply pre_get_posts on Custom Post Types in WordPress
Web Development

How to Apply pre_get_posts on Custom Post Types in WordPress

how7o
By how7o
Last updated: May 10, 2026
8 Min Read
WordPress pre_get_posts scoped to a custom post type with is_post_type_archive
SHARE

To scope a wordpress pre_get_posts custom post type hook, check $query->is_post_type_archive('your_type') inside the callback — it returns true only on that archive URL and the main query. Without a scope check, pre_get_posts fires on every WP_Query in the request (widgets, related posts, REST calls) and leaks your ordering or filter into queries you didn’t mean to touch. This guide shows the three common check forms, the mandatory guards around them, and when to modify tax_query safely.

Contents
  • TL;DR
  • The three guards that belong on every pre_get_posts
  • Check 1 — $query->is_post_type_archive()
  • Check 2 — is_post_type_archive() conditional tag
  • Check 3 — $query->get('post_type')
  • Modifying meta_query and tax_query
  • Also-useful scope checks
  • Frequently asked questions
  • Related guides
  • References

Last verified: 2026-04-23 on WordPress 6.5 and PHP 8.3. Originally published 2022-07-17, rewritten and updated 2026-04-23.

TL;DR

add_action( 'pre_get_posts', 'how7o_customize_cpt_archive' );

function how7o_customize_cpt_archive( $query ) {
    if ( is_admin() || ! $query->is_main_query() ) {
        return;
    }

    if ( $query->is_post_type_archive( 'custom_post_type' ) ) {
        $query->set( 'meta_key', 'votes' );
        $query->set( 'orderby', 'meta_value_num' );
        $query->set( 'order', 'DESC' );
    }
}

The three guards that belong on every pre_get_posts

  • is_admin() — skip the hook in the WordPress admin. The admin list tables are their own WP_Querys; unless you specifically want to alter them, stay out.
  • $query->is_main_query() — skip secondary queries. Widgets, block queries, related posts, REST API endpoints all fire through WP_Query and hit the hook too. The main query is the one WordPress built from the URL.
  • A scope check for the specific page(s) you want to affect — one of the three forms below.

Skip any of these and the customization leaks. The cost of the guards is one extra condition per request.

Check 1 — $query->is_post_type_archive()

if ( $query->is_post_type_archive( 'event' ) ) {
    // runs on /events/ URL, main query
}

Returns true when the request is the custom-post-type archive (typically /events/ if your CPT uses has_archive => true). Doesn’t fire for single posts of that type, taxonomy archives, or search results that happen to include that type. This is the form you want 90% of the time.

Check 2 — is_post_type_archive() conditional tag

if ( is_post_type_archive( 'event' ) ) {
    // same result as $query->is_post_type_archive('event')
}

Same semantics, global function form. $query->is_post_type_archive() is more explicit inside a pre_get_posts callback — it’s obviously asking about the query being processed, not some ambient global state — so prefer the method form. The global tag is there for compatibility with older codebases.

Check 3 — $query->get('post_type')

if ( $query->get( 'post_type' ) === 'event' ) {
    // fires any time a query targets the 'event' post type
}

Reads the post_type query var directly. Fires anywhere the query specifies that post type — archive pages, some REST endpoints, explicit new WP_Query(['post_type' => 'event']) calls. Use this when you want the customization to apply broadly, not just on the archive URL. Combine with is_main_query to still avoid affecting secondary queries.

Watch out when your CPT is accessed via multiple query shapes — post_type can be a string ('event') or an array (['event', 'post']) on queries that mix types. For the array case: in_array('event', (array) $query->get('post_type'), true).

wordpress pre_get_posts custom post type — three scope checks compared

Modifying meta_query and tax_query

$query->set('meta_query', [...]) replaces the existing value. On archive pages WordPress may have already built part of the query (for example the tax_query on a category archive), and overwriting wipes that. Merge instead:

// Merge with existing, don't replace
$meta_query = $query->get( 'meta_query' ) ?: array();

$meta_query[] = array(
    'key'     => 'featured',
    'value'   => '1',
    'compare' => '=',
);

$query->set( 'meta_query', $meta_query );

Same pattern for tax_query. The ?: [] gives you a usable starting value when nothing was there yet, and the append leaves any existing clauses alone.

Also-useful scope checks

$query->is_home()           // the blog page
$query->is_category()       // any category archive
$query->is_category( 'news' ) // specifically the 'news' category
$query->is_tag( 'featured' ) // a specific tag archive
$query->is_tax( 'genre' )    // a custom-taxonomy archive
$query->is_search()          // search results
$query->is_author()          // author archive

Combine with the three mandatory guards (is_admin / is_main_query / scope) to target exactly the archive you want to modify.

Frequently asked questions

What’s the simplest wordpress pre_get_posts custom post type check?

$query->is_post_type_archive('custom_type') inside a pre_get_posts callback. It returns true only when the request is the archive for that custom post type — not for the regular blog, category pages, taxonomy pages, or individual posts. Combine it with is_main_query() and the !is_admin() guard so you only modify the intended frontend query.

When should I use is_post_type_archive vs $query->get('post_type')?

is_post_type_archive is the higher-level answer — it reflects the URL context (is this the /events/ archive page?), so it naturally fits the main query on archive URLs. $query->get('post_type') === 'event' is a lower-level check that answers “is this query specifically for events?” — useful when you want the hook to also fire on secondary queries, REST endpoints, or admin-list screens where archive semantics don’t apply.

Why does the hook change all my default posts when I skip the scope check?

pre_get_posts fires on every WP_Query — the main query, widget queries, related-posts queries, REST API queries, dashboard widgets. Without a scope check (is_main_query, is_post_type_archive, etc.), your ordering or filter leaks into all of those and you get unexpected output everywhere. Treat scope checks as mandatory.

Should I check is_admin() or !is_admin()?

Skip the hook in admin (if (is_admin()) return;) when your changes are user-facing (frontend post ordering, frontend filtering). Run the hook in admin when you’re intentionally modifying the admin list table (hiding posts from a certain role, changing the default sort in Posts → All Posts). The default is to skip — most customizations are frontend-only.

Can I modify meta_query or tax_query in pre_get_posts?

Yes, using $query->set('meta_query', [...]) and $query->set('tax_query', [...]). Be careful: set replaces the existing value. If you want to add a clause without wiping whatever WordPress already computed (category archive’s tax_query, for example), read the current value first, merge, then set: $tax_query = $query->get('tax_query') ?: []; $tax_query[] = [...]; $query->set('tax_query', $tax_query);.

Related guides

  • How to Order Posts by Meta Value in WordPress — the most common pre_get_posts customization.
  • How to Get Posts by Date Range in WordPress — adding date_query via pre_get_posts.
  • How to Get the Current Category ID in WordPress — context for taxonomy archive checks.
  • How to Disable Revisions and Autosave in WordPress — another filter-driven customization.

References

WordPress developer reference for pre_get_posts and WP_Query conditional methods: developer.wordpress.org/reference/hooks/pre_get_posts.

TAGGED:phpwordpress

Sign Up For Daily Newsletter

Be keep up! Get the latest breaking news delivered straight to your inbox.
[mc4wp_form]
By signing up, you agree to our Terms of Use and acknowledge the data practices in our Privacy Policy. You may unsubscribe at any time.
Share This Article
Facebook Copy Link Print
Previous Article WordPress logged-in menu swap — register_nav_menus + wp_nav_menu with is_user_logged_in ternary How to Display Different Menus to Logged-In Users in WordPress
Next Article WordPress custom avatar without a plugin — media uploader writes user meta, get_avatar filter renders the image How to Change a User Profile Picture in WordPress Without a Plugin
Leave a Comment

Leave a Reply Cancel reply

You must be logged in to post a comment.

You Might Also Like

Check Bootstrap modal open or closed with jQuery
Web Development

How to Check if a Bootstrap Modal Is Open or Closed with jQuery

4 Min Read
Laravel unique validation that ignores the current record on update
Web Development

How to Validate a Unique Column on Update in Laravel

4 Min Read
GitHub Actions workflow deploying Laravel to a VPS, zero-downtime symlink swap
Web Development

How to Deploy a Laravel App to a VPS with GitHub Actions (Zero-Downtime, No Forge)

11 Min Read
WordPress default posts per page — get_option reads the Settings Reading value
Web Development

How to Get the Default Posts Per Page Value in WordPress

5 Min Read
How7oHow7o

Free browser-based tools, prank screens, and step-by-step tech tutorials. No signup, nothing uploaded.

  • Private by design — your files never leave your device
  • Instant — no signup, no install, no waiting
  • Always free — no trials, no watermarks, no paywalls

Tools

  • PDF Editor
  • Image Upscaler
  • JPEG Compressor
  • Password Generator
  • QR Code Generator
  • Video Trimmer
  • See all tools →

Pranks

  • Cracked Screen Prank
  • Fake Blue Screen (BSOD)
  • Fake Console Update Screen
  • Fake Disk Format
  • Fake Low Battery
  • Fake Virus Scan
  • See all prank screens →

Company

  • About Us
  • Blog
  • Contact
  • Privacy Policy
  • Terms of Service
  • Sitemap
© 2024–2026 How7o. All rights reserved.
Welcome Back!

Sign in to your account

Username or Email Address
Password

Lost your password?