คู่มือขั้นสูงเพื่อเพิ่มประสิทธิภาพการทำงานของ WordPress
เผยแพร่แล้ว: 2022-03-11วันนี้ WordPress มีอำนาจมากกว่า 30% ของอินเทอร์เน็ต ใช้งานง่าย เป็นที่นิยมอย่างเหลือเชื่อ และจะไม่ไปทุกที่ในเร็วๆ นี้
แต่ WordPress อาจทำงานช้า แล้วคุณจะเพิ่มประสิทธิภาพได้อย่างไร?
มีบทความมากมายเกี่ยวกับวิธีการปรับแต่งและเพิ่มประสิทธิภาพ WordPress อันที่จริง WordPress เองก็มีคู่มือที่มีประสิทธิภาพในการเพิ่มประสิทธิภาพ WordPress
โดยส่วนใหญ่ บทความและบทช่วยสอนเหล่านี้ครอบคลุมแนวคิดที่ค่อนข้างเรียบง่ายแต่มีประโยชน์ เช่น การใช้ปลั๊กอินแคช การผสานรวมกับเครือข่ายการจัดส่งเนื้อหา (CDN) และการลดคำขอ แม้ว่าคำแนะนำเหล่านี้จะมีประสิทธิภาพสูงและจำเป็น แต่ท้ายที่สุดแล้วก็ไม่ได้ช่วยแก้ปัญหาพื้นฐาน: ไซต์ WordPress ที่ช้าส่วนใหญ่เป็นผลมาจากโค้ดที่ไม่ดีหรือไม่มีประสิทธิภาพ
ดังนั้น บทความนี้จึงมีวัตถุประสงค์หลักเพื่อให้นักพัฒนาและบริษัทพัฒนา WordPress ทราบถึงแนวทางบางประการที่สามารถช่วยแก้ปัญหาด้านประสิทธิภาพของ WordPress ได้
WordPress มีคุณสมบัติที่เน้นประสิทธิภาพมากมายที่นักพัฒนามักมองข้าม โค้ดที่ไม่ใช้ประโยชน์จากคุณลักษณะเหล่านี้อาจทำให้งานที่ง่ายที่สุดช้าลง เช่น การดึงข้อมูลโพสต์ บทความนี้ให้รายละเอียดวิธีแก้ปัญหาที่เป็นไปได้สี่วิธี ซึ่งระบุปัญหาเบื้องหลังการทำงานของ WordPress ที่ช้า
กำลังดึงกระทู้
WordPress เสนอความเป็นไปได้ในการดึงโพสต์ประเภทใดก็ได้จากฐานข้อมูล มีสามวิธีพื้นฐานในการทำเช่นนั้น:
การใช้
query_posts()
: นี่เป็นแนวทางที่ตรงไปตรงมามาก แต่ปัญหาคือมันแทนที่การสืบค้นหลัก ซึ่งอาจนำไปสู่ความไม่สะดวก ตัวอย่างเช่น นี่อาจเป็นปัญหาหากเราต้องการตรวจสอบ ในบางจุดหลังจากที่ดึงข้อมูลโพสต์ (เช่น ภายในfooter.php
) เพจประเภทใดที่เรากำลังดำเนินการอยู่ อันที่จริง เอกสารอย่างเป็นทางการมีหมายเหตุที่แนะนำให้ต่อต้านการใช้ฟังก์ชันนี้ เนื่องจากคุณจะต้องเรียกใช้ฟังก์ชันเพิ่มเติมเพื่อกู้คืนการสืบค้นข้อมูลเดิม นอกจากนี้ การแทนที่การสืบค้นข้อมูลหลักจะส่งผลเสียต่อเวลาในการโหลดหน้าการใช้ฟังก์ชัน get_posts(
get_posts()
: ใช้งานได้เหมือนกับquery_posts()
แต่จะไม่แก้ไขการสืบค้นหลัก ในทางกลับกัน โดยค่าเริ่มต้นget_posts()
จะทำการสืบค้นโดยตั้งค่าพารามิเตอร์suppress_filters
true
ซึ่งอาจนำไปสู่ความไม่สอดคล้องกัน โดยเฉพาะอย่างยิ่งถ้าเราใช้ตัวกรองที่เกี่ยวข้องกับการสืบค้นในโค้ดของเรา เนื่องจากฟังก์ชันนี้อาจส่งคืนโพสต์ที่คุณไม่ได้คาดหวังในหน้าเพจการใช้คลาส
WP_Query
: ในความคิดของฉัน นี่เป็นวิธีที่ดีที่สุดในการดึงข้อมูลโพสต์จากฐานข้อมูล ไม่เปลี่ยนแปลงการสืบค้นข้อมูลหลัก และดำเนินการในลักษณะมาตรฐาน เช่นเดียวกับการสืบค้นอื่นๆ ของ WordPress
แต่ไม่ว่าเราจะใช้วิธีใดในการโต้ตอบกับฐานข้อมูล มีสิ่งอื่น ๆ ที่เราต้องพิจารณา
การจำกัดการสืบค้น
เราควรระบุจำนวนโพสต์ที่ต้องดึงข้อมูลข้อความค้นหาเสมอ
เพื่อให้บรรลุผลนั้น เราใช้พารามิเตอร์ posts_per_page
WordPress ให้เราระบุ -1 เป็นค่าที่เป็นไปได้สำหรับพารามิเตอร์นั้น ในกรณีนี้ระบบจะพยายามดึงข้อมูลโพสต์ทั้งหมดที่ตรงตามเงื่อนไขที่กำหนดไว้
นี่ไม่ใช่แนวทางปฏิบัติที่ดี แม้ว่าเราจะแน่ใจว่าเราจะได้ผลลัพธ์กลับมาเพียงไม่กี่คำตอบเท่านั้น
ประการหนึ่ง เราไม่ค่อยแน่ใจนักว่าจะได้ผลลัพธ์กลับมาเพียงไม่กี่ครั้ง และแม้ว่าเราทำได้ การตั้งไม่จำกัดจะทำให้เอ็นจิ้นฐานข้อมูลสแกนฐานข้อมูลทั้งหมดเพื่อค้นหารายการที่ตรงกัน
ในทางกลับกัน การจำกัดผลลัพธ์มักจะทำให้กลไกฐานข้อมูลสามารถสแกนข้อมูลได้เพียงบางส่วนเท่านั้น ซึ่งแปลว่าใช้เวลาในการประมวลผลน้อยลงและตอบสนองเร็วขึ้น
อีกสิ่งหนึ่งที่ WordPress ทำโดยค่าเริ่มต้น ซึ่งอาจส่งผลเสียต่อประสิทธิภาพการทำงาน คือพยายามนำโพสต์ที่ติดหนึบและคำนวณจำนวนแถวที่พบในแบบสอบถาม
แม้ว่าบ่อยครั้งที่เราไม่ต้องการข้อมูลนั้นจริงๆ การเพิ่มพารามิเตอร์ทั้งสองนี้จะปิดใช้งานคุณลักษณะเหล่านั้นและทำให้การสืบค้นของเราเร็วขึ้น:
$query = new WP_Query( array( 'ignore_sticky_posts' => true, 'no_found_rows' => true ) );
ไม่รวมโพสต์จากแบบสอบถาม
บางครั้งเราต้องการแยกบางโพสต์ออกจากข้อความค้นหา WordPress นำเสนอวิธีการที่ค่อนข้างตรงไปตรงมา: ใช้พารามิเตอร์ post__not_in
ตัวอย่างเช่น:
$posts_to_exclude = array( 1, 2, 3 ); $posts_per_page = 10; $query = new WP_Query( array( 'posts_per_page' => $posts_per_page, 'post__not_in' => $posts_to_exclude ) ); for ( $i = 0; $i < count( $query->posts ); $i++ ) { //do stuff with $query->posts[ $i ] }
แต่แม้ว่าจะค่อนข้างเรียบง่าย แต่ก็ไม่เหมาะเพราะภายในจะสร้างแบบสอบถามย่อย โดยเฉพาะอย่างยิ่งในการติดตั้งขนาดใหญ่ อาจทำให้การตอบสนองช้า ให้ล่าม PHP ประมวลผลนั้นเร็วกว่าด้วยการดัดแปลงง่ายๆ บางอย่าง:
$posts_to_exclude = array( 1, 2, 3 ); $posts_per_page = 10; $query = new WP_Query( array( 'posts_per_page' => $posts_per_page + count( $posts_to_exclude ) ) ); for ( $i = 0; $i < count( $query->posts ) && $i < $posts_per_page; $i++ ) { if ( ! in_array( $query->posts[ $i ]->ID, $posts_to_exclude ) ) { //do stuff with $query->posts[ $i ] } }
ฉันทำอะไรที่นั่น
โดยพื้นฐานแล้ว ฉันนำงานบางส่วนออกจากเอ็นจิ้นฐานข้อมูลและปล่อยให้มันทำงานแทนเอ็นจิ้น PHP ซึ่งทำสิ่งเดียวกันแต่ในหน่วยความจำ ซึ่งเร็วกว่ามาก
ยังไง?
ก่อนอื่น ฉันลบพารามิเตอร์ post__not_in
ออกจากข้อความค้นหา
เนื่องจากข้อความค้นหาอาจทำให้เราโพสต์บางรายการซึ่งเราไม่ต้องการผลลัพธ์ ฉันจึงเพิ่มพารามิเตอร์ posts_per_page
ด้วยวิธีนี้ ฉันรับรองว่าแม้ว่าฉันจะมีโพสต์ที่ไม่ต้องการในคำตอบของฉัน แต่ฉันก็มีโพสต์ที่ต้องการอย่างน้อย $posts_per_page
จากนั้น เมื่อฉันวนซ้ำโพสต์ ฉันจะประมวลผลเฉพาะสิ่งที่ไม่อยู่ในอาร์เรย์ $posts_to_exclude
หลีกเลี่ยงการกำหนดพารามิเตอร์ที่ซับซ้อน
วิธีการสืบค้นข้อมูลเหล่านี้นำเสนอความเป็นไปได้ที่หลากหลายสำหรับการดึงข้อมูลโพสต์: ตามหมวดหมู่ ตามคีย์เมตาหรือค่า ตามวันที่ โดยผู้เขียน ฯลฯ
และในขณะที่ความยืดหยุ่นนั้นเป็นคุณลักษณะที่ทรงพลัง แต่ควรใช้ด้วยความระมัดระวัง เนื่องจากการกำหนดพารามิเตอร์นั้นสามารถแปลเป็นการรวมตารางที่ซับซ้อนและการดำเนินการฐานข้อมูลที่มีราคาแพง
ในส่วนถัดไป เราจะร่างวิธีที่สวยงามในการบรรลุการทำงานที่คล้ายคลึงกันโดยไม่กระทบต่อประสิทธิภาพ
บีบตัวเลือก WordPress ให้เกิดประโยชน์สูงสุด
WordPress Options API มีชุดเครื่องมือสำหรับการโหลดหรือบันทึกข้อมูลอย่างง่ายดาย มีประโยชน์ในการจัดการข้อมูลชิ้นเล็กๆ ซึ่งกลไกอื่นๆ ที่ WordPress นำเสนอ (เช่น โพสต์หรืออนุกรมวิธาน) นั้นซับซ้อนเกินไป

ตัวอย่างเช่น หากเราต้องการจัดเก็บคีย์การตรวจสอบสิทธิ์หรือสีพื้นหลังของส่วนหัวของไซต์ ตัวเลือกคือสิ่งที่เรากำลังมองหา
WordPress ไม่เพียงแต่ให้ฟังก์ชันต่างๆ แก่เราเท่านั้น แต่ยังช่วยให้เราดำเนินการดังกล่าวได้อย่างมีประสิทธิภาพสูงสุด
ตัวเลือกบางตัวจะโหลดโดยตรงเมื่อระบบเริ่มทำงาน ทำให้เราเข้าถึงได้เร็วขึ้น (เมื่อสร้างตัวเลือกใหม่ เราต้องพิจารณาว่าเราต้องการโหลดอัตโนมัติหรือไม่)
ตัวอย่างเช่น ลองพิจารณาไซต์ที่เราให้ภาพหมุนแสดงข่าวด่วนซึ่งระบุไว้ในส่วนหลัง สัญชาตญาณแรกของเราคือการใช้เมตาคีย์ดังนี้:
// functions.php add_action( 'save_post', function ( $post_id ) { // For simplicity, we do not include all the required validation before saving // the meta key: checking nonces, checking post type and status, checking // it is not a revision or an autosaving, etc. update_post_meta( $post_id, 'is_breaking_news', ! empty ( $_POST['is_breaking_news'] ) ); } ); // front-page.php $query = new WP_Query( array( 'posts_per_page' => 1, 'meta_key' => 'is_breaking_news' ) ); $breaking_news = $query->posts[0] ?: NULL;
อย่างที่คุณเห็น แนวทางนี้เรียบง่ายมาก แต่ไม่เหมาะสม จะทำการค้นหาฐานข้อมูลโดยพยายามค้นหาโพสต์ด้วยเมตาคีย์เฉพาะ เราสามารถใช้ตัวเลือกเพื่อให้ได้ผลลัพธ์ที่คล้ายคลึงกัน:
// functions.php add_action( 'save_post', function ( $post_id ) { // Same comment for post validation if ( ! empty ( $_POST['is_breaking_news'] ) ) update_option( 'breaking_news_id', $post_id ); } ); // front-page.php if ( $breaking_news_id = get_option( 'breaking_news_id' ) ) $breaking_news = get_post( $breaking_news_id ); else $breaking_news = NULL;
ฟังก์ชันการทำงานจะแตกต่างกันเล็กน้อยจากตัวอย่างหนึ่งไปอีกตัวอย่างหนึ่ง
ในโค้ดชิ้นแรก เราจะได้รับข่าวสารล่าสุดเสมอในแง่ของวันที่เผยแพร่ของโพสต์
ในอันที่สอง ทุกครั้งที่ตั้งโพสต์ใหม่เป็นข่าวด่วน โพสต์นั้นจะเขียนทับข่าวด่วนก่อนหน้า
แต่เนื่องจากเราอาจต้องการโพสต์ข่าวด่วนครั้งละหนึ่งโพสต์ จึงไม่เป็นปัญหา
และในท้ายที่สุด เราได้เปลี่ยนการสืบค้นฐานข้อมูลจำนวนมาก (โดยใช้ WP_Query
พร้อมเมตาคีย์) เป็นการสืบค้นที่ง่ายและตรงไปตรงมา (การเรียก get_post()
) ซึ่งเป็นแนวทางที่ดีกว่าและมีประสิทธิภาพมากกว่า
เรายังสามารถทำการเปลี่ยนแปลงเล็กน้อย และใช้ชั่วคราวแทนตัวเลือก
Transients ทำงานในลักษณะเดียวกัน แต่อนุญาตให้เราระบุเวลาหมดอายุได้
เช่น ข่าวด่วน ก็เหมือนถุงมือเพราะเราไม่ต้องการให้โพสต์เก่าเป็นข่าวด่วน และถ้าเราปล่อยให้งานเปลี่ยนหรือกำจัดข่าวด่วนนั้นให้ผู้ดูแลระบบ [s] เขาอาจลืมทำ มัน. ดังนั้น ด้วยการเปลี่ยนแปลงง่ายๆ สองประการ เราจึงเพิ่มวันหมดอายุ:
// functions.php add_action( 'save_post', function ( $post_id ) { // Same comment for post validation // Let's say we want that breaking news for one hour // (3600 = # of seconds in an hour). if ( ! empty ( $_POST['is_breaking_news'] ) ) set_transient( 'breaking_news_id', $post_id, 3600 ); } ); // front-page.php if ( $breaking_news_id = get_transient( 'breaking_news_id' ) ) $breaking_news = get_post( $breaking_news_id ); else $breaking_news = NULL;
เปิดใช้งานการแคชแบบถาวร
WordPress มีกลไกการแคชวัตถุ
ตัวอย่างเช่น ตัวเลือกจะถูกแคชโดยใช้กลไกนั้น
แต่ตามค่าเริ่มต้น การแคชนั้นจะไม่คงอยู่ หมายความว่าจะใช้งานได้เฉพาะในช่วงระยะเวลาของคำขอเดียว ข้อมูลทั้งหมดถูกแคชไว้ในหน่วยความจำ เพื่อการเข้าถึงที่รวดเร็วยิ่งขึ้น แต่จะใช้ได้เฉพาะระหว่างที่ร้องขอเท่านั้น
การสนับสนุนการแคชแบบถาวรจำเป็นต้องติดตั้งปลั๊กอินแคชแบบถาวร
ปลั๊กอินแคชแบบเต็มหน้าบางตัวมาพร้อมกับปลั๊กอินแคชแบบถาวร (เช่น W3 Total Cache) แต่ตัวอื่นๆ ไม่มี และเราจำเป็นต้องติดตั้งแยกต่างหาก
จะขึ้นอยู่กับสถาปัตยกรรมของแพลตฟอร์มของเรา ไม่ว่าเราจะใช้ไฟล์ Memcached หรือกลไกอื่นๆ เพื่อจัดเก็บข้อมูลแคช แต่เราควรใช้ประโยชน์จากคุณลักษณะที่น่าทึ่งนี้
อาจมีคนถามว่า: “ถ้านี่เป็นคุณสมบัติที่ยอดเยี่ยม ทำไม WordPress ไม่เปิดใช้งานตามค่าเริ่มต้น”?
เหตุผลหลักคือ เทคนิคแคชบางอย่างจะใช้งานได้ ทั้งนี้ขึ้นอยู่กับสถาปัตยกรรมของแพลตฟอร์มของเรา
หากเราโฮสต์ไซต์ของเราในเซิร์ฟเวอร์แบบกระจายของเรา เราควรใช้ระบบแคชภายนอก (เช่น เซิร์ฟเวอร์ Memcached) แต่ถ้าเว็บไซต์ของเราอยู่บนเซิร์ฟเวอร์เดียว เราก็สามารถประหยัดเงินได้โดยใช้ระบบไฟล์ เพื่อแคช
สิ่งหนึ่งที่เราต้องคำนึงถึงคือการหมดอายุของแคช นี่เป็นหลุมพรางที่พบบ่อยที่สุดในการทำงานกับการแคชแบบถาวร
หากเราไม่แก้ไขปัญหานี้อย่างถูกต้อง ผู้ใช้ของเราจะบ่นว่าจะไม่เห็นการเปลี่ยนแปลงที่พวกเขาทำหรือการเปลี่ยนแปลงใช้เวลานานเกินไปที่จะใช้
บางครั้งเราจะพบว่าตัวเองกำลังแลกกันระหว่างประสิทธิภาพและไดนามิก แต่ถึงแม้จะมีอุปสรรคเหล่านั้น การแคชแบบถาวรก็เป็นสิ่งที่แทบทุกการติดตั้ง WordPress ควรใช้ประโยชน์จาก
AJAXing วิธีที่เร็วที่สุด
หากเราจำเป็นต้องสื่อสารผ่าน AJAX กับเว็บไซต์ของเรา WordPress เสนอสิ่งที่เป็นนามธรรมในขณะที่ดำเนินการตามคำขอทางฝั่งเซิร์ฟเวอร์
แม้ว่าเทคนิคเหล่านั้นจะสามารถใช้ได้เมื่อตั้งโปรแกรมเครื่องมือส่วนหลังหรือการส่งแบบฟอร์มจากส่วนหน้า แต่ควรหลีกเลี่ยงหากไม่จำเป็นอย่างยิ่ง
เหตุผลก็คือเพื่อใช้กลไกเหล่านั้น เราจำเป็นต้องส่งคำขอโพสต์ไปยังไฟล์บางไฟล์ที่อยู่ในโฟลเดอร์ wp-admin
ปลั๊กอินแคชแบบเต็มหน้าของ WordPress ส่วนใหญ่ (ถ้าไม่ใช่ทั้งหมด) ไม่ใช่คำขอโพสต์แคชหรือการเรียกใช้ไฟล์ผู้ดูแลระบบ
ตัวอย่างเช่น หากเราโหลดโพสต์แบบไดนามิกมากขึ้นเมื่อผู้ใช้เลื่อนหน้าแรกของเรา จะเป็นการดีกว่าที่จะเรียกไปยังหน้าส่วนหน้าอื่นโดยตรง ซึ่งจะได้รับประโยชน์จากการถูกแคช
จากนั้นเราสามารถแยกวิเคราะห์ผลลัพธ์ผ่าน JavaScript ในเบราว์เซอร์
ใช่ เรากำลังส่งข้อมูลมากกว่าที่จำเป็น แต่เราชนะในแง่ของความเร็วในการประมวลผลและเวลาตอบสนอง
ทำลายความคิดที่ว่า WordPress นั้นทำงานช้า
นี่เป็นเพียงคำแนะนำบางส่วนที่นักพัฒนาซอฟต์แวร์ควรพิจารณาเมื่อเขียนโค้ดสำหรับ WordPress
บางครั้ง เราลืมไปว่าปลั๊กอินหรือธีมของเราอาจต้องใช้ร่วมกับปลั๊กอินอื่นๆ หรือไซต์ของเราอาจให้บริการโดยบริษัทที่ให้บริการพื้นที่ซึ่งให้บริการไซต์อื่นๆ หลายร้อยหรือหลายพันแห่งที่มีฐานข้อมูลร่วมกัน
เราแค่เน้นว่าปลั๊กอินควรทำงานอย่างไร ไม่ใช่ว่าปลั๊กอินเกี่ยวข้องกับฟังก์ชันนั้นอย่างไร หรือทำอย่างไรให้มีประสิทธิภาพ
จากข้างต้น เป็นที่ชัดเจนว่าสาเหตุของประสิทธิภาพที่ไม่ดีใน WordPress นั้นเป็นโค้ดที่ไม่ดีและไม่มีประสิทธิภาพ อย่างไรก็ตาม WordPress มีฟังก์ชันที่จำเป็นทั้งหมดผ่าน API ต่างๆ ที่ช่วยให้เราสร้างปลั๊กอินและธีมที่มีประสิทธิภาพมากขึ้นโดยไม่ลดความเร็วของแพลตฟอร์มโดยรวม