ข้อจำกัดความรับผิดชอบที่สำคัญ: วิธีที่เหมาะสมในการทำเช่นนี้ไม่ใช่เพื่อปรับเปลี่ยนโครงสร้างตารางของคุณ แต่ใช้ 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;
}