get_terms за спеціальним типом публікації


19

У мене є два користувальницькі типи "країна" та "місто" та спільний таксономічний "прапор".

Якщо я використовую:

<?php $flags = get_terms('flag', 'orderby=name&hide_empty=0');

Я отримую список усіх термінів в систематиці, але хочу обмежити цей список на посаді "країна".

Як я можу це зробити?


Використання нового рішення

<?php 
$flags = wpse57444_get_terms('flags',array('parent' => 0,'hide_empty' => 1,'post_types' =>array('country')));
foreach ($flags as $flag) {
    $childTerms = wpse57444_get_terms('flags',array('parent' => $flag->term_id,'hide_empty' => 1,'post_types' =>array('country')));
    foreach ($childTerms as $childTerm) {
        echo $childTerm->name.'<br />';
    }
}
?>

Я не можу повторити ім'я $ childTerm->. Чому?


Не могли б ви бути трохи зрозумілішими?
TheDeadMedic

Відповіді:


16

Я боюся, що це неможливо спочатку (ще?). Дивіться цей текст: http://core.trac.wordpress.org/ticket/18106

Аналогічно, на сторінці адміністратора систематики кількість повідомлень відображає всі типи публікацій. ( Я майже впевнений, що для цього теж є квиток на Trac ) http://core.trac.wordpress.org/ticket/14084

Дивіться також цей пов’язаний пост .


Нове рішення

Написавши цей нижче, я випустив набагато кращий спосіб (але в іншому сенсі ви можете зробити більше) - використовувати фільтри, надані у get_terms()виклику. Ви можете створити функцію обгортки, яка використовує get_termsта (умовно) додає фільтр для маніпулювання запитом SQL (для обмеження за типом публікації).

Функція бере ті ж аргументи, що і get_terms($taxonomies, $args).$argsприймає додатковий аргумент, post_typesякий займає масив | рядок типів публікацій.

Але я не можу гарантувати, що все працює "так, як очікувалося" (я думаю про те, щоб залишити рахунок). Схоже, це працює лише за замовчуванням $argsдля get_terms.

function wpse57444_get_terms( $taxonomies, $args=array() ){
    //Parse $args in case its a query string.
    $args = wp_parse_args($args);

    if( !empty($args['post_types']) ){
        $args['post_types'] = (array) $args['post_types'];
        add_filter( 'terms_clauses','wpse_filter_terms_by_cpt',10,3);

        function wpse_filter_terms_by_cpt( $pieces, $tax, $args){
            global $wpdb;

            // Don't use db count
            $pieces['fields'] .=", COUNT(*) " ;

            //Join extra tables to restrict by post type.
            $pieces['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 ";

            // Restrict by post type and Group by term_id for COUNTing.
            $post_types_str = implode(',',$args['post_types']);
            $pieces['where'].= $wpdb->prepare(" AND p.post_type IN(%s) GROUP BY t.term_id", $post_types_str);

            remove_filter( current_filter(), __FUNCTION__ );
            return $pieces;
        }
    } // endif post_types set

    return get_terms($taxonomies, $args);           
}

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

$args =array(
    'hide_empty' => 0,
    'post_types' =>array('country','city'),
);

$terms = wpse57444_get_terms('flag',$args);

Оригінальна обробка

Натхненний вищезгаданим квитком на Trac, (перевірено, і він працює для мене)

function wpse57444_filter_terms_by_cpt($taxonomy, $post_types=array() ){
    global $wpdb;

    $post_types=(array) $post_types;
    $key = 'wpse_terms'.md5($taxonomy.serialize($post_types));
    $results = wp_cache_get($key);

    if ( false === $results ) {
       $where =" WHERE 1=1";
       if( !empty($post_types) ){
            $post_types_str = implode(',',$post_types);
            $where.= $wpdb->prepare(" AND p.post_type IN(%s)", $post_types_str);
       }

       $where .= $wpdb->prepare(" AND tt.taxonomy = %s",$taxonomy);

       $query = "
          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
          GROUP BY t.term_id";

       $results = $wpdb->get_results( $query );
       wp_cache_set( $key, $results );
    }        

    return $results;
}

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

 $terms = wpse57444_filter_terms_by_cpt('flag',array('country','city'));

або

 $terms = wpse57444_filter_terms_by_cpt('flag','country');

Це працює, але що я можу зробити зі своїми $ аргументами? Я маю на увазі ... parent = 0 & orderby = name & hid_empty = 0
user1443216

немає - це має бути масивом: $args = array('parent'=>0,'orderby'=>'name','hide_empty'=>0);. Я відредагую це, щоб дозволити рядки запитів ...
Стівен Гарріс

Де я можу розмістити $ args у цьому прикладі $terms = wpse57444_filter_terms_by_cpt('flag',array('country','city'));:?
користувач1443216

Ви не можете в цьому, тільки в новому рішенні:wpse57444_get_terms()
Стівен Харріс

@ user1443216 $args- другий аргумент. Там ви просто помістилиwpse57444_get_terms( 'flag', array( 'country', 'city' ) );
кайзер

2

@ відповідь Стівена-Гарріса вище для мене працювала лише частково. Якщо я спробував використати його двічі на сторінці, це не вийшло. Також мене хвилює ідея поховати такі запити mysql - я думаю, що її краща практика використовувати основні методи для досягнення рішення, щоб уникнути конфліктів з майбутніми оновленнями WP. Ось моє рішення, засноване на коментарі №7 до квитка на Trac, на який він посилається

function get_terms_by_custom_post_type( $post_type, $taxonomy ){
  $args = array( 'post_type' => $post_type);
  $loop = new WP_Query( $args );
  $postids = array();
  // build an array of post IDs
  while ( $loop->have_posts() ) : $loop->the_post();
    array_push($postids, get_the_ID());
  endwhile;
  // get taxonomy values based on array of IDs
  $regions = wp_get_object_terms( $postids,  $taxonomy );
  return $regions;
}

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

$terms = get_terms_by_custom_post_type('country','flag');

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

У цій нитці Trac було сказано, що це може бути недостатньо масштабним, але я працюю в досить малому масштабі і не мав проблем зі швидкістю.


це рішення виглядає для мене більш "рідним" - у будь-якому випадку -> вам слід зателефонувати "wp_reset_postdata ()" відразу після "кінцевого" циклу: wordpress.stackexchange.com/questions/144343/…
Томас Феллінгер

2

Два спеціальні типи постів "країна" та "місто" та спільний таксономічний "прапор". Ви хочете обмежити список типом публікації "країна".

Ось більш просте рішення:

$posts_in_post_type = get_posts( array(
    'fields' => 'ids',
    'post_type' => 'country',
    'posts_per_page' => -1,
) );
$terms = wp_get_object_terms( $posts_in_post_type, 'flag', array( 'ids' ) ); ?>

1

[редагувати] Це коментар до чудової відповіді Стівена Харріса.

Він не повертає жодних термінів, якщо використовується з кількома типами таких публікацій $flags = wpse57444_get_terms('flags', array('post_types' => array('country','city')));. Це пов’язано з тим, що $ wpdb-> pripraє санітує рядок $ post_types_str до того часу, p.post_type IN('country,city')як це має бути p.post_type IN('country','city'). Дивіться цей квиток: 11102 . Використовуйте рішення з цієї теми, щоб обійти це: /programming//a/10634225


1

Я також спробував використати відповідь @Stephen Harris, але мені потрібний запит було досить важко написати як один запит та за допомогою фільтр-фрагментів.

Крім того, мені також потрібно було використовувати цю функцію кілька разів на одній сторінці, і я вирішив проблему, оголосивши wpse_filter_terms_by_cptфункцію поза функцією обгортки.

У будь-якому випадку відповідь @Mark Pruce, на мій погляд, підходить краще, з тих же причин, що він сказав, навіть якщо вам потрібно зробити ще один запит (і пов'язаний цикл), щоб підготувати аргументи для wp_get_object_termsфункції.

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