3

Here's the situation;

I am using get_terms to retrieve all terms from Tax 1 with posts associated with it. Using the following

$args = array(
            'hide_empty'    =>  0,
            'orderby'       =>  'name',
            'taxonomy'      =>  'tax_1'
        );

$terms  =   get_terms( $args );

Pretty simple. However that returns all terms, and does not consider the second taxonomy Tax 2 which I want to compare against term x

Ultimately I want to get all Tax 1 terms that have posts which also have Tax 2 term x

I could most likely to a query directly on posts and create an array of terms where the post has both of the above but that seems a bit messy, I am hoping there is a way to query this directly.

Thanks

2 Answers 2

5

Just to start, you say "I am using get_terms to retrieve all terms from Tax 1 with posts associated with it", however your actual code gets all terms in that taxonomy regardless of whether or not they have posts. You need to set hide_empty to true.

So with that out of the way, the bad news: You won't be able to do this with get_terms(). That type of information doesn't exist without querying posts and comparing the terms. So the messy solution you wanted to avoid is unfortunately necessary.

Ultimately I think this is a situation where you might be better off just using SQL. This code will use $wpdb to get terms from Taxonomy A that have any posts of a given post type that have a specific term in Taxonomy B:

$post_type  = 'post';
$taxonomy_a = 'post_tag';
$taxonomy_b = 'category';
$term_b_id  = 12;

$query = $wpdb->prepare(
    "SELECT DISTINCT
        terms.*
    FROM
        `wp_terms` terms
    INNER JOIN
        `wp_term_taxonomy` tt1 ON
            tt1.term_id = terms.term_id
    INNER JOIN
        `wp_term_relationships` tr1 ON
            tr1.term_taxonomy_id = tt1.term_taxonomy_id
    INNER JOIN
        `wp_posts` p ON
            p.ID = tr1.object_id
    INNER JOIN 
        `wp_term_relationships` tr2 ON
            tr2.object_ID = p.ID
    INNER JOIN 
        `wp_term_taxonomy` tt2 ON
            tt2.term_taxonomy_id = tr2.term_taxonomy_id
    WHERE
        p.post_type = %s AND
        p.post_status = 'publish' AND
        tt1.taxonomy = %s AND
        tt2.taxonomy = %s AND
        tt2.term_id = %d",
    [
        $post_type,
        $taxonomy_a,
        $taxonomy_b,
        $term_b_id,
    ]
);

$results = $wpdb->get_results( $query );

if ( $results ) {
    $terms = array_map( 'get_term', $results );
}

So that code gets all Tags that have Posts that are assigned to the Category with the ID 12.

The last little bit with get_term() ensures that the final array contains the same WP_Term objects that you would get by running get_terms().

3

You could use the tax_query argument, for example:

'tax_query' => array(
    'relation' => 'AND',
    array(
        'taxonomy' => 'tax1',
        'field'    => 'slug',
        'terms'    => $terms,
    ),
    array(
        'taxonomy' => 'tax2',
        'field'    => 'slug',
        'terms'    => $terms,
    )
)

To get all posts which have both terms. You can then use get_terms and pass the object_ids as a parameter. See the WP_Term_Query documentation for more details.

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.