Отримайте терміни за систематикою ТА пост_типом


17

У мене є два користувальницькі типи публікацій "закладки" та "фрагменти" та спільний таксономічний "тег". Я можу генерувати список усіх термінів у систематиці за допомогою get_terms (), але не можу зрозуміти, як обмежити список типом публікації. Що я в основному шукаю, є щось подібне:

get_terms(array('taxonomy' => 'tag', 'post_type' => 'snippet'));

Чи є спосіб досягти цього? Ідеї ​​дуже цінують !!

О, я на WP 3.1.1

Відповіді:


11

Ось ще один спосіб зробити щось подібне за допомогою одного SQL запиту:

static public function get_terms_by_post_type( $taxonomies, $post_types ) {

    global $wpdb;

    $query = $wpdb->prepare(
        "SELECT t.*, COUNT(*) from $wpdb->terms AS t
        INNER JOIN $wpdb->term_taxonomy AS tt ON t.term_id = tt.term_id
        INNER JOIN $wpdb->term_relationships AS r ON r.term_taxonomy_id = tt.term_taxonomy_id
        INNER JOIN $wpdb->posts AS p ON p.ID = r.object_id
        WHERE p.post_type IN('%s') AND tt.taxonomy IN('%s')
        GROUP BY t.term_id",
        join( "', '", $post_types ),
        join( "', '", $taxonomies )
    );

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

    return $results;

}

Так! Це робить саме те, що я хочу.
Гевін Хьюїтт

print_r(get_terms_by_post_type(array('category') , array('event') ));шоуWarning: Missing argument 2 for wpdb::prepare()
дев

Я можу помилятися, але в самому верху голови, я не думаю, що ці заяви про "приєднання" спрацюють - тобто вони працюватимуть лише у разі передачі масивів з однозначним значенням. Це відбувається тому, що функція підготовки дозволить уникнути всіх генерованих одинарних лапок і розглядати кожне ціле «об’єднання» по одному рядку.
Кодесміт

14

Тож просто буває, що мені було потрібно щось подібне для проекту, над яким я працюю. Я просто написав запит, щоб вибрати всі повідомлення користувальницького типу, потім перевіряю, які фактичні умови моєї таксономії вони використовують.

Тоді я отримав усі терміни цієї систематики get_terms() і тоді я використав лише ті, які були в обох списках, завершив її функцією, і я закінчив.

Але тоді мені знадобилося більше, ніж просто ідентифікатори: мені потрібні були імена, тому я додав новий аргумент на ім'я, $fieldsщоб я міг сказати функції, що потрібно повернути. Тоді я зрозумів, що get_termsприймає багато аргументів, і моя функція обмежувалася просто термінами, які використовуються типом публікації, тому я додав ще одне ifтвердження, і ви переходите:

Функція:

/* get terms limited to post type 
 @ $taxonomies - (string|array) (required) The taxonomies to retrieve terms from. 
 @ $args  -  (string|array) all Possible Arguments of get_terms http://codex.wordpress.org/Function_Reference/get_terms
 @ $post_type - (string|array) of post types to limit the terms to
 @ $fields - (string) What to return (default all) accepts ID,name,all,get_terms. 
 if you want to use get_terms arguments then $fields must be set to 'get_terms'
*/
function get_terms_by_post_type($taxonomies,$args,$post_type,$fields = 'all'){
    $args = array(
        'post_type' => (array)$post_type,
        'posts_per_page' => -1
    );
    $the_query = new WP_Query( $args );
    $terms = array();
    while ($the_query->have_posts()){
        $the_query->the_post();
        $curent_terms = wp_get_object_terms( $post->ID, $taxonomy);
        foreach ($curent_terms as $t){
          //avoid duplicates
            if (!in_array($t,$terms)){
                $terms[] = $c;
            }
        }
    }
    wp_reset_query();
    //return array of term objects
    if ($fields == "all")
        return $terms;
    //return array of term ID's
    if ($fields == "ID"){
        foreach ($terms as $t){
            $re[] = $t->term_id;
        }
        return $re;
    }
    //return array of term names
    if ($fields == "name"){
        foreach ($terms as $t){
            $re[] = $t->name;
        }
        return $re;
    }
    // get terms with get_terms arguments
    if ($fields == "get_terms"){
        $terms2 = get_terms( $taxonomies, $args );
        foreach ($terms as $t){
            if (in_array($t,$terms2)){
                $re[] = $t;
            }
        }
        return $re;
    }
}

Використання:

Якщо вам потрібен лише перелік ідентифікатора терміна:

$terms = get_terms_by_post_type('tag','','snippet','ID');

Якщо вам потрібен лише перелік назв термінів, виконайте вказані нижче дії.

$terms = get_terms_by_post_type('tag','','snippet','name');

Якщо вам потрібен лише перелік об'єктів терміна, тоді:

$terms = get_terms_by_post_type('tag','','snippet');

І якщо вам потрібно використовувати додаткові аргументи get_terms, такі як: orderby, order, hierarchical ...

$args = array('orderby' => 'count', 'order' => 'DESC',  'hide_empty' => 1);
$terms = get_terms_by_post_type('tag',$args,'snippet','get_terms');

Насолоджуйтесь!

Оновлення:

Щоб виправити підрахунок терміна до конкретної зміни типу публікації:

foreach ($current_terms as $t){
          //avoid duplicates
            if (!in_array($t,$terms)){
                $terms[] = $t;
            }
        }

до:

foreach ($current_terms as $t){
    //avoid duplicates
    if (!in_array($t,$terms)){
        $t->count = 1;
        $terms[] = $t;
    }else{
        $key = array_search($t, $terms);
        $terms[$key]->count = $terms[$key]->count + 1;
    }
}

не було б краще, якщо ви використовуєте (array) $argsзамість списку 4 $ vars? Це дозволить вам не піклуватися про порядок, який ви наводите в аргументах, тому щось подібне, get_terms_by_post_type( $args = array( 'taxonomies', 'args', 'post_type', 'fields' => 'all') )а потім викликайте їх всередині функції $args['taxonomies']. Це допоможе вам утриматися від додавання порожніх значень і запам'ятати порядок своїх аргументів. Я б також запропонував використовувати одинарні лапки замість подвійних. Я бачив, як вони б'ються в п’ять разів швидше.
кайзер

1
@kaiser - Рядки з подвійним цитуванням повинні бути проаналізовані, де як значення, що котируються окремо, завжди трактуються як буквальні. Коли ви використовуєте змінні в рядку, це має сенс, і цілком чудово використовувати подвійні лапки, але для не змінних значень рядків одиничні лапки є більш ідеальними (тому що їх не потрібно буде розбирати) і трохи швидшими (ми ' знову говорити про мілісекунди в більшості випадків).
t31os

@ t31os - Абсолютно правильно. Я по- , як і раніше вважаю за краще 'this is my mood: '.$valueбільш "this is my mood: $value", з - за зручність читання. Що стосується швидкості: Це не мало - я вимірював до п'яти разів. І коли ви використовуєте подвійні лапки у всій своїй тематиці скрізь, вони швидко підсумують, коли у вас буде багато запитів. Все одно добре, що ви це зрозуміли.
кайзер

@ t31os З обговорення я повторно виміряв швидкість "проти 'і я помилявся. Різниця далеко поза тим, що хтось помітив би.
кайзер

1
+1 приємна функція! 2 помилки: $ таксономії використовуються у функції $ таксономія та $ терміни [] = $ c; має бути $ terms [] = $ t;
Роб Вермер

8

Я написав функцію, яка дозволяє передати post_typeв $argsмасиві get_terms()функції:

HT для @braydon для написання SQL.

 /**
 * terms_clauses
 *
 * filter the terms clauses
 *
 * @param $clauses array
 * @param $taxonomy string
 * @param $args array
 * @return array
**/
function terms_clauses($clauses, $taxonomy, $args)
{
    global $wpdb;

    if ($args['post_type'])
    {
        $clauses['join'] .= " INNER JOIN $wpdb->term_relationships AS r ON r.term_taxonomy_id = tt.term_taxonomy_id INNER JOIN $wpdb->posts AS p ON p.ID = r.object_id";
        $clauses['where'] .= " AND p.post_type='{$args['post_type']}'"; 
    }
    return $clauses;
}
add_filter('terms_clauses', 'terms_clauses', 10, 3);

7

Відмінне запитання і ґрунтовні відповіді.

Мені дуже сподобався підхід @jessica за допомогою фільтра terms_clauses, тому що він дуже просто розширює функцію get_terms.

Мій код - це продовження її ідеї, з деяким sql від @braydon для зменшення дублікатів. Він також дозволяє створити масив post_types:

/**
 * my_terms_clauses
 *
 * filter the terms clauses
 *
 * @param $clauses array
 * @param $taxonomy string
 * @param $args array
 * @return array
 **/
function my_terms_clauses($clauses, $taxonomy, $args)
{
  global $wpdb;

  if ($args['post_types'])
  {
    $post_types = $args['post_types'];

    // allow for arrays
    if ( is_array($args['post_types']) ) {
      $post_types = implode("','", $args['post_types']);
    }
    $clauses['join'] .= " INNER JOIN $wpdb->term_relationships AS r ON r.term_taxonomy_id = tt.term_taxonomy_id INNER JOIN $wpdb->posts AS p ON p.ID = r.object_id";
    $clauses['where'] .= " AND p.post_type IN ('". esc_sql( $post_types ). "') GROUP BY t.term_id";
  }
  return $clauses;
}
add_filter('terms_clauses', 'my_terms_clauses', 99999, 3);

Оскільки в get_terms немає пункту для GROUPY BY, я повинен був додати його до кінця пункту WHERE. Зауважте, що у мене пріоритет фільтра встановлений дуже високо, сподіваючись, він завжди буде останнім.


3

Я не зміг зробити аргументи get_terms для роботи з версією коду Гевіна вище, але нарешті, змінивши це

$terms2 = get_terms( $taxonomy );

до

$terms2 = get_terms( $taxonomy, $args );

як це було в оригінальній функції від Bainternet.


1
Виправлено це в поточній версії
Гевін Хьюїтт

0

@Bainternet: Дякую! Мені довелося трохи змінити функцію, оскільки вона не працювала (деякі помилки). Єдиною проблемою зараз є те, що кількість термінів вимкнено. Підрахунок не враховує тип публікації, тому я не думаю, що ви можете використовувати get_terms () у цьому.

function get_terms_by_post_type($post_type,$taxonomy,$fields='all',$args){
    $q_args = array(
        'post_type' => (array)$post_type,
        'posts_per_page' => -1
    );
    $the_query = new WP_Query( $q_args );

    $terms = array();

    while ($the_query->have_posts()) { $the_query->the_post();

        global $post;

        $current_terms = get_the_terms( $post->ID, $taxonomy);

        foreach ($current_terms as $t){
            //avoid duplicates
            if (!in_array($t,$terms)){
                $t->count = 1;
                $terms[] = $t;
            }else{
                $key = array_search($t, $terms);
                $terms[$key]->count = $terms[$key]->count + 1;
            }
        }
    }
    wp_reset_query();

    //return array of term objects
    if ($fields == "all")
        return $terms;
    //return array of term ID's
    if ($fields == "ID"){
        foreach ($terms as $t){
            $re[] = $t->term_id;
        }
        return $re;
    }
    //return array of term names
    if ($fields == "name"){
        foreach ($terms as $t){
            $re[] = $t->name;
        }
        return $re;
    }
    // get terms with get_terms arguments
    if ($fields == "get_terms"){
        $terms2 = get_terms( $taxonomy, $args );

        foreach ($terms as $t){
            if (in_array($t,$terms2)){
                $re[] = $t;
            }
        }
        return $re;
    }
}

EDIT: Додано виправлення. Але якось це все одно не працює для мене. Підрахунок все ще показує неправильне значення.


Це вже інша історія, але ви можете порахувати, уникаючи дублікатів у циклі while.
Bainternet

Я оновив свою відповідь виправленням кількості термінів.
Bainternet

1
Будь ласка, не додайте подальші дії як відповіді, якщо ви конкретно не відповідаєте на власне запитання , замість цього слід вносити доповнення до оригінального питання.
t31о

1
@ t31os: Ага так, мені було цікаво, як додати доповнення. Не думав редагувати моє запитання. Спасибі!
Гевін Хьюїтт

Як я можу це назвати? print_r(get_terms_by_post_typea(array('event','category','',array()));цей дає Warning: Invalid argument supplied for foreach()для рядкаforeach ($current_terms as $t){
дев

0

Уникайте дублікатів:

//avoid duplicates
    $mivalor=$t->term_id;
    $arr=array_filter($terms, function ($item) use ($mivalor) {return isset($item->term_id) && $item->term_id == $mivalor;});

    if (empty($arr)){
    $t->count=1;
            $terms[] = $t;
        }else{
            $key = array_search($t, $terms);
            $terms[$key]->count = $terms[$key]->count + 1;
        }

1
Чи можете ви пояснити, чому це вирішує проблему? Дивіться, як відповісти .
брасофіло
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.