วิธีการขยาย WP_Query เพื่อรวมตารางที่กำหนดเองในแบบสอบถาม


31

ฉันมีปัญหามาหลายวันแล้ว ตอนแรกมันเป็นวิธีการจัดเก็บข้อมูลผู้ติดตามของผู้ใช้ในฐานข้อมูลซึ่งฉันได้รับคำแนะนำที่ดีที่นี่ที่ WordPress Answers หลังจากทำตามคำแนะนำฉันได้เพิ่มตารางใหม่เช่นนี้:

id  leader_id   follower_id
1   2           4
2   3           10
3   2           10

ในตารางด้านบนแถวแรกมีผู้ใช้ที่มี ID เป็น 2 ซึ่งกำลังตามด้วยผู้ใช้ที่มี ID เป็น 4 ในแถวที่สองผู้ใช้ที่มี ID 3 จะถูกตามด้วยผู้ใช้ที่มี ID เป็น 10 ใช้ตรรกะเดียวกันกับแถวที่สาม

ตอนนี้โดยพื้นฐานแล้วฉันต้องการขยาย WP_Query เพื่อให้ฉันสามารถ จำกัด การโพสต์ที่ดึงข้อมูลได้เฉพาะผู้นำของผู้ใช้เท่านั้น ดังนั้นการพิจารณาตารางข้างต้นหากฉันต้องส่ง ID ผู้ใช้ 10 ถึง WP_Query ผลลัพธ์ควรมีการโพสต์ด้วย ID ผู้ใช้ 2 และ ID ผู้ใช้ 3 เท่านั้น

ฉันค้นหาคำตอบจำนวนมากแล้ว หรือฉันได้เห็นบทช่วยสอนใด ๆ เพื่อช่วยให้ฉันเข้าใจวิธีการขยายคลาส WP_Query ฉันได้เห็นคำตอบของ Mike Schinkel (ขยาย WP_Query) เป็นคำถามที่คล้ายกัน แต่ฉันไม่เข้าใจวิธีการใช้กับความต้องการของฉัน มันคงจะดีถ้ามีคนช่วยฉันด้วย

เชื่อมโยงไปยังคำตอบของไมค์ที่เป็นที่ต้องการ: 1 Link , 2 Link


เพิ่มลิงก์ไปยังคำตอบ Mikes โปรด
ไกเซอร์

1
คุณสามารถยกตัวอย่างสิ่งที่คุณจะสอบถามได้หรือไม่ WP_Queryสำหรับรับโพสต์และฉันไม่เข้าใจว่าสิ่งนี้เชื่อมโยงกับโพสต์อย่างไร
mor7ifer

@kaiser ฉันได้อัปเดตคำถามพร้อมลิงก์ไปยังคำตอบของไมค์
John

@ m0r7if3r »ฉันต้องการขยาย WP_Query เพื่อให้ฉันสามารถ จำกัด การโพสต์ที่ดึงมาได้เฉพาะกับผู้นำของผู้ใช้คนหนึ่ง«คล้ายกับ "รับโพสต์โดยผู้เขียน"
ไกเซอร์

2
@ m0r7if3r โพสต์เป็นสิ่งที่ฉันต้องการค้นหา แต่โพสต์ที่จะดึงข้อมูลควรมาจากผู้ใช้ที่มีรายชื่อเป็นผู้นำของผู้ใช้บางรายในตารางที่กำหนดเอง ดังนั้นในคำอื่น ๆ ที่ฉันต้องการบอก WP_Query ไปเรียกโพสต์ทั้งหมดโดยผู้ใช้ทั้งหมดที่ระบุว่าเป็นผู้นำของผู้ใช้ที่มี ID '10' ในตารางที่กำหนดเอง
จอห์น

คำตอบ:


13

ข้อจำกัดความรับผิดชอบที่สำคัญ: วิธีที่เหมาะสมในการทำเช่นนี้ไม่ใช่เพื่อปรับเปลี่ยนโครงสร้างตารางของคุณ แต่ใช้ wp_usermeta จากนั้นคุณไม่จำเป็นต้องสร้าง SQL แบบกำหนดเองใด ๆ เพื่อค้นหาโพสต์ของคุณ (แม้ว่าคุณจะยังต้องการ SQL แบบกำหนดเองบางรายการเพื่อรับรายการของทุกคนที่รายงานไปยังหัวหน้างานเฉพาะ - ในส่วนผู้ดูแลระบบ) อย่างไรก็ตามเนื่องจาก OP ถามเกี่ยวกับการเขียน SQL แบบกำหนดเองต่อไปนี้เป็นแนวปฏิบัติที่ดีที่สุดในปัจจุบันสำหรับการฉีด SQL แบบกำหนดเองลงในแบบสอบถาม WordPress ที่มีอยู่

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

ทางออกที่ดีที่สุดของคุณคือการใช้ตัวกรอง 'posts_clauses' นี่เป็นตัวกรองที่มีประโยชน์สูง (ที่ไม่ควรใช้ในทางที่ผิด!) ที่อนุญาตให้คุณผนวก / แก้ไขส่วนต่าง ๆ ของ SQL ที่สร้างขึ้นโดยอัตโนมัติโดยโค้ดหลายบรรทัดภายในเวิร์ดเพรสคอร์ ลายเซ็นตัวกรองการเรียกกลับคือ และคาดว่าคุณจะกลับมาfunction posts_clauses_filter_cb( $clauses, $query_object ){ }$clauses

The Clauses

$clausesคืออาร์เรย์ที่มีคีย์ต่อไปนี้ แต่ละคีย์คือสตริง SQL ที่จะใช้โดยตรงในคำสั่ง SQL สุดท้ายที่ส่งไปยังฐานข้อมูล:

  • ที่ไหน
  • GroupBy
  • ร่วม
  • สั่งโดย
  • แตกต่าง
  • สาขา
  • ขีด จำกัด

หากคุณกำลังเพิ่มตารางลงในฐานข้อมูล (ทำได้เฉพาะในกรณีที่คุณไม่สามารถใช้ประโยชน์ post_meta, user_meta หรือ taxonomies ได้อย่างแน่นอน) คุณอาจต้องสัมผัสมากกว่าหนึ่งในข้อเหล่านี้ตัวอย่างเช่นfields("เลือก" ส่วนหนึ่งของคำสั่ง SQL) ที่join(ตารางของคุณทุกอื่น ๆ กว่าหนึ่งในของคุณ "จาก" ข้อ) orderbyและอาจจะเป็น

การปรับเปลี่ยน Clauses

วิธีที่ดีที่สุดในการทำเช่นนี้คือการอ้างอิงคีย์ที่เกี่ยวข้องจาก$clausesอาร์เรย์ที่คุณได้รับจากตัวกรอง:

$join = &$clauses['join'];

ตอนนี้ถ้าคุณแก้ไข$joinคุณจะต้องแก้ไขโดยตรง$clauses['join']ดังนั้นการเปลี่ยนแปลงจะเกิดขึ้น$clausesเมื่อคุณส่งคืน

รักษาข้อต้นฉบับ

โอกาสคือ (ไม่จริงจังฟัง) คุณจะต้องรักษา SQL ที่มีอยู่ซึ่ง WordPress สร้างขึ้นสำหรับคุณ ถ้าไม่คุณควรดูที่posts_requestตัวกรองแทน - นั่นคือแบบสอบถาม mySQL ที่สมบูรณ์ก่อนที่มันจะถูกส่งไปยังฐานข้อมูลเพื่อให้คุณสามารถปิดบังมันด้วยตัวคุณเอง ทำไมคุณต้องการทำเช่นนี้? คุณอาจจะไม่

ดังนั้นเพื่อรักษา SQL ที่มีอยู่ในส่วนคำสั่งอย่าลืมผนวกส่วนคำสั่งไม่ได้กำหนดให้ (เช่น: ใช้$join .= ' {NEW SQL STUFF}';ไม่ได้$join = '{CLOBBER SQL STUFF}';โปรดทราบว่าเนื่องจากแต่ละองค์ประกอบของ$clausesอาร์เรย์เป็นสตริงถ้าคุณต้องการต่อท้าย คุณอาจต้องการแทรกช่องว่างหน้าโทเค็นอักขระอื่น ๆ มิฉะนั้นคุณอาจสร้างข้อผิดพลาดทางไวยากรณ์ของ SQL

คุณสามารถสันนิษฐานได้ว่ามีบางสิ่งในแต่ละข้อและอย่าลืมเริ่มต้นสตริงใหม่ด้วยช่องว่างดังที่: $join .= ' my_tableหรือคุณสามารถเพิ่มบรรทัดเล็ก ๆ ที่เพิ่มช่องว่างได้ถ้าคุณต้องการ:

$join = &$clauses['join'];
if (! empty( $join ) ) $join .= ' ';
$join .= "JOIN my_table... "; // <-- note the space at the end
$join .= "JOIN my_other_table... ";


return $clauses;

นั่นเป็นโวหารมากกว่าสิ่งอื่นใด บิตสำคัญที่ต้องจำคือให้เว้นช่องว่างไว้เสมอก่อนที่สตริงของคุณหากคุณต่อท้ายประโยคที่มี SQL อยู่แล้ว!

วางไว้ด้วยกัน

กฎข้อแรกของการพัฒนา WordPress คือพยายามใช้ฟังก์ชั่นหลักให้มากที่สุดเท่าที่จะทำได้ นี่เป็นวิธีที่ดีที่สุดในการพิสูจน์การทำงานของคุณในอนาคต สมมติว่าทีมหลักตัดสินใจว่า WordPress จะใช้ SQLite หรือ Oracle หรือภาษาฐานข้อมูลอื่น ๆ mySQL ที่เขียนด้วยมือใด ๆ อาจไม่ถูกต้องและทำให้ปลั๊กอินหรือธีมของคุณเสียหาย! ดีกว่าที่จะให้ WP สร้าง SQL ให้มากที่สุดเท่าที่จะทำได้ด้วยตัวเองและเพิ่มบิตที่คุณต้องการ

ลำดับแรกของธุรกิจคือการใช้ประโยชน์จากWP_Queryการสร้างแบบสอบถามฐานของคุณให้มากที่สุด วิธีการที่แน่นอนที่เราใช้ในการทำสิ่งนี้ขึ้นอยู่กับว่ารายการโพสต์นี้ควรปรากฏที่ใด หากเป็นส่วนย่อยของหน้า (ไม่ใช่ข้อความค้นหาหลัก) คุณจะใช้get_posts(); หากเป็นคำถามหลักฉันคิดว่าคุณสามารถใช้query_posts()และทำได้ด้วย แต่วิธีที่เหมาะสมในการทำคือสกัดกั้นข้อความค้นหาหลักก่อนที่จะเข้าถึงฐานข้อมูล (และใช้รอบเซิร์ฟเวอร์) เพื่อใช้requestตัวกรอง

ตกลงดังนั้นคุณได้สร้างแบบสอบถามและ SQL กำลังจะถูกสร้างขึ้น ในความเป็นจริงมันถูกสร้างขึ้นเพียงไม่ส่งไปยังฐานข้อมูล โดยการใช้posts_clausesตัวกรองคุณจะเพิ่มตารางความสัมพันธ์ของพนักงานของคุณลงในการผสม ลองเรียกตารางนี้ {$ wpdb-> คำนำหน้า} 'user_relationship' และเป็นตารางสี่แยก (โดยวิธีการนี้ฉันขอแนะนำให้คุณสร้างโครงสร้างของตารางนี้และแปลงให้เป็นตารางสี่แยกที่เหมาะสมด้วยฟิลด์ต่อไปนี้: 'relationship_id', 'user_id', 'related_user_id', 'relationship_type' นี่คือความยืดหยุ่นและทรงพลัง .. แต่ฉันเชือนแช)

หากฉันเข้าใจว่าคุณต้องการทำอะไรคุณต้องการส่ง ID ของผู้นำแล้วเห็นเฉพาะโพสต์ของผู้ติดตามของผู้นำนั้น ฉันหวังว่าฉันพูดถูก ถ้ามันไม่ถูกต้องคุณจะต้องใช้สิ่งที่ฉันพูดและปรับให้เข้ากับความต้องการของคุณ ฉันจะติดกับโครงสร้างของตารางของคุณ: เรามีและleader_id follower_idดังนั้น JOIN จะ{$wpdb->posts}.post_authorเป็นคีย์ต่างประเทศในตาราง 'follower_id' ในตาราง 'user_relationship' ของคุณ

add_filter( 'posts_clauses', 'filter_by_leader_id', 10, 2 ); // we need the 2 because we want to get all the arguments

function filter_by_leader_id( $clauses, $query_object ){
  // I don't know how you intend to pass the leader_id, so let's just assume it's a global
  global $leader_id;

  // In this example I only want to affect a query on the home page.
  // This is where the $query_object is used, to help us avoid affecting
  // ALL queries (since ALL queries pass through this filter)
  if ( $query_object->is_home() ){
    // Now, let's add your table into the SQL
    $join = &$clauses['join'];
    if (! empty( $join ) ) $join .= ' '; // add a space only if we have to (for bonus marks!)
    $join .= "JOIN {$wpdb->prefix}employee_relationship EMP_R ON EMP_R.follower_id = {$wpdb->posts}.author_id";

    // And make sure we add it to our selection criteria
    $where = &$clauses['where'];
    // Regardless, you always start with AND, because there's always a '1=1' statement as the first statement of the WHERE clause that's added in by WP/
    // Just don't forget the leading space!
    $where .= " AND EMP_R.leader_id={$leader_id}"; // assuming $leader_id is always (int)

    // And I assume you'll want the posts "grouped" by user id, so let's modify the groupby clause
    $groupby = &$clauses['groupby'];
    // We need to prepend, so...
    if (! empty( $groupby ) ) $groupby = ' ' . $groupby; // For the show-offs
    $groupby = "{$wpdb->posts}.post_author" . $groupby;
  }

  // Regardless, we need to return our clauses...
  return $clauses;
}

13

ฉันตอบคำถามนี้ช้ามากและขอโทษด้วย ฉันยุ่งมากกับการส่งงานตามกำหนดเวลา

ขอขอบคุณ @ m0r7if3r และ @kaiser ที่ให้บริการโซลูชั่นพื้นฐานที่ฉันสามารถขยายและนำไปใช้ในแอปพลิเคชันของฉันได้ คำตอบนี้ให้รายละเอียดเกี่ยวกับการปรับแก้ปัญหาของฉันที่นำเสนอโดย @ m0r7if3r และ @kaiser

ก่อนอื่นให้ฉันอธิบายว่าทำไมคำถามนี้ถูกถามตั้งแต่แรก จากคำถามและความคิดเห็นดังกล่าวอาจรวบรวมได้ว่าฉันพยายามทำให้ WP_Query ดึงโพสต์โดยผู้ใช้ทั้งหมด (ผู้นำ) ที่ผู้ใช้ที่กำหนด (ผู้ติดตาม) ติดตาม followความสัมพันธ์ระหว่างลูกศิษย์และเป็นผู้นำจะถูกเก็บไว้ในตารางที่กำหนดเอง ทางออกที่พบบ่อยที่สุดสำหรับปัญหานี้คือการดึง ID ผู้ใช้ของผู้นำทั้งหมดของผู้ติดตามจากตารางติดตามและวางไว้ในอาร์เรย์ ดูด้านล่าง:

global $wpdb;
$results = $wpdb->get_results($wpdb->prepare('SELECT leader_id FROM cs_follow WHERE follower_id = %s', $user_id));

foreach($results as $result)
    $leaders[] = $result->leader_id;

เมื่อคุณมีผู้นำมากมายคุณสามารถส่งผ่านมันเป็นอาร์กิวเมนต์ของ WP_Query ดูด้านล่าง:

if (isset($leaders)) $authors = implode(',', $leaders); // Necessary as authors argument of WP_Query only accepts string containing post author ID's seperated by commas

$args = array(
    'post_type'         => 'post',
    'posts_per_page'    => 10,
    'author'            => $authors
);

$wp_query = new WP_Query( $args );

// Normal WordPress loop continues

การแก้ปัญหาข้างต้นเป็นวิธีที่ง่ายที่สุดในการบรรลุผลลัพธ์ที่ต้องการ อย่างไรก็ตามมันไม่สามารถปรับขนาดได้ ทันทีที่คุณมีผู้ติดตามตามผู้นำนับหมื่นคนแถวลำดับผลลัพธ์ของรหัสผู้นำจะมีขนาดใหญ่มากและบังคับให้ไซต์ WordPress ของคุณใช้หน่วยความจำ 100MB - 250MB ในการโหลดหน้าเว็บแต่ละหน้า วิธีแก้ไขปัญหาคือเรียกใช้แบบสอบถาม SQL โดยตรงในฐานข้อมูลและดึงข้อมูลการโพสต์ที่เกี่ยวข้อง นั่นคือเมื่อโซลูชันของ @ m0r7if3r มาช่วยเหลือ การทำตามคำแนะนำของ @ kaiser ฉันได้เริ่มทดสอบการใช้งานทั้งสองอย่าง ฉันนำเข้าผู้ใช้ประมาณ 47K จากไฟล์ CSV เพื่อลงทะเบียนพวกเขาในการทดสอบการติดตั้งใหม่ของ WordPress การติดตั้งใช้งานชุดรูปแบบ Twenty Eleven หลังจากนี้ฉันก็วิ่งวนรอบเพื่อให้ผู้ใช้ประมาณ 50 คนติดตามผู้ใช้ทุกคน ความแตกต่างของเวลาสอบถามสำหรับทั้งโซลูชันของ @kaiser และ @ m0r7if3r นั้นทำให้เกิดส่าย โดยปกติแล้วโซลูชันของ kaiser ใช้เวลาประมาณ 2 ถึง 5 วินาทีในการสืบค้นแต่ละครั้ง รูปแบบที่ฉันเข้าใจเกิดขึ้นเมื่อ WordPress แคชแบบสอบถามเพื่อใช้ในภายหลัง ในทางกลับกันโซลูชันของ @ m0r7if3r แสดงเวลาการสืบค้นเฉลี่ย 0.02 มิลลิวินาที สำหรับการทดสอบทั้งสองวิธีฉันมีการทำดัชนี ON สำหรับคอลัมน์ leader_id หากไม่มีการจัดทำดัชนีจะมีเวลาเพิ่มขึ้นอย่างมากในแบบสอบถาม

การใช้หน่วยความจำเมื่อใช้โซลูชันที่ใช้อาเรย์นั้นอยู่ที่ประมาณ 100-150 MB และลดลงเหลือ 20 MB เมื่อเรียกใช้ SQL โดยตรง

ฉันพบปัญหาด้วย @m0r7if3r เมื่อฉันต้องการส่งรหัสผู้ติดตามไปยังฟังก์ชันตัวกรอง posts_where อย่างน้อยตามความรู้ของฉัน WordPress ไม่อนุญาตให้ส่งผ่านตัวแปรไปยังฟังก์ชันตัวกรอง คุณสามารถใช้ตัวแปรทั่วโลกได้ แต่ฉันต้องการหลีกเลี่ยงการกลม ฉันสิ้นสุดการขยาย WP_Query เพื่อแก้ไขปัญหาในที่สุด ดังนั้นนี่คือทางออกสุดท้ายที่ฉันนำมาใช้ (ขึ้นอยู่กับโซลูชันของ @ m0r7if3r)

class WP_Query_Posts_by_Leader extends WP_Query {
    var $follower_id;

    function __construct($args=array()) {
        if(!empty($args['follower_id'])) {
            $this->follower_id = $args['follower_id'];
            add_filter('posts_where', array($this, 'posts_where'));
        }

        parent::query($args);
    }

    function posts_where($where) {
        global $wpdb;
        $table_name = $wpdb->prefix . 'follow';
        $where .= $wpdb->prepare(" AND post_author IN (SELECT leader_id FROM " . $table_name . " WHERE follower_id = %d )", $this->follower_id);
        return $where;
    }
}


$args = array(
    'post_type'         => 'post',
    'posts_per_page'    => 10,
    'follower_id'       => $follower_id
);

$wp_query = new WP_Query_Posts_by_Leader( $args );

หมายเหตุ: ในที่สุดฉันก็ลองใช้วิธีแก้ปัญหาข้างต้นโดยมี 1.2 ล้านรายการในตารางต่อไปนี้ เวลาสอบถามเฉลี่ยอยู่ที่ประมาณ 0.060 ms


3
ฉันไม่เคยบอกคุณว่าฉันชื่นชมการอภิปรายในคำถามนี้มากแค่ไหน ตอนนี้ฉันพบว่าฉันพลาดไปแล้วฉันได้เพิ่มอัพote :)
kaiser

8

คุณสามารถทำได้ด้วยโซลูชัน SQL ทั้งหมดโดยใช้posts_whereตัวกรอง นี่คือตัวอย่างของที่:

if( some condition ) 
    add_filter( 'posts_where', 'wpse50305_leader_where' );
    // lol, question id is the same forward and backward

function wpse50305_leader_where( $where ) {
    $where .= $GLOBALS['wpdb']->prepare( ' AND post_author '.
        'IN ( '.
            'SELECT leader_id '.
            'FROM custom_table_name '.
            'WHERE follower_id = %s'.
        ' ) ', $follower_id );
    return $where;
}

ฉันคิดว่าอาจมีวิธีที่จะทำเช่นนี้ด้วยJOINแต่ฉันไม่สามารถเกิดขึ้นได้ ฉันจะเล่นต่อไปและอัปเดตคำตอบถ้าฉันได้รับ

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

จากความคิดเห็น:

คุณควรใส่ฟังก์ชั่นของคุณfunctions.phpและทำสิ่งที่add_filter()ถูกต้องก่อนquery()วิธีการที่WP_Queryเรียกว่า ทันทีหลังจากนั้นคุณควรremove_filter()จะไม่ส่งผลต่อข้อความค้นหาอื่น ๆ


1
prepare()แก้ไขและเพิ่ม หวังว่าคุณจะไม่รังเกียจการแก้ไข และใช่: ผลการดำเนินงานมีการวัดได้โดย OP อย่างไรก็ตาม: ฉันยังคิดว่านี่น่าจะเป็นแค่ useta และไม่มีอะไรอื่น
ไกเซอร์

@ m0r7if3r ขอบคุณสำหรับการลองวิธีแก้ปัญหา ฉันเพิ่งโพสต์ความคิดเห็นเพื่อตอบคำตอบของ Kaiser พร้อมกับความกังวลเกี่ยวกับปัญหาการขยายที่เป็นไปได้ โปรดพิจารณาด้วย
จอห์น

1
@kaiser ไม่คิดในอย่างน้อยในความเป็นจริงผมค่อนข้างขอบคุณมัน :)
mor7ifer

@ m0r7if3r ขอบคุณ มีผู้ชายอย่างคุณในแวดวงชุมชน :)
ไกเซอร์

1
คุณควรใส่ฟังก์ชั่นของคุณfunctions.phpและทำสิ่งที่add_filter()ถูกต้องก่อนquery()วิธีการที่WP_Queryเรียกว่า ทันทีหลังจากนั้นคุณควรremove_filter()จะไม่ส่งผลต่อข้อความค้นหาอื่น ๆ ผมไม่แน่ใจว่าสิ่งที่เป็นปัญหาที่มี URL ที่เขียนใหม่จะเป็นผมเคยใช้posts_whereหลายครั้งและไม่เคยเห็นได้ว่า ...
mor7ifer

6

เทมเพลตแท็ก

เพียงวางฟังก์ชั่นทั้งสองไว้ในfunctions.phpไฟล์ของคุณ จากนั้นปรับฟังก์ชั่นที่ 1 และเพิ่มชื่อตารางที่กำหนดเองของคุณ จากนั้นคุณต้องลอง / ข้อผิดพลาดเพื่อกำจัด ID ผู้ใช้ปัจจุบันภายในอาร์เรย์ผลลัพธ์ (ดูความคิดเห็น)

/**
 * Get "Leaders" of the current user
 * @param int $user_id The current users ID
 * @return array $query The leaders
 */
function wpse50305_get_leaders( $user_id )
{
    global $wpdb;

    return $wpdb->query( $wpdb->prepare(
        "
            SELECT `leader_id`, `follower_id`
            FROM %s
                WHERE `follower_id` = %s
            ORDERBY `leader_id` ASC
        ",
        // Edit the table name
        "{$wpdb->prefix}custom_table_name"
        $user_id
    ) );
}

/**
 * Get posts array that contain posts by 
 * "Leaders" the current user is following
 * @return array $posts Posts that are by the current "Leader
 */
function wpse50305_list_posts_by_leader()
{
    get_currentuserinfo();
    global $current_user;

    $user_id = $current_user->ID;

    $leaders = wpse5035_get_leaders( $user_id );
    // could be that you need to loop over the $leaders
    // and get rid of the follower ids

    return get_posts( array(
        'author' => implode( ",", $leaders )
    ) );
}

ภายในเทมเพลต

ที่นี่คุณสามารถทำสิ่งที่คุณต้องการด้วยผลลัพธ์ของคุณ

foreach ( wpse50305_list_posts_by_leader() as $post )
{
    // do something with $post
}

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


2
JOINเป็นมากขึ้นมีราคาแพง บวก:ที่ฉันกล่าวถึงเราไม่มีข้อมูลการทดสอบดังนั้นโปรดทดสอบทั้งคำตอบและสอนเราด้วยผลลัพธ์ของคุณ
ไกเซอร์

1
WP_Query ทำงานร่วมกับ JOIN ระหว่างตารางโพสต์และ postmeta เมื่อทำการสอบถาม ฉันเคยเห็นการใช้งานหน่วยความจำ PHP ถึง 70MB - 200MB ต่อการโหลดหน้าเว็บ การดำเนินการบางอย่างเช่นนั้นกับผู้ใช้หลายคนพร้อมกันจะต้องมีโครงสร้างพื้นฐานที่รุนแรง ฉันเดาว่าตั้งแต่นั้นมา WordPress ได้ใช้เทคนิคที่คล้ายกันอยู่แล้ว JOIN ควรมีการเก็บภาษีน้อยลงเมื่อเทียบกับการทำงานกับอาร์เรย์ของ ID
จอห์น

1
@ John ที่ดีที่จะได้ยิน อยากรู้ว่าสิ่งที่กำลังจะมาถึงจริงๆ
ไกเซอร์

4
ตกลงนี่คือผลการทดสอบ สำหรับสิ่งนี้ฉันได้เพิ่มผู้ใช้ประมาณ 47K จากไฟล์ csv หลังจากนั้นให้วิ่งวนรอบเพื่อให้ผู้ใช้ 45 คนแรกติดตามผู้ใช้ทุกคน ทำให้บันทึก 3,704,951 รายการในตารางที่กำหนดเองของฉัน เริ่มแรกโซลูชันของ @ m0r7if3r ทำให้ฉันมีเวลาสอบถาม 95 วินาทีซึ่งลดลงเหลือ 0.020 ms หลังจากเปิดการจัดทำดัชนีในคอลัมน์ leader_id หน่วยความจำ PHP ทั้งหมดที่ใช้มีขนาดประมาณ 20MB ในทางกลับกันโซลูชันของคุณใช้เวลาประมาณ 2 ถึง 5 วินาทีในการค้นหาด้วยการเปิดดัชนี หน่วยความจำ PHP ทั้งหมดที่ใช้อยู่ประมาณ 117MB
จอห์น

1
ฉันเพิ่มคำตอบอื่น (เราสามารถประมวลผลและแก้ไข / แก้ไขในเรื่องนั้น) ในขณะที่การจัดรูปแบบรหัสในความคิดเห็นเพียง sucks: P
kaiser

3

หมายเหตุ: คำตอบนี้ที่นี่คือการหลีกเลี่ยงการอภิปรายเพิ่มเติมในความคิดเห็น

  1. นี่คือรหัส OPs จากความคิดเห็นเพื่อเพิ่มผู้ใช้ชุดทดสอบครั้งแรก ฉันต้องได้รับการดัดแปลงให้เป็นตัวอย่างในโลกแห่งความเป็นจริง

    for ( $j = 2; $j <= 52; $j++ ) 
    {
        for ( $i = ($j + 1); $i <= 47000; $i++ )
        {
            $rows_affected = $wpdb->insert( $table_name, array( 'leader_id' => $i, 'follower_id' => $j ) );
        }
    }

    OP เกี่ยวกับการทดสอบฉันเพิ่มผู้ใช้ประมาณ 47K จากไฟล์ csv หลังจากนั้นให้วิ่งวนรอบเพื่อให้ผู้ใช้ 45 คนแรกติดตามผู้ใช้ทุกคน

    • ทำให้บันทึก 3,704,951 รายการในตารางที่กำหนดเองของฉัน
    • ในขั้นต้นโซลูชันของ @ m0r7if3r ทำให้ฉันมีเวลาสอบถาม 95 วินาทีซึ่งลดลงเหลือ 0.020 ms หลังจากเปิดการจัดทำดัชนีในคอลัมน์ leader_id หน่วยความจำ PHP ทั้งหมดที่ใช้มีขนาดประมาณ 20MB
    • ในทางกลับกันโซลูชันของคุณใช้เวลาประมาณ 2 ถึง 5 วินาทีในการค้นหาด้วยการเปิดดัชนี หน่วยความจำ PHP ทั้งหมดที่ใช้อยู่ประมาณ 117MB
  2. คำตอบของฉันสำหรับการทดสอบ↑นี้:

    การทดสอบ "ชีวิตจริง" เพิ่มเติม: ให้ผู้ใช้ทุกคนติดตาม$leader_amount = rand( 0, 5 );และเพิ่มจำนวน$leader_amount x $random_ids = rand( 0, 47000 );ผู้ใช้แต่ละคน จนถึงตอนนี้สิ่งที่เรารู้คือ: โซลูชันของฉันจะแย่มากถ้าผู้ใช้ติดตามผู้ใช้รายอื่น เพิ่มเติม: คุณจะได้แสดงให้เห็นว่าคุณทำการทดสอบอย่างไรและที่ที่คุณเพิ่มตัวจับเวลา

    ฉันต้องระบุด้วยว่าการติดตามเวลาข้างต้นไม่สามารถวัดได้จริงๆเพราะต้องใช้เวลาในการคำนวณลูปด้วยกัน ดีกว่าคือการวนซ้ำชุด ID ที่ได้ในลูปที่สอง

กระบวนการเพิ่มเติมที่นี่


2
หมายเหตุสำหรับผู้ที่ติดตามคำถามนี้: ฉันอยู่ระหว่างการวัดประสิทธิภาพภายใต้เงื่อนไขต่าง ๆ และจะโพสต์ผลลัพธ์ในหนึ่งวันหรือ 3 ซึ่งเป็นงานที่ใช้เวลานานมากเนื่องจากขนาดของข้อมูลทดสอบที่ต้องใช้ สร้าง
จอห์น
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.