Get_terms + hide_empty + post meta_query

get_terms îmi dă terms dintr-o taxonomie, dar hide_empty nu ajută foarte mult dacă vreau să afișez doar terms care au post-uri cu un anumit status.

Caz concret, am un post type jobs și taxonomie pentru categorii. Un job poate fi deschis sau nu, iar get_terms nu știe - sau cel puțin eu nu mi-am dat seama cum - să filtreze doar categoriile care au job-uri deschise (un meta_key job_is_open cu valoarea 1).

Din fericire, terms_clauses este destul de flexibil, prin urmare a ieșit asta:

<?php 

$metaQuery = [
  [
    'key' => 'job_is_open',
    'value' => 1,
    'compare' => '=',
  ],
];

$categories = get_terms([
  'taxonomy' => 'job-category',
  'post_meta_query' => $metaQuery,
]);


add_filter('terms_clauses', function ($clauses, $tax, $args) {
  if (!empty($args['post_meta_query'])) {
    global $wpdb;

    $clauses['fields'] .= ', p.ID, pm.* ';

    if ($args['parent'] > 0) {
      $join[] = " INNER JOIN {$wpdb->term_relationships} AS tr ON tr.term_taxonomy_id = tt.parent";
    } else {
      $join[] = " INNER JOIN {$wpdb->term_relationships} AS tr ON tr.term_taxonomy_id = t.term_id";
    }

    $join[] = " INNER JOIN {$wpdb->posts} AS p ON p.ID = tr.object_id";
    $join[] = " INNER JOIN {$wpdb->postmeta} AS pm on pm.post_id = p.ID";

    $clauses['join'] .=  implode(' ', $join);

    foreach ($args['post_meta_query'] as $q) {
      $clauses['where'] .= " AND pm.meta_key = '{$q['key']}' AND pm.meta_value {$q['compare']} '{$q['value']}' ";
    }

    $clauses['orderby'] = ' GROUP BY t.term_id ' . $clauses['orderby'];
  }

  return $clauses;
}, 10, 3);

Nu am apucat să testez în amănunt, dar la o primă vedere pare a merge bine. Rămâne de văzut dacă este și vreo problemă de performanță sau de compatibilitate cu alte plugin-uri. :slight_smile:

Edit: este o problemă de caching, în sensul că schimbarea unui metafield nu va actualiza și numărul, ceea ce înseamnă că sunt șanse maxime să nu funcționeze chiar bine. Încă investighez.

Edit2: am actualizat interogările, acum pare în regulă. Nu știu cum funcționează pe DB-uri medii/mari. That’s a problem for a future me :slight_smile:

Edit3: este o problemă la get_terms([ "parent" => xxx ]). În stadiul actual, merge doar dacă un post are toată ierarhia de terms selectată, nu doar ultimul. Este suficient pentru ce am nevoie, posibil voi reveni asupra soluției în viitor.

1 Like