admin管理员组

文章数量:1323157

I have a simple WP_Query:

$loop = new WP_Query(array( 
      'post_type' => array('image', 'video'), 
      'category_name' => $cat, 
      'meta_key'=>'total_votes', 
      'orderby'=>'date meta_value_num'
));

How can I alter this so that it return only videos with the tag editor-pick while still returning all images regardless of tags?

I'm looking for a filter to add onto the MySQL query so that order and pagination remain intact.

I have a simple WP_Query:

$loop = new WP_Query(array( 
      'post_type' => array('image', 'video'), 
      'category_name' => $cat, 
      'meta_key'=>'total_votes', 
      'orderby'=>'date meta_value_num'
));

How can I alter this so that it return only videos with the tag editor-pick while still returning all images regardless of tags?

I'm looking for a filter to add onto the MySQL query so that order and pagination remain intact.

Share Improve this question edited Dec 30, 2014 at 18:33 jetlej asked Dec 2, 2014 at 21:11 jetlejjetlej 5721 gold badge6 silver badges24 bronze badges 8
  • Where is this query happening? A widget? – Tom J Nowell Commented Dec 3, 2014 at 1:50
  • Yes, you're going to want to use a query filter, along with some more advanced sql queries to achieve this goal. Just using the WP_Query object won't achieve this alone. – Hybrid Web Dev Commented Dec 3, 2014 at 4:56
  • 1 I'm sure @tf is pretty close to solve this for you with his solution (+1), but in the meanwhile I wonder if this kind of experiment can help you? – birgire Commented Dec 30, 2014 at 19:03
  • @birgire, that's exactly what I need! Thanks so much for putting together that plugin! – jetlej Commented Dec 30, 2014 at 23:59
  • 1 The reason I wrote that it wasn't supported is that in general one sub-query might not contain any meta query, so ordering by a meta value might then not make sense. We must order by a field that's contained in both (all) sub-queries. I just played with it and found a way to order the combined query (where all the sub-queries contain a meta query) by a meta value, I will update that plugin version (plus some bug fixes) on Github in couple of days. Then we could continue on the Issue tracker over there. – birgire Commented Dec 31, 2014 at 11:00
 |  Show 3 more comments

5 Answers 5

Reset to default 4 +50

I happened to be working on something similar today and just remembered you were looking for something like this, so let me share it with you.

Here's how one can use the posts_where filter to restrict the WP_Query, to posts in some custom post type cpt1 OR another post type cpt2 that's attached to some taxonomy term.

Here's an example:

add_filter( 'posts_where', 'wpse_posts_where' );
$loop = new WP_Query( $args );

where

/**
 * Restrict WP_Query to ( cpt1 OR cpt2 attached to a given term in some taxonomy).
 *
 * @see http://wordpress.stackexchange/a/173889/26350
 */

function wpse_posts_where( $where )
{
    global $wpdb;

    // Run this filter callback only once:
    remove_filter( current_filter(), __FUNCTION__ );

    // Modify this to your needs:  
    $cpt1       = 'image';     
    $cpt2       = 'video';    
    $taxonomy   = 'post_tag';     // Related to cpt2
    $term_slug  = 'editor-pick';  // Related to cpt2    

    // Get the term info for the term_taxonomy_id:
    $term = get_term_by( 'slug', $term_slug, $taxonomy );

    // Modify the SQL query:
    if( ! is_wp_error( $term ) )
    {
        $where .= " AND ( {$wpdb->posts}.post_type = '{$cpt1}' 
            OR {$wpdb->posts}.post_type = '{$cpt2}' 
            AND {$wpdb->posts}.post_status = 'publish'
            AND {$wpdb->posts}.ID IN (
                SELECT object_id FROM {$wpdb->term_relationships} 
                WHERE term_taxonomy_id IN ( {$term->term_taxonomy_id} ) ) ) ";
    }
    return $where;
}

where you might have to modify it further to your needs.

Unfortunately, you can't. At least not with a single WP_Query, that is. What you could do, however, is run two separate queries - one for each post type - then combine the results. Like so:

$args = array( 
    'post_type'     => 'image',
    'category_name' => $cat,
    'meta_key'      => 'total_votes',
    'orderby'       => 'date meta_value_num',
);
$loop = new WP_Query( $args );

$args = array( 
    'post_type'     => 'video',
    'category_name' => $cat,
    'tag'           => 'editor-pick',
    'meta_key'      => 'total_votes',
    'orderby'       => 'date meta_value_num',
);
$loop2 = new WP_Query( $args );

$loop->posts = array_merge( $loop->posts, $loop2->posts );
$loop->found_posts += $loop2->found_posts;
$loop->max_num_pages = ceil( $loop->found_posts / $loop->query_vars[ 'posts_per_pages' ] );

Note: This is untested code. I hope it may be of help to you, though.

// tell WordPress about our new query var

function wpse52480_query_vars( $query_vars ){   
    $query_vars[] = 'my_special_query';
    return $query_vars;
}
add_filter( 'query_vars', 'wpse52480_query_vars' );

// check if our query var is set in any query

function wpse52480_pre_get_posts( $query ){    
    if( isset( $query->query_vars['my_special_query'] ) )

        // do special stuff

    return $query;
}
add_action( 'pre_get_posts', 'wpse52480_pre_get_posts' );

and in the template:

// set the query var (along with whatever others) to trigger the filter

$args = array(
    'my_special_query' => true
);
$my_secondary_loop = new WP_Query( $args );

You can use the taxonomy params to achieve this https://codex.wordpress/Class_Reference/WP_Query#Taxonomy_Parameters

One WP_Query-way of doing this is to fetch all other categories than the ones you want to use, and use operator => NOT IN like so:

$terms_to_use = [ 10, 12, 15 ];

$all_other_terms = get_terms( [
    'taxonomy' => 'category',
    'fields' => 'slugs',
    'exclude' => $terms_to_use,
] );

$args = [
    'post_type' => [ 'post', 'my_cpt' ],
    'tax_query' => [
        [
            'taxonomy' => 'category',
            'operator' => 'NOT IN',
            'terms' => $all_other_terms
        ]
    ]    
];

This way, you will only get posts with categories 10, 12 and 15, and you will get all posts from my_cpt.

本文标签: wp queryWPQuery with two post typesbut requiring category on only one of those post types