0

How do I get all terms matching:

  1. custom taxonomy "company"
  2. only where term meta (ACF field) "tags" value matches a given string, "Publishing"
  3. only if the term has any posts of custom type "article"
  4. but those posts must only have a taxonomy "format" value of term "viewpoint" or one of its children

... ?

My current code fulfils 1) and 2) above - but I do not how how to add the additional constraints of 3) "article" and 4) "format"...

  $args = array(
     'meta_query' => array(
          array(
             'key'       => 'tags',
             'value'     => 'Publishing',
             'compare'   => 'LIKE'
          )
     ),
     'taxonomy'   => 'company',
     'hide_empty' => false,
     'number'     => 10,
  );
  $orgs_matched = get_terms($args);

  echo '<ul class="list-group list-unstyled">';
  foreach ($orgs_matched as $matching_org) {
     echo '<li class="list-group-item d-flex justify-content-between align-items-center">';
     echo '<span><img src="https://www.google.com/s2/favicons?domain='.get_field( 'domain', $matching_org ).'" class="mr-2"><a href="' . esc_url( get_term_link( $matching_org ) ) . '" alt="' . esc_attr( sprintf( __( 'View all post filed under %s', 'my_localization_domain' ), $matching_org->name ) ) . '">' . $matching_org->name . '</a></span>';
     echo '<span class="badge badge-primary badge-pill">'.$matching_org->count.'</span>';
     echo '</li>';
  }
  echo '</ul>';

In my setup, "article" posts can have associations with:

  • "format" taxonomy term, with name values including "viewpoint".
  • "company" taxonomy terms, which themselves have an ACF Checkbox field, "tags", one of whose values is "Publishing".

I want to get only the "company" terms which have a "tags" value of "Publishing" - but I am only interested in getting those companies which have associated "article" posts that also have taxonomy "format" values of "viewpoint" or beneath.

For each resulting "company' term, I would want to count the number of "article" posts of taxonomy format "viewpoint" and beneath.

Update:

I'm contemplating the method below. Basically, the standard get_terms below, which works, and then stepping through the resulting array to filter out any terms which don't have the term in question...

  $args_for_short = array(
     'taxonomy'   => 'company',
     // ACF "tag" checkbox field
     'meta_query' => array(
          array(
             'key'       => 'tags',
             'value'     => 'Publishing',
             'compare'   => 'LIKE'
          )
     ),
     'orderby'    => 'count',
     'order'      => 'desc',
     'hide_empty' => false,
     'number'     => 10,
  );
  // array: actual term objects
  $orgs_list_short = get_terms($args_for_short);

  // Strip non-Viewpoints out of the terms array
  $orgs_list_short_filtered = array();
  foreach ($orgs_list_short as $org_short_single) {
    // Get all posts of type 'article'
    // For each 'article'
      // Examine associated "format" terms
      // If 'format' term "viewpoint" or child is not present
        // Remove this term from the term object array
  }
  • 3 & 4 aren't possible with get_terms() alone. – Jacob Peattie Jan 2 at 14:15
  • What should I be looking to do in addition, @JacobPeattie? – Robert Andrews Jan 2 at 14:16
  • Honestly, I think you're basically going to need to just do straight up SQL. – Jacob Peattie Jan 2 at 14:17
  • FYI, I added a method under consideration - stripping out of the array created by get_terms any terms which are not associated with the post type and secondary taxonomy term. Seems like it may be a little intensive. Anyone can feel free to weigh in; thanks. – Robert Andrews Jan 4 at 12:53
0

I think I have cracked this, thanks to a Redditor's help. The advice was, effectively:

  • start with 3 and 4 ("Use get_posts() to build an array of post ids that match conditions 3 and 4")
  • then refine by 1 and 2 ("then drop that array into the object_ids argument for your get_terms() query")...

Like...

// 1. First, get all (4) Viewpoint (taxonomy term) (3) Articles (post type).
$vp_post_args = array(
  'post_type' => 'article',
  'tax_query' => array(
        array(
            'taxonomy' => 'format',
            'field' => 'slug',
            'terms' => 'viewpoint'
        )
    ),
    'fields' => 'ids',
  'nopaging'  => 'true',
);

// 2b. [Longlist for WP_Query] Then constrain by (1) Company (taxonomy) and its (2) Tag (ACF Checkbox) value.
    $vp_org_term_args_for_posts = array(
        'object_ids' => $viewpoint_posts_ints,
        'taxonomy'   => 'company',
        'meta_query' => array(
             array(
                'key'       => 'tags',
                'value'     => $tag_section,
                'compare'   => 'LIKE'
             )
        ),
        'hide_empty' => false,
    );
    $viewpoint_org_terms_for_posts = get_terms($vp_org_term_args_for_posts);
0

Furthermore, I found that this kind of use case was something I needed to use in multiple cases on my site.

Hard-coding in some names of post types, taxonomies and meta values would have committed the code to that use case.

So I moved it in to a flexible function. The below represents one of my first positive contributions back to the community, and an increase in my proficiency. That said, please feel free to improve further...

Starting proviso: I chose to move the posts that were type "article" with taxonomy "format" term "viewpoint" (ie. my dimension #4 in the starting post) instead to a new post type "viewpoint".

The function:

/**
 * ==============================================================================
 *                      GET TERMS WITH EXTRA DIMENSIONS
 *  Gets a) Taxonomy Terms that have b) a Meta set and c) are associated with posts
 *  of a particular type.
 *
 *  This is how it works:
 *  1. First, gets IDs of all Posts of specified type.
 *  2. Then, uses that list to constrain getting a) Taxonomy Terms with b) Meta value set.
 *
 *  Arguments:
 *  1. Taxonomy name, 2. Taxonomy Meta Key-and-Value array pair, 3. Post Type name,
 *  4. get_terms 'orderby', 5. get_terms 'order', 6. get_terms 'number'

 *  Example:
 *  $terms_list = get_terms_with_meta_and_posts_of_type('company', array("tags"=>$tax_meta_value), 'viewpoint', 11);
 *
 *  cf. https://www.reddit.com/r/Wordpress/comments/acmw9r/how_can_i_get_terms_but_with_additional_dimensions/
 *  cf. https://wordpress.stackexchange.com/questions/324441/get-terms-but-with-additional-dimensions
 * ==============================================================================
 */

function get_terms_with_meta_and_posts_of_type($taxonomy, $tax_meta, $post_type, $orderby='name', $order='ASC', $number='false') {

    // 1. Gets ID of all Posts of specified type.
    // Nb. If function calle dmultiple times over, consider calling this posts parts once only,
    // in the callig page. If so, place "global $post_ids;" here to pick it up
    $post_args = array(
      'post_type' => $post_type,
      'fields' => 'ids',
      'nopaging'  => 'true',
    );
    $post_ids = get_posts($post_args);

    // 2. Get specified terms associated with those posts
    $term_list_args = array(
        // c) Load only constrained Post IDs in to get_terms():
        'object_ids' => $post_ids,
        // a) Only get specified Terms
        'taxonomy'   => $taxonomy,
        // b) Only company terms with Tags Checkbox value:
        'meta_query' => array(
             array(
                'key'       => key($tax_meta),
                'value'     => reset($tax_meta),
                'compare'   => 'LIKE'
             )
        ),
        // Order
        'orderby'    => $orderby, // want to order by specific post-type count, not all
        'order'      => $order,
        'hide_empty' => false,
        // Number of terms to show in list
        'number'     => $number,
    );
    // Get the terms and return them to whatever called this...
    $terms_list = get_terms($term_list_args);
    return $terms_list;

}

Use-specific, I call it like this...

Example 1:

      // Get terms with: 1. taxonomy name, 2. taxonomy meta key and value, 3. post type name, 4. orderby, 5. order, 6. number of terms
      $terms_list = get_terms_with_meta_and_posts_of_type('company', array("tags"=>$tax_meta_value), 'viewpoint', 'count', 'desc', 11);

And, using the resulting $terms_list, I can cycle through it to output a list of the terms bearing those dimensions.

      // List organisations:
      echo '<div class="list-group list-unstyled">';
      foreach ($terms_list as $term_single) {
           echo '<a href="' . esc_url( get_term_link( $term_single ) ) . '" alt="' . esc_attr( sprintf( __( 'View all post filed under %s', 'my_localization_domain' ), $term_single->name ) ) . '" class="list-group-item list-group-item-action d-flex justify-content-between align-items-center">';
           echo '<span><img src="https://www.google.com/s2/favicons?domain='.get_field( 'domain', $term_single ).'" class="mr-2">' . $term_single->name . '</span>';
           echo '<span class="badge badge-primary badge-pill">'.get_term_post_count_by_type($term_single,'company','viewpoint').'</span>';
           echo '</a>';
      }
      echo '</div>';

Example 2:

Rather than output a list of the whole result, I can also just provide a simple count of the total...

$people_terms = get_terms_with_meta_and_posts_of_type('person', '', 'viewpoint');
$count_people = count($people_terms);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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