Nhận các điều khoản bằng cách phân loại VÀ post_type


17

Tôi có 2 loại bài đăng tùy chỉnh 'dấu trang' và 'đoạn trích' và một thẻ phân loại 'thẻ'. Tôi có thể tạo danh sách tất cả các thuật ngữ trong phân loại bằng get_terms (), nhưng tôi không thể tìm ra cách giới hạn danh sách ở loại bài đăng. Những gì tôi về cơ bản đang tìm kiếm là một cái gì đó như thế này:

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

Có cách nào để đạt được điều này? Ý tưởng được đánh giá rất cao !!

Ồ, tôi đang dùng WP 3.1.1

Câu trả lời:


11

Đây là một cách khác để làm điều gì đó tương tự, với một truy vấn 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;

}

Đúng! Điều này làm chính xác những gì tôi muốn.
Gavin Hewitt

print_r(get_terms_by_post_type(array('category') , array('event') ));chương trìnhWarning: Missing argument 2 for wpdb::prepare()
devo

Tôi có thể sai, nhưng ngoài đỉnh đầu, tôi không nghĩ những tuyên bố 'tham gia' đó sẽ hoạt động - tức là chúng chỉ hoạt động nếu vượt qua các mảng giá trị đơn. Điều này là do hàm chuẩn bị sẽ thoát khỏi tất cả các dấu ngoặc đơn được tạo và xem xét từng chuỗi 'nối' toàn bộ.
Codmith

14

Vì vậy, nó xảy ra rằng tôi cần một cái gì đó như thế cho một dự án tôi đang làm. Tôi chỉ đơn giản là viết một truy vấn để chọn tất cả các bài đăng thuộc loại tùy chỉnh, sau đó tôi kiểm tra các điều khoản thực tế trong phân loại của chúng mà chúng đang sử dụng là gì.

Sau đó, tôi đã sử dụng tất cả các điều khoản của phân loại đó bằng cách sử dụng get_terms()và sau đó tôi chỉ sử dụng những điều khoản trong cả hai danh sách, gói nó trong một chức năng và tôi đã hoàn thành.

Nhưng sau đó tôi cần nhiều hơn chỉ là ID: Tôi cần tên nên tôi đã thêm một đối số mới có tên $fieldsđể tôi có thể nói cho hàm biết phải trả về cái gì. Sau đó, tôi hình dung rằng get_termschấp nhận nhiều đối số và chức năng của tôi bị giới hạn ở các thuật ngữ đơn giản đang được sử dụng bởi một loại bài đăng nên tôi đã thêm một iftuyên bố nữa và bạn sẽ đi:

Chức năng:

/* 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;
    }
}

Sử dụng:

Nếu bạn chỉ cần một danh sách các id hạn thì:

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

Nếu bạn chỉ cần một danh sách các tên hạn thì:

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

Nếu bạn chỉ cần một danh sách các đối tượng hạn thì:

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

Và nếu bạn cần sử dụng các đối số bổ sung của get_terms như: orderby, order, phân cấp ...

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

Thưởng thức!

Cập nhật:

Để sửa lỗi thuật ngữ để thay đổi loại bài cụ thể:

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

đến:

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;
    }
}

Sẽ tốt hơn nếu bạn sử dụng (array) $argsthay vì danh sách 4 $ vars? Điều này sẽ cho phép bạn không quan tâm đến thứ tự bạn đưa ra trong các đối số, vì vậy một cái gì đó giống như get_terms_by_post_type( $args = array( 'taxonomies', 'args', 'post_type', 'fields' => 'all') )và sau đó gọi chúng bên trong hàm với $args['taxonomies']. Điều này sẽ giúp bạn tránh xa việc thêm các giá trị trống và phải nhớ thứ tự các đối số của bạn. Tôi cũng đề nghị sử dụng dấu ngoặc đơn thay vì gấp đôi. Tôi thấy chúng ong nhanh hơn đến năm lần.
kaiser

1
@kaiser - Các chuỗi trích dẫn kép phải được phân tích cú pháp, trong đó các giá trị được trích dẫn duy nhất luôn được coi là bằng chữ. Khi bạn đang sử dụng các biến trong một chuỗi, sẽ rất hợp lý khi sử dụng dấu ngoặc kép, nhưng đối với các giá trị chuỗi không biến thì dấu ngoặc đơn là lý tưởng hơn (vì chúng sẽ không cần phải phân tích cú pháp) và nhanh hơn một chút (chúng tôi ' đang nói về mili giây trong hầu hết các trường hợp).
t31os

@ t31os - Hoàn toàn chính xác. Tôi vẫn thích 'this is my mood: '.$valuehơn "this is my mood: $value", vì dễ đọc. Khi nói đến tốc độ: Nó không phải là một chút - tôi đã bị nhiễm bệnh tới năm lần. Và khi bạn sử dụng dấu ngoặc kép trong toàn bộ chủ đề của mình ở mọi nơi, chúng sẽ nhanh chóng tổng hợp khi bạn nhận được rất nhiều yêu cầu. Dù sao tốt bạn đã làm cho rõ ràng.
kaiser

@ t31os Trong một cuộc thảo luận tôi đã kiểm tra lại tốc độ "so với 'và tôi đã sai. Sự khác biệt là xa bên ngoài bất cứ điều gì bất cứ ai sẽ nhận thấy.
kaiser

1
+1 chức năng tốt đẹp! 2 lỗi chính tả: $ taxonomies được sử dụng trong hàm $ taxonomy và $ terms [] = $ c; phải là $ terms [] = $ t;
Rob Vermeer

8

Tôi đã viết một hàm cho phép bạn chuyển post_typetrong $argsmảng tới get_terms()hàm:

HT đến @braydon để viết 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

Câu hỏi tuyệt vời và câu trả lời vững chắc.

Tôi thực sự thích cách tiếp cận của @jessica bằng bộ lọc terms_clauses, bởi vì nó mở rộng hàm get_terms một cách rất hợp lý.

Mã của tôi là sự tiếp nối ý tưởng của cô ấy, với một số sql từ @braydon để giảm trùng lặp. Nó cũng cho phép một loạt các 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);

Vì get_terms không có mệnh đề cho GROUPY BY, nên tôi đã phải thêm nó vào cuối mệnh đề WHERE. Lưu ý rằng tôi có mức ưu tiên bộ lọc rất cao, với hy vọng nó sẽ luôn đi sau cùng.


3

Tôi không thể làm cho các đối số get_terms hoạt động với phiên bản mã của Gavin ở trên, nhưng cuối cùng đã làm bằng cách thay đổi

$terms2 = get_terms( $taxonomy );

đến

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

như trong chức năng ban đầu từ BaiNET.


1
Đã sửa lỗi trong phiên bản hiện tại
Gavin Hewitt

0

@Bai Internet: Cảm ơn! Tôi đã phải thay đổi chức năng một chút vì nó không hoạt động (một số lỗi chính tả). Vấn đề duy nhất bây giờ là số lượng hạn đã tắt. Số lượng không xem xét loại bài đăng vì vậy tôi không nghĩ bạn có thể sử dụng get_terms () trong việc này.

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: Đã thêm (các) sửa chữa. Nhưng bằng cách nào đó nó vẫn không làm việc cho tôi. Số lượng vẫn hiển thị giá trị không chính xác.


Đó là một câu chuyện khác nhau, nhưng bạn có thể tính khi tránh trùng lặp trong vòng lặp while.
BaiNET

Tôi cập nhật câu trả lời của tôi với một sửa chữa hạn hạn.
BaiNET

1
Vui lòng không thêm các câu hỏi tiếp theo dưới dạng câu trả lời, trừ khi bạn đang trả lời cụ thể câu hỏi của riêng mình , thay vào đó nên bổ sung vào câu hỏi ban đầu.
t31os

1
@ t31os: À đúng rồi, tôi đã tự hỏi làm thế nào để thêm một bổ sung. Không nghĩ đến việc chỉnh sửa câu hỏi của tôi. Cảm ơn!
Gavin Hewitt

Làm thế nào tôi có thể gọi đây? print_r(get_terms_by_post_typea(array('event','category','',array()));cái này mang lại Warning: Invalid argument supplied for foreach()cho dòngforeach ($current_terms as $t){
devo

0

Tránh trùng lặp:

//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
Bạn có thể giải thích tại sao điều này giải quyết vấn đề? Xem cách trả lời .
brasofilo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.