I'm struggling to find a solution to the following problem.

The main query should only check pages and selected custom post types for the selected post type name.

  1. address.com/flower-post-name [custom-post-type]
  2. address.com/flower-page-name [page]

As you can see, my custom post type has the slug removed from permalink using this solution vip.wordpress.com.

The problem I encountered is that the query also checks if there are attachments with the same slug. So despite having an unique slugs for both posts and pages there are still conflicts with my media library.

  1. address.com/post-name [attachment] -> displayed
  2. address.com/post-name [custom-post-type] -> should be displayed

Is there a way to exclude attachments from main query?

This is the code I'm using:

function vipx_parse_request_tricksy( $query ) {
// Only noop the main query
if ( ! $query->is_main_query() )
// Only noop our very specific rewrite rule match
if ( 2 != count( $query->query )
    || ! isset( $query->query['page'] ) )
// 'name' will be set if post permalinks are just post_name, otherwise the page rule will match
if ( ! empty( $query->query['name'] ) )
    $query->set( 'post_type', array( 'flower', 'page' ) );
} add_action( 'pre_get_posts', 'vipx_parse_request_tricksy' );

From my understanding the query is being rewritten to check if there's a custom post type 'flower' then 'page' with the particular slug.

$query->set( 'post_type', array( 'flower', 'page', 'attachment' ) );

I tried this approach, but it did not work. Wordpress is still checking if the slug corresponds to attachments first and the page displayed is a media page, instead of custom post type page.

1 Answer 1


Rather than using pre_get_posts hook, you could try a better approach which will work perfectly with parse_request hook. The code -

add_action( 'parse_request', 'my_cpt_parse_request', 11, 2 );
function my_cpt_parse_request( $wp )
    if( isset($wp->request) && !is_admin() )
        $requests = explode('/', $wp->request);
        $request_amount = count($requests);
        $post_name = array_shift( $requests );

        // if an attachment has been queried under this or another post type, skip checking
        if( $request_amount > 1 && !in_array( $requests['0'], array('feed', 'page') ) )

        global $wpdb;
        $post = $wpdb->get_row( $wpdb->prepare( 
            "SELECT * FROM $wpdb->posts WHERE post_status='publish' AND post_type=%s AND post_name=%s",

        if( $post && isset($post->ID) ){
            $wp->set_query_var( 'flower', $post->post_name );
            $wp->set_query_var( 'post_type', 'flower' );
            $wp->set_query_var( 'name', $post->post_name );
            $wp->set_query_var( 'attachment', false );
            $wp->set_query_var( 'error', false );

Remove the pre_get_post hook and use this one, but keep the post_type_link hook as it is.

  • Thank you for the answer. It worked partially. The page is not recognized as custom post type, but as a normal post. I have a separate template single-flower, but it was not used by wordpress. EDIT: other custom posts which have no duplicated slug with attachments work as intended, single-flower temmplate is used. Also wanted to ask, does your approach have a significant impact on the performance? Thanks.
    – WhyCry
    Feb 24, 2014 at 17:47
  • It should define the custom post type thought, perhaps try the updated code. This code just make one additional query, so performance will not be halted at all.
    – Shazzad
    Feb 24, 2014 at 17:54
  • Unfortunately it didn't work, wordpress is still using single.php instead of single-flower.php. Is there any other solution?
    – WhyCry
    Feb 24, 2014 at 18:02
  • Is the retrieved post is a flower post or it's a built-in simple post ?
    – Shazzad
    Feb 24, 2014 at 18:08
  • I think it's custom post, but with a bad template. Can't say for sure, my custom post types are based on pods framework, all the content is read by this template.
    – WhyCry
    Feb 24, 2014 at 18:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.