รับข้อกำหนดตาม taxonomy และ post_type


17

ฉันมี 'บุ๊กมาร์ก' และ 'ตัวอย่าง' ประเภทโพสต์ที่กำหนดเองและแท็ก taxonomy ที่ใช้ร่วมกัน ฉันสามารถสร้างรายการคำศัพท์ทั้งหมดในอนุกรมวิธานด้วย 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;

}

ใช่ นี่เป็นสิ่งที่ฉันต้องการ
Gavin Hewitt

print_r(get_terms_by_post_type(array('category') , array('event') ));รายการWarning: Missing argument 2 for wpdb::prepare()
devo

ฉันผิด แต่ด้านบนของหัวฉันไม่คิดว่าคำสั่ง 'เข้าร่วม' จะทำงานได้ - กล่าวคือพวกเขาจะทำงานได้ก็ต่อเมื่อผ่านอาร์เรย์แบบค่าเดียว นี่เป็นเพราะฟังก์ชั่นการเตรียมการจะหลีกเลี่ยงการอ้างคำพูดเดียวที่สร้างขึ้นทั้งหมดและพิจารณา 'เข้าร่วม' หนึ่งสตริงทั้งหมด
Codesmith

14

ดังนั้นมันก็เกิดขึ้นที่ฉันต้องการอะไรแบบนั้นสำหรับโครงการที่ฉันกำลังทำอยู่ ฉันเพียงแค่เขียนแบบสอบถามเพื่อเลือกโพสต์ทั้งหมดของประเภทที่กำหนดเองแล้วฉันจะตรวจสอบสิ่งที่เป็นเงื่อนไขที่แท้จริงของอนุกรมวิธานของพวกเขากำลังใช้

จากนั้นฉันได้รับเงื่อนไขทั้งหมดของการใช้อนุกรมวิธานget_terms()นั้นและจากนั้นฉันใช้เฉพาะสิ่งที่อยู่ในรายการทั้งสองห่อไว้ในฟังก์ชั่นและฉันก็ทำเสร็จแล้ว

แต่แล้วฉันก็ต้องการมากกว่านั้นเพียงแค่ ID ของ: ฉันต้องการชื่อดังนั้นฉันจึงเพิ่มอาร์กิวเมนต์ใหม่ที่ชื่อว่า$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;
    }
}

การใช้งาน:

หากคุณต้องการรายการของ id คำนั้น:

$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 typos: $ taxonomies ใช้ในฟังก์ชัน $ taxonomy และ $ terms [] = $ c; จะต้องเป็น $ terms [] = $ t;
Rob Vermeer

8

ผมเขียนฟังก์ชั่นที่ช่วยให้คุณผ่านpost_typeใน$argsอาร์เรย์กับget_terms()ฟังก์ชั่น:

HT to @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 ไม่มี clause สำหรับ GROUPY BY ฉันจึงต้องเพิ่มไปที่ท้าย WHERE clause โปรดสังเกตว่าฉันมีชุดตัวกรองลำดับความสำคัญสูงมากหวังว่ามันจะคงอยู่ตลอดไป


3

ฉันไม่สามารถทำให้อาร์กิวเมนต์ get_terms ทำงานร่วมกับโค้ดในเวอร์ชันของ Gavin ได้ แต่ท้ายที่สุดก็เกิดจากการเปลี่ยนแปลง

$terms2 = get_terms( $taxonomy );

ถึง

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

เหมือนเดิมในฟังก์ชั่นดั้งเดิมจาก Bainternet


1
แก้ไขในเวอร์ชันปัจจุบัน
Gavin Hewitt

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

แก้ไข: เพิ่มการแก้ไข (es) แต่อย่างใดมันก็ยังไม่ทำงานสำหรับฉัน การนับยังคงแสดงค่าที่ไม่ถูกต้อง


นั่นเป็นเรื่องราวที่แตกต่างกัน แต่คุณสามารถนับได้เมื่อหลีกเลี่ยงการซ้ำซ้อนในขณะที่วนซ้ำ
Bainternet

ฉันอัปเดตคำตอบของฉันด้วยการแก้ไขการนับคำ
Bainternet

1
โปรดอย่าเพิ่มการติดตามเป็นคำตอบยกเว้นว่าคุณกำลังตอบคำถามของคุณโดยเฉพาะการเพิ่มเติมควรทำกับคำถามเดิม
t31os

1
@ t31os: อ่าใช่ฉันสงสัยว่าจะเพิ่มยังไง ไม่คิดว่าจะแก้ไขคำถามของฉัน ขอบคุณ!
Gavin Hewitt

ฉันจะเรียกสิ่งนี้ได้อย่างไร print_r(get_terms_by_post_typea(array('event','category','',array()));อันนี้ให้Warning: Invalid argument supplied for foreach()สายforeach ($current_terms as $t){
devo

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
คุณช่วยอธิบายได้ไหมว่าเพราะเหตุใดจึงแก้ปัญหาได้ ดูวิธีการตอบ
brasofilo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.