WordPress แบบไม่มีหัว: ข้อดีและข้อเสียของการสร้าง WordPress แบบแยกส่วน

เผยแพร่แล้ว: 2022-03-10
สรุปด่วน ↬ ทุกคนรู้ดีว่าถ้าเว็บไซต์ช้าผู้ใช้จะละทิ้งมัน การศึกษาจำนวนมากแสดงให้เห็นถึงความเชื่อมโยงระหว่างประสิทธิภาพของเว็บไซต์และอัตราการแปลง ในบทความนี้ Denis Zoljom จะมาแบ่งปันประสบการณ์และพื้นฐานของการสร้าง WordPress แบบแยกส่วน

WordPress มาไกลตั้งแต่เริ่มต้นในฐานะเครื่องมือเขียนบล็อกอย่างง่าย 15 ปีต่อมา มันกลายเป็นตัวเลือก CMS อันดับหนึ่งสำหรับนักพัฒนาและผู้ที่ไม่ใช่นักพัฒนา ตอนนี้ WordPress มีอำนาจประมาณ 30% ของเว็บไซต์ 10 ล้านอันดับแรกบนเว็บ

นับตั้งแต่ REST API ถูกรวมไว้ในแกนหลักของ WordPress นักพัฒนาสามารถทดลองและใช้งานในลักษณะแยกส่วนได้ เช่น การเขียนส่วนหน้าโดยใช้เฟรมเวิร์กหรือไลบรารี JavaScript ที่ Infinum เรา (และยังคงใช้) WordPress ในรูปแบบ 'คลาสสิก': PHP สำหรับส่วนหน้าและส่วนหลัง หลังจากนั้นไม่นาน เราก็อยากจะลองใช้วิธีการแบบแยกคู่ ในบทความนี้ ฉันจะแบ่งปันภาพรวมของสิ่งที่เราต้องการบรรลุและสิ่งที่เราพบขณะพยายามดำเนินการตามเป้าหมายของเรา

มีโครงการหลายประเภทที่สามารถได้รับประโยชน์จากแนวทางนี้ ตัวอย่างเช่น ไซต์การนำเสนอทั่วไปหรือไซต์ที่ใช้ WordPress เป็นแบ็กเอนด์คือตัวเลือกหลักสำหรับแนวทางแยกส่วน

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

การอ่านที่แนะนำ : วิธีใช้ Heatmaps เพื่อติดตามการคลิกบนเว็บไซต์ WordPress ของคุณ

หากการตอบกลับเว็บไซต์เป็นเวลานานทำให้คุณนอนไม่หลับ นี่คือวิธีการสำหรับคุณ ฉันจะครอบคลุมพื้นฐานของการสร้าง WordPress แบบแยกส่วนและบทเรียนบางส่วนที่ได้เรียนรู้ ได้แก่ :

  1. ความหมายของ “เวิร์ดเพรสแยก”
  2. การทำงานกับ WordPress REST API ที่เป็นค่าเริ่มต้น
  3. การปรับปรุงประสิทธิภาพด้วยแนวทาง JSON แบบแยกส่วน
  4. ความกังวลด้านความปลอดภัย
เพิ่มเติมหลังกระโดด! อ่านต่อด้านล่าง↓

ดังนั้น WordPress แบบแยกส่วนคืออะไรกันแน่?

เมื่อพูดถึงวิธีการตั้งโปรแกรม WordPress สิ่งหนึ่งที่แน่นอนคือ มันไม่เป็นไปตามรูปแบบการออกแบบ M odel- V iew- C ontroller (MVC) ที่นักพัฒนาหลายคนคุ้นเคย เนื่องจากประวัติความเป็นมาและการจัดเรียงของแพลตฟอร์มบล็อกเก่าที่เรียกว่า "b2" (รายละเอียดเพิ่มเติมที่นี่) ส่วนใหญ่เขียนในลักษณะที่เป็นขั้นตอน (โดยใช้โค้ดตามฟังก์ชัน) นักพัฒนาหลักของ WordPress ใช้ระบบ hooks ซึ่งอนุญาตให้นักพัฒนารายอื่นแก้ไขหรือขยายฟังก์ชันการทำงานบางอย่างได้

เป็นระบบ all-in-one ที่ติดตั้งอินเทอร์เฟซผู้ดูแลระบบที่ใช้งานได้ มันจัดการการเชื่อมต่อฐานข้อมูล และมี API ที่มีประโยชน์มากมายที่เปิดเผยซึ่งจัดการการพิสูจน์ตัวตนผู้ใช้ การกำหนดเส้นทาง และอื่นๆ

แต่ต้องขอบคุณ REST API ที่ทำให้คุณสามารถแยกแบ็กเอนด์ของ WordPress ออกเป็นแบบจำลองและตัวควบคุมที่รวมเข้าด้วยกันซึ่งจัดการการจัดการข้อมูลและการโต้ตอบของฐานข้อมูล และใช้ REST API Controller เพื่อโต้ตอบกับเลเยอร์มุมมองที่แยกจากกันโดยใช้จุดปลาย API ต่างๆ นอกเหนือจากการแยก MVC เราสามารถ (ด้วยเหตุผลด้านความปลอดภัยหรือการปรับปรุงความเร็ว) วางแอป JS บนเซิร์ฟเวอร์ที่แยกจากกัน เช่นในสคีมาด้านล่าง:

รูปภาพที่แสดงไดอะแกรม WordPress แบบแยกส่วนโดยแยกส่วน PHP และ JS
ไดอะแกรม WordPress แบบแยกส่วน (ตัวอย่างขนาดใหญ่)

ข้อดีของการใช้แนวทางแยกส่วน

สิ่งหนึ่งที่คุณอาจต้องการใช้วิธีนี้เพื่อแยกข้อกังวล ส่วนหน้าและส่วนหลังมีการโต้ตอบกันผ่านจุดปลาย แต่ละเซิร์ฟเวอร์สามารถอยู่บนเซิร์ฟเวอร์ที่แยกจากกัน ซึ่งสามารถปรับให้เหมาะสมสำหรับแต่ละงานโดยเฉพาะ เช่น เรียกใช้แอป PHP และเรียกใช้แอป Node.js แยกกัน

การแยกส่วนหน้าออกจากส่วนหลังจะทำให้ออกแบบใหม่ได้ง่ายขึ้นในอนาคต โดยไม่ต้องเปลี่ยน CMS นอกจากนี้ นักพัฒนาส่วนหน้าจะต้องสนใจว่าจะทำอย่างไรกับข้อมูลที่แบ็กเอนด์ให้ไว้เท่านั้น ซึ่งช่วยให้พวกเขามีความคิดสร้างสรรค์และใช้ไลบรารีที่ทันสมัย ​​เช่น ReactJS, Vue หรือ Angular เพื่อนำเสนอเว็บแอปแบบไดนามิกสูง ตัวอย่างเช่น การสร้างเว็บแอปแบบโปรเกรสซีฟจะง่ายกว่าเมื่อใช้ไลบรารีดังกล่าว

ข้อดีอีกประการหนึ่งสะท้อนให้เห็นในการรักษาความปลอดภัยเว็บไซต์ การใช้ประโยชน์จากเว็บไซต์ผ่านแบ็กเอนด์นั้นยากขึ้นเนื่องจากส่วนใหญ่ซ่อนจากสาธารณะ

การอ่านที่แนะนำ : WordPress Security As A Process

ข้อบกพร่องของการใช้แนวทางแยกส่วน

ขั้นแรก การมี WordPress แบบแยกส่วนหมายถึงการรักษาสองอินสแตนซ์แยกกัน:

  1. WordPress สำหรับแบ็กเอนด์;
  2. แอปฟรอนต์เอนด์ที่แยกต่างหาก รวมถึงการอัปเดตความปลอดภัยตามกำหนดเวลา

ประการที่สอง ไลบรารีส่วนหน้าบางส่วนมีช่วงการเรียนรู้ที่ชันกว่า อาจต้องใช้เวลามากในการเรียนรู้ภาษาใหม่ (หากคุณคุ้นเคยกับ HTML และ CSS สำหรับการสร้างเทมเพลตเท่านั้น) หรือจะต้องนำผู้เชี่ยวชาญ JavaScript เพิ่มเติมมาที่โครงการ

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

การทำงานกับ WordPress REST API

ก่อนที่เราจะเจาะลึกลงไปในโค้ด อีกสองสามสิ่งเกี่ยวกับ WordPress REST API พลังเต็มที่ของ REST API ใน WordPress มาพร้อมกับเวอร์ชัน 4.7 ในวันที่ 6 ธันวาคม 2016

สิ่งที่ WordPress REST API ให้คุณทำได้คือโต้ตอบกับการติดตั้ง WordPress ของคุณจากระยะไกลโดยส่งและรับออบเจกต์ JSON

ตั้งโครงการ

เนื่องจากมันมาพร้อมกับการติดตั้ง WordPress ล่าสุด เราจึงจะทำงานกับธีม Twenty Seventeen ฉันกำลังทำงานกับ Varying Vagrant Vagrants และได้ตั้งค่าไซต์ทดสอบที่มี URL https://dev.wordpress.test/ URL นี้จะถูกใช้ตลอดทั้งบทความ นอกจากนี้เรายังจะนำเข้าโพสต์จากที่เก็บ wordpress.org Theme Review Teams เพื่อให้เรามีข้อมูลทดสอบที่จะใช้งานได้ แต่ก่อนอื่น เราจะทำความคุ้นเคยกับการทำงานกับปลายทางเริ่มต้น จากนั้นเราจะสร้างปลายทางที่กำหนดเอง

เข้าถึงปลายทาง REST เริ่มต้น

ดังที่ได้กล่าวไปแล้ว WordPress มาพร้อมกับจุดปลายในตัวหลายตัวที่คุณสามารถตรวจสอบได้โดยไปที่เส้นทาง /wp-json/ :

 https://dev.wordpress.test/wp-json/

ไม่ว่าจะใส่ URL นี้โดยตรงในเบราว์เซอร์ของคุณ หรือเพิ่มลงในแอปบุรุษไปรษณีย์ คุณจะได้รับการตอบสนอง JSON จาก WordPress REST API ที่มีลักษณะดังนี้:

 { "name": "Test dev site", "description": "Just another WordPress site", "url": "https://dev.wordpress.test", "home": "https://dev.wordpress.test", "gmt_offset": "0", "timezone_string": "", "namespaces": [ "oembed/1.0", "wp/v2" ], "authentication": [], "routes": { "/": { "namespace": "", "methods": [ "GET" ], "endpoints": [ { "methods": [ "GET" ], "args": { "context": { "required": false, "default": "view" } } } ], "_links": { "self": "https://dev.wordpress.test/wp-json/" } }, "/oembed/1.0": { "namespace": "oembed/1.0", "methods": [ "GET" ], "endpoints": [ { "methods": [ "GET" ], "args": { "namespace": { "required": false, "default": "oembed/1.0" }, "context": { "required": false, "default": "view" } } } ], "_links": { "self": "https://dev.wordpress.test/wp-json/oembed/1.0" } }, ... "wp/v2": { ...

ดังนั้นเพื่อให้ได้โพสต์ทั้งหมดในเว็บไซต์ของเราโดยใช้ REST เราจะต้องไปที่ https://dev.wordpress.test/wp-json/wp/v2/posts โปรดสังเกตว่า wp/v2/ ทำเครื่องหมายปลายทางหลักที่สงวนไว้ เช่น โพสต์ เพจ สื่อ การจัดหมวดหมู่ หมวดหมู่ และอื่นๆ

เราจะเพิ่มปลายทางที่กำหนดเองได้อย่างไร

สร้างจุดสิ้นสุด REST ที่กำหนดเอง

สมมติว่าเราต้องการเพิ่มปลายทางใหม่หรือฟิลด์เพิ่มเติมไปยังปลายทางที่มีอยู่ มีหลายวิธีที่เราสามารถทำได้ ขั้นแรกสามารถทำได้โดยอัตโนมัติเมื่อสร้างประเภทโพสต์ที่กำหนดเอง ตัวอย่างเช่น เราต้องการสร้างปลายทางเอกสาร มาสร้างปลั๊กอินทดสอบขนาดเล็กกัน สร้างโฟลเดอร์ test-documentation ในโฟลเดอร์ wp-content/plugins และเพิ่มไฟล์ document.php ที่มีลักษณะดังนี้:

 <?php /** * Test plugin * * @since 1.0.0 * @package test_plugin * * @wordpress-plugin * Plugin Name: Test Documentation Plugin * Plugin URI: * Description: The test plugin that adds rest functionality * Version: 1.0.0 * Author: Infinum <[email protected]> * Author URI: https://infinum.co/ * License: GPL-2.0+ * License URI: https://www.gnu.org/licenses/gpl-2.0.txt * Text Domain: test-plugin */ namespace Test_Plugin; // If this file is called directly, abort. if ( ! defined( 'WPINC' ) ) { die; } /** * Class that holds all the necessary functionality for the * documentation custom post type * * @since 1.0.0 */ class Documentation { /** * The custom post type slug * * @var string * * @since 1.0.0 */ const PLUGIN_NAME = 'documentation-plugin'; /** * The custom post type slug * * @var string * * @since 1.0.0 */ const POST_TYPE_SLUG = 'documentation'; /** * The custom taxonomy type slug * * @var string * * @since 1.0.0 */ const TAXONOMY_SLUG = 'documentation-category'; /** * Register custom post type * * @since 1.0.0 */ public function register_post_type() { $args = array( 'label' => esc_html( 'Documentation', 'test-plugin' ), 'public' => true, 'menu_position' => 47, 'menu_icon' => 'dashicons-book', 'supports' => array( 'title', 'editor', 'revisions', 'thumbnail' ), 'has_archive' => false, 'show_in_rest' => true, 'publicly_queryable' => false, ); register_post_type( self::POST_TYPE_SLUG, $args ); } /** * Register custom tag taxonomy * * @since 1.0.0 */ public function register_taxonomy() { $args = array( 'hierarchical' => false, 'label' => esc_html( 'Documentation tags', 'test-plugin' ), 'show_ui' => true, 'show_admin_column' => true, 'update_count_callback' => '_update_post_term_count', 'show_in_rest' => true, 'query_var' => true, ); register_taxonomy( self::TAXONOMY_SLUG, [ self::POST_TYPE_SLUG ], $args ); } } $documentation = new Documentation(); add_action( 'init', [ $documentation, 'register_post_type' ] ); add_action( 'init', [ $documentation, 'register_taxonomy' ] );

ด้วยการลงทะเบียนประเภทโพสต์และอนุกรมวิธานใหม่ และตั้งค่าอาร์กิวเมนต์ show_in_rest true WordPress จะสร้างเส้นทาง REST ใน /wp/v2/ เนมสเปซโดยอัตโนมัติ ตอนนี้คุณมี https://dev.wordpress.test/wp-json/wp/v2/documentation และ https://dev.wordpress.test/wp-json/wp/v2/documentation-category endpoints ที่พร้อมใช้งาน หากเราเพิ่มโพสต์ในโพสต์ที่กำหนดเองของเอกสารที่สร้างขึ้นใหม่โดยไปที่ https://dev.wordpress.test/?post_type=documentation มันจะให้คำตอบที่มีลักษณะดังนี้:

 [ { "id": 4, "date": "2018-06-11T19:48:51", "date_gmt": "2018-06-11T19:48:51", "guid": { "rendered": "https://dev.wordpress.test/?post_type=documentation&p=4" }, "modified": "2018-06-11T19:48:51", "modified_gmt": "2018-06-11T19:48:51", "slug": "test-documentation", "status": "publish", "type": "documentation", "link": "https://dev.wordpress.test/documentation/test-documentation/", "title": { "rendered": "Test documentation" }, "content": { "rendered": "

นี่คือเนื้อหาเอกสารบางส่วน

\n", "ป้องกัน": เท็จ }, "feature_media": 0, "แม่แบบ": "", "หมวดหมู่เอกสาร": [ 2 ], "_links": { "ตัวเอง": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation/4" } ], "ของสะสม": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation" } ], "เกี่ยวกับ": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/types/documentation" } ], "รุ่น-ประวัติ": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation/4/revisions" } ], "wp:ไฟล์แนบ": [ { "href": "https://dev.wordpress.test/wp-json/wp/v2/media?parent=4" } ], "wp:term": [ { "taxonomy": "หมวดหมู่เอกสารประกอบ", "ฝังได้": จริง, "href": "https://dev.wordpress.test/wp-json/wp/v2/documentation-category?post=4" } ], "curies": [ { "ชื่อ": "wp", "href": "https://api.w.org/{rel}", "เทมเพลท": จริง } ] } } ]

นี่เป็นจุดเริ่มต้นที่ดีสำหรับแอปพลิเคชันหน้าเดียวของเรา อีกวิธีหนึ่งที่เราสามารถเพิ่มจุดปลายแบบกำหนดเองได้คือการต่อเบ็ด rest_api_init และสร้างจุดปลายด้วยตนเอง มาเพิ่มเส้นทาง custom-documentation ซึ่งแตกต่างจากที่เราลงทะเบียนไว้เล็กน้อย ยังคงทำงานในปลั๊กอินเดิม เราสามารถเพิ่ม:

 /** * Create a custom endpoint * * @since 1.0.0 */ public function create_custom_documentation_endpoint() { register_rest_route( self::PLUGIN_NAME . '/v1', '/custom-documentation', array( 'methods' => 'GET', 'callback' => [ $this, 'get_custom_documentation' ], ) ); } /** * Create a callback for the custom documentation endpoint * * @return string JSON that indicates success/failure of the update, * or JSON that indicates an error occurred. * @since 1.0.0 */ public function get_custom_documentation() { /* Some permission checks can be added here. */ // Return only documentation name and tag name. $doc_args = array( 'post_type' => self::POST_TYPE_SLUG, 'post_status' => 'publish', 'perm' => 'readable' ); $query = new \WP_Query( $doc_args ); $response = []; $counter = 0; // The Loop if ( $query->have_posts() ) { while ( $query->have_posts() ) { $query->the_post(); $post_id = get_the_ID(); $post_tags = get_the_terms( $post_id, self::TAXONOMY_SLUG ); $response[ $counter ]['title'] = get_the_title(); foreach ( $post_tags as $tags_key => $tags_value ) { $response[ $counter ]['tags'][] = $tags_value->name; } $counter++; } } else { $response = esc_html__( 'There are no posts.', 'documentation-plugin' ); } /* Restore original Post Data */ wp_reset_postdata(); return rest_ensure_response( $response ); }

และขอ create_custom_documentation_endpoint() กับเบ็ด rest_api_init ดังนี้:

 add_action( 'rest_api_init', [ $documentation, 'create_custom_documentation_endpoint' ] );

สิ่งนี้จะเพิ่มเส้นทางที่กำหนดเองใน https://dev.wordpress.test/wp-json/documentation-plugin/v1/custom-documentation ด้วยการโทรกลับที่ส่งคืนการตอบกลับสำหรับเส้นทางนั้น

 [{ "title": "Another test documentation", "tags": ["Another tag"] }, { "title": "Test documentation", "tags": ["REST API", "test tag"] }]

มีหลายสิ่งที่คุณทำได้ด้วย REST API (ดูรายละเอียดเพิ่มเติมได้ในคู่มือ REST API)

หลีกเลี่ยงเวลาตอบสนองที่ยาวนานเมื่อใช้ REST API . เริ่มต้น

สำหรับใครก็ตามที่พยายามสร้างไซต์ WordPress แบบแยกส่วน นี่ไม่ใช่สิ่งใหม่ — REST API นั้นช้า

ทีมของฉันและฉันพบ REST API ที่ล้าหลัง WordPress แบบแปลกๆ บนเว็บไซต์ไคลเอนต์ (ไม่แยกส่วน) ซึ่งเราใช้ปลายทางที่กำหนดเองเพื่อรับรายการตำแหน่งบนแผนที่ Google ควบคู่ไปกับข้อมูลเมตาอื่น ๆ ที่สร้างขึ้นโดยใช้ Advanced Custom Fields Pro เสียบเข้าไป. ปรากฎว่าเวลาที่ไบต์แรก (TTFB) ซึ่งใช้เป็นตัวบ่งชี้การตอบสนองของเว็บเซิร์ฟเวอร์หรือทรัพยากรเครือข่ายอื่น ๆ ใช้เวลานานกว่า 3 วินาที

หลังจากตรวจสอบเพียงเล็กน้อย เราก็รู้ว่าการเรียก REST API เริ่มต้นนั้นช้าจริงๆ โดยเฉพาะอย่างยิ่งเมื่อเรา "สร้างภาระ" ให้กับไซต์ด้วยปลั๊กอินเพิ่มเติม ดังนั้นเราจึงทำการทดสอบเล็กน้อย เราติดตั้งปลั๊กอินยอดนิยมสองสามตัวและพบผลลัพธ์ที่น่าสนใจ แอปบุรุษไปรษณีย์ให้เวลาในการโหลด 1.97 วินาทีสำหรับขนาดการตอบสนอง 41.9KB เวลาในการโหลดของ Chrome คือ 1.25 วินาที (TTFB คือ 1.25 วินาที ดาวน์โหลดเนื้อหาใน 3.96 มิลลิวินาที) เพียงเพื่อเรียกค้นรายการโพสต์ง่ายๆ ไม่มีการจัดหมวดหมู่ ไม่มีข้อมูลผู้ใช้ ไม่มีฟิลด์เมตาเพิ่มเติม

ทำไมสิ่งนี้จึงเกิดขึ้น?

ปรากฎว่าการเข้าถึง REST API บน WordPress เริ่มต้นจะโหลดคอร์ WordPress ทั้งหมดเพื่อให้บริการปลายทาง แม้ว่าจะไม่ได้ใช้งานก็ตาม ยิ่งคุณเพิ่มปลั๊กอินมากเท่าไหร่ ก็ยิ่งมีสิ่งเลวร้ายเท่านั้น ตัวควบคุม REST เริ่มต้น WP_REST_Controller เป็นคลาสที่ใหญ่มาก ซึ่งทำมากกว่าที่จำเป็นเมื่อสร้างหน้าเว็บธรรมดาๆ จัดการการลงทะเบียนเส้นทาง การตรวจสอบสิทธิ์ การสร้างและการลบรายการ และอื่นๆ

มีวิธีแก้ปัญหาทั่วไปสองวิธีสำหรับปัญหานี้:

  1. สกัดกั้นการโหลดปลั๊กอิน และป้องกันการโหลดทั้งหมดเมื่อคุณต้องการตอบสนอง REST อย่างง่าย
  2. โหลดเฉพาะ WordPress ขั้นต่ำและจัดเก็บข้อมูลชั่วคราว จากนั้นเราจะดึงข้อมูลโดยใช้หน้าที่กำหนดเอง

การปรับปรุงประสิทธิภาพด้วยแนวทาง JSON แบบแยกส่วน

เมื่อคุณทำงานกับไซต์การนำเสนอทั่วไป คุณไม่จำเป็นต้องมีฟังก์ชัน REST API ทั้งหมดที่เสนอให้คุณ แน่นอนว่าการวางแผนที่ดีเป็นสิ่งสำคัญ คุณคงไม่อยากสร้างไซต์ของคุณโดยไม่มี REST API จริงๆ แล้วจากนั้นก็พูดในอีกหลายปีว่าคุณต้องการเชื่อมต่อกับไซต์ของคุณ หรืออาจสร้างแอปบนอุปกรณ์เคลื่อนที่ที่ต้องใช้ฟังก์ชัน REST API คุณล่ะ?

ด้วยเหตุผลดังกล่าว เราจึงใช้คุณสมบัติ WordPress สองอย่างที่สามารถช่วยคุณได้เมื่อให้บริการข้อมูล JSON อย่างง่าย:

  • API ชั่วคราวสำหรับการแคช
  • กำลังโหลด WordPress ขั้นต่ำที่จำเป็นโดยใช้ค่าคงที่ SHORTINIT

การสร้างจุดสิ้นสุดหน้าแบบแยกส่วนอย่างง่าย

มาสร้างปลั๊กอินขนาดเล็กที่จะแสดงผลที่เรากำลังพูดถึงกัน ขั้นแรก เพิ่ม ไฟล์ wp-config-simple.php ในปลั๊กอิน json-transient ที่มีลักษณะดังนี้:

 <?php /** * Create simple wp configuration for the routes * * @since 1.0.0 * @package json-transient */ define( 'SHORTINIT', true ); $parse_uri = explode( 'wp-content', $_SERVER['SCRIPT_FILENAME'] ); require_once filter_var( $parse_uri[0] . 'wp-load.php', FILTER_SANITIZE_STRING );

การ define( 'SHORTINIT', true ); จะป้องกันไม่ให้โหลดไฟล์หลักของ WordPress ส่วนใหญ่ ดังที่เห็นใน ไฟล์ wp-settings.php

เรายังอาจต้องการฟังก์ชันบางอย่างของ WordPress ดังนั้นเราจึงต้องการไฟล์ (เช่น wp-load.php ) ด้วยตนเอง เนื่องจาก wp-load.php อยู่ในรูทของการติดตั้ง WordPress ของเรา เราจะดึงมันมาโดยรับพาธของไฟล์โดยใช้ $_SERVER['SCRIPT_FILENAME'] แล้วระเบิดสตริงนั้นด้วยสตริง wp-content สิ่งนี้จะส่งคืนอาร์เรย์ที่มีค่าสองค่า:

  1. รากของการติดตั้งของเรา
  2. เส้นทางไฟล์ที่เหลือ (ซึ่งเราไม่สนใจ)

โปรดทราบว่าเรากำลังใช้การติดตั้งเริ่มต้นของ WordPress และไม่ใช่การติดตั้งแบบแก้ไข เช่นในต้นแบบ Bedrock ซึ่งแยก WordPress ออกเป็นไฟล์อื่น

สุดท้ายนี้ เราต้องการ ไฟล์ wp-load.php พร้อมการฆ่าเชื้อเล็กน้อย เพื่อความปลอดภัย

ในไฟล์ init.php เราจะเพิ่มข้อมูลต่อไปนี้:

* Author URI: https://infinum.co/ * License: GPL-2.0+ * License URI: https://www.gnu.org/licenses/gpl-2.0.txt * Text Domain: json-transient */ namespace Json_Transient; // If this file is called directly, abort. if ( ! defined( 'WPINC' ) ) { die; } class Init { /** * Get the array of allowed types to do operations on. * * @return array * * @since 1.0.0 */ public function get_allowed_post_types() { return array( 'post', 'page' ); } /** * Check if post type is allowed to be save in transient. * * @param string $post_type Get post type. * @return boolean * * @since 1.0.0 */ public function is_post_type_allowed_to_save( $post_type = null ) { if( ! $post_type ) { return false; } $allowed_types = $this->get_allowed_post_types(); if ( in_array( $post_type, $allowed_types, true ) ) { return true; } return false; } /** * Get Page cache name for transient by post slug and type. * * @param string $post_slug Page Slug to save. * @param string $post_type Page Type to save. * @return string * * @since 1.0.0 */ public function get_page_cache_name_by_slug( $post_slug = null, $post_type = null ) { if( ! $post_slug || ! $post_type ) { return false; } $post_slug = str_replace( '__trashed', '', $post_slug ); return 'jt_data_' . $post_type . '_' . $post_slug; } /** * Get full post data by post slug and type. * * @param string $post_slug Page Slug to do Query by. * @param string $post_type Page Type to do Query by. * @return array * * @since 1.0.0 */ public function get_page_data_by_slug( $post_slug = null, $post_type = null ) { if( ! $post_slug || ! $post_type ) { return false; } $page_output = ''; $args = array( 'name' => $post_slug, 'post_type' => $post_type, 'posts_per_page' => 1, 'no_found_rows' => true ); $the_query = new \WP_Query( $args ); if ( $the_query->have_posts() ) { while ( $the_query->have_posts() ) { $the_query->the_post(); $page_output = $the_query->post; } wp_reset_postdata(); } return $page_output; } /** * Return Page in JSON format * * @param string $post_slug Page Slug. * @param string $post_type Page Type. * @return json * * @since 1.0.0 */ public function get_json_page( $post_slug = null, $post_type = null ) { if( ! $post_slug || ! $post_type ) { return false; } return wp_json_encode( $this->get_page_data_by_slug( $post_slug, $post_type ) ); } /** * Update Page to transient for caching on action hooks save_post. * * @param int $post_id Saved Post ID provided by action hook. * * @since 1.0.0 */ public function update_page_transient( $post_id ) { $post_status = get_post_status( $post_id ); $post = get_post( $post_id ); $post_slug = $post->post_name; $post_type = $post->post_type; $cache_name = $this->get_page_cache_name_by_slug( $post_slug, $post_type ); if( ! $cache_name ) { return false; } if( $post_status === 'auto-draft' || $post_status === 'inherit' ) { return false; } else if( $post_status === 'trash' ) { delete_transient( $cache_name ); } else { if( $this->is_post_type_allowed_to_save( $post_type ) ) { $cache = $this->get_json_page( $post_slug, $post_type ); set_transient( $cache_name, $cache, 0 ); } } } } $init = new Init(); add_action( 'save_post', [ $init, 'update_page_transient' ] );

วิธีการของตัวช่วยในโค้ดด้านบนจะช่วยให้เราสามารถทำการแคชได้:

  • get_allowed_post_types()
    วิธีนี้ช่วยให้ประเภทโพสต์ทราบว่าเราต้องการเปิดใช้งานการแสดงใน 'ปลายทาง' แบบกำหนดเองของเรา คุณสามารถขยายสิ่งนี้ได้ และปลั๊กอินที่เราได้ทำให้วิธีนี้สามารถกรองได้จริง ๆ เพื่อให้คุณสามารถใช้ตัวกรองเพื่อเพิ่มรายการเพิ่มเติมได้
  • is_post_type_allowed_to_save()
    วิธีนี้จะตรวจสอบง่ายๆ ว่าประเภทโพสต์ที่เราพยายามดึงข้อมูลนั้นอยู่ในอาร์เรย์ที่อนุญาตซึ่งระบุโดยวิธีก่อนหน้าหรือไม่
  • get_page_cache_name_by_slug()
    เมธอดนี้จะส่งคืนชื่อของทรานเซียนท์ที่จะดึงข้อมูลออกมา
  • get_page_data_by_slug()
    เมธอดนี้เป็นวิธีที่จะดำเนินการ WP_Query บนโพสต์ผ่านประเภทกระสุนและโพสต์และส่งคืนเนื้อหาของอาร์เรย์โพสต์ที่เราจะแปลงด้วย JSON โดยใช้ get_json_page()
  • update_page_transient()
    สิ่งนี้จะทำงานบน save_post และจะเขียนทับชั่วคราวในฐานข้อมูลด้วยข้อมูล JSON ของโพสต์ของเรา วิธีสุดท้ายนี้เรียกว่า "วิธีการแคชคีย์"

มาอธิบายเรื่องชั่วคราวในเชิงลึกกันดีกว่า

API ชั่วคราว

Transients API ใช้เพื่อเก็บข้อมูลในตารางตัวเลือกของฐานข้อมูล WordPress ของคุณในช่วงระยะเวลาหนึ่ง เป็นแคชออบเจ็กต์ที่คงอยู่ ซึ่งหมายความว่าคุณกำลังจัดเก็บออบเจ็กต์บางอย่าง เช่น ผลลัพธ์ของข้อความค้นหาขนาดใหญ่และช้า หรือหน้าเต็มที่สามารถคงอยู่ในการโหลดหน้าเว็บ คล้ายกับ WordPress Object Cache ปกติ แต่ต่างจาก WP_Cache ชั่วคราวจะคงข้อมูลในการโหลดหน้าเว็บ โดยที่ WP_Cache (จัดเก็บข้อมูลในหน่วยความจำ) จะเก็บข้อมูลไว้ในช่วงระยะเวลาของคำขอเท่านั้น

เป็นที่เก็บคีย์-ค่า ซึ่งหมายความว่าเราสามารถดึงข้อมูลที่ต้องการได้อย่างง่ายดายและรวดเร็ว คล้ายกับที่ in-memory caching systems เช่น Memcached หรือ Redis ทำ ข้อแตกต่างคือโดยปกติคุณจะต้องติดตั้งแยกต่างหากบนเซิร์ฟเวอร์ (ซึ่งอาจเป็นปัญหาบนเซิร์ฟเวอร์ที่ใช้ร่วมกัน) ในขณะที่ WordPress สร้างขึ้นชั่วคราว

ตามที่ระบุไว้ในหน้า Codex — ชั่วครู่จะถูกเร่งความเร็วโดยเนื้อแท้โดยการแคชปลั๊กอิน เนื่องจากสามารถจัดเก็บชั่วคราวในหน่วยความจำแทนฐานข้อมูล กฎทั่วไปคือ คุณไม่ควรทึกทักเอาเองว่าชั่วครู่มีอยู่ในฐานข้อมูลเสมอ — ซึ่งเป็นเหตุผลว่าทำไมจึงควรตรวจสอบการมีอยู่ของมันก่อนที่จะดึงข้อมูล

 $transient_name = get_transient( 'transient_name' ); if ( $transient_name === false ) { set_transient( 'transient_name', $transient_data, $transient_expiry ); }

คุณสามารถใช้มันได้โดยไม่หมดอายุ (เหมือนที่เราทำอยู่) และนั่นเป็นเหตุผลที่เราใช้การ 'ป้องกันแคช' ในการบันทึกโพสต์ นอกเหนือจากฟังก์ชันการทำงานที่ยอดเยี่ยมทั้งหมดที่มีให้แล้ว ยังสามารถเก็บข้อมูลได้ถึง 4GB แต่เราไม่แนะนำให้จัดเก็บข้อมูลขนาดใหญ่ในฟิลด์ฐานข้อมูลเดียว

การอ่านที่แนะนำ : ระวังให้ดี: ฟังก์ชัน PHP และ WordPress ที่สามารถทำให้ไซต์ของคุณไม่ปลอดภัย

ปลายทางสุดท้าย: การทดสอบและการตรวจสอบ

จิ๊กซอว์ชิ้นสุดท้ายที่เราต้องการคือ 'จุดสิ้นสุด' ฉันกำลังใช้คำว่า endpoint ที่นี่ แม้ว่าจะไม่ใช่จุดสิ้นสุด เนื่องจากเรากำลังเรียกไฟล์เฉพาะเพื่อดึงผลลัพธ์ของเราโดยตรง ดังนั้นเราจึงสามารถสร้างไฟล์ test.php ที่มีลักษณะดังนี้:

 get_page_cache_name_by_slug( $post_slug, $post_type ) ); // Return error on false. if ( $cache === false ) { wp_send_json( 'Error, the page does not exist or it is not cached correctly. Please try rebuilding cache and try again!' ); } // Decode json for output. wp_send_json( json_decode( $cache ) );

ถ้าเราไปที่ https://dev.wordpress.test/wp-content/plugins/json-transient/test.php เราจะเห็นข้อความนี้:

เกิดข้อผิดพลาด กระสุนหน้าหรือประเภทหายไป!

ดังนั้น เราจะต้องระบุประเภทโพสต์และทากของโพสต์ เมื่อเราไปที่ https://dev.wordpress.test/wp-content/plugins/json-transient/test.php?slug=hello-world&type=post เราจะเห็น:

เกิดข้อผิดพลาด หน้าไม่มีอยู่หรือไม่ได้แคชไว้อย่างถูกต้อง โปรดลองสร้างแคชใหม่และลองอีกครั้ง!

โอ้รอ! เราต้องบันทึกหน้าและโพสต์ของเราอีกครั้งก่อน ดังนั้นเมื่อคุณเริ่มต้น สิ่งนี้อาจเป็นเรื่องง่าย แต่ถ้าคุณมีเพจหรือโพสต์มากกว่า 100+ เพจ นี่อาจเป็นงานที่ท้าทาย นี่คือเหตุผลที่เราใช้วิธีการล้างข้อมูลชั่วคราวในปลั๊กอินเนื้อหา JSON แบบแยกส่วน และสร้างใหม่เป็นกลุ่ม

แต่ให้บันทึกโพสต์ Hello World ใหม่ จากนั้นเปิดลิงก์อีกครั้ง สิ่งที่คุณควรมีในตอนนี้คือบางสิ่งที่มีลักษณะดังนี้:

 { "ID": 1, "post_author": "1", "post_date": "2018-06-26 18:28:57", "post_date_gmt": "2018-06-26 18:28:57", "post_content": "Welcome to WordPress. This is your first post. Edit or delete it, then start writing!", "post_title": "Hello world!", "post_excerpt": "", "post_status": "publish", "comment_status": "open", "ping_status": "open", "post_password": "", "post_name": "hello-world", "to_ping": "", "pinged": "", "post_modified": "2018-06-30 08:34:52", "post_modified_gmt": "2018-06-30 08:34:52", "post_content_filtered": "", "post_parent": 0, "guid": "http:\/\/dev.wordpress.test\/?p=1", "menu_order": 0, "post_type": "post", "post_mime_type": "", "comment_count": "1", "filter": "raw" }

และนั่นแหล่ะ ปลั๊กอินที่เราทำขึ้นมีฟังก์ชันพิเศษบางอย่างที่คุณสามารถใช้ได้ แต่โดยสรุป นี่คือวิธีที่คุณสามารถดึงข้อมูล JSON จาก WordPress ของคุณได้เร็วกว่าการใช้ REST API

ก่อนและหลัง: ปรับปรุงเวลาตอบสนอง

เราทำการทดสอบใน Chrome ซึ่งเราสามารถเห็นเวลาตอบสนองทั้งหมดและ TTFB แยกกัน เราทดสอบการตอบสนอง 10 ครั้งติดต่อกัน โดยเริ่มจากไม่มีปลั๊กอิน และจากนั้นเพิ่มปลั๊กอินเข้าไป นอกจากนี้ เราได้ทดสอบการตอบกลับสำหรับรายการโพสต์และสำหรับโพสต์เดียว

ผลการทดสอบแสดงไว้ในตารางด้านล่าง:

กราฟเปรียบเทียบแสดงเวลาตอบสนองของการใช้ WordPress REST API เทียบกับการใช้วิธีการแยกส่วนโดยไม่ต้องเพิ่มปลั๊กอิน วิธีแยกส่วนเร็วกว่า 2 ถึง 3 เท่า
กราฟเปรียบเทียบแสดงเวลาตอบสนองของการใช้ WordPress REST API เทียบกับการใช้วิธีการแยกส่วนโดยไม่ต้องเพิ่มปลั๊กอิน วิธีแยกส่วนเร็วขึ้น 2 ถึง 3 เท่า (ตัวอย่างขนาดใหญ่)
กราฟเปรียบเทียบแสดงเวลาตอบสนองของการใช้ WordPress REST API เทียบกับการใช้วิธีการแยกส่วนที่มีปลั๊กอินเพิ่มเติม วิธีการแยกส่วนนั้นเร็วขึ้นถึง 8 เท่า
กราฟเปรียบเทียบแสดงเวลาตอบสนองของการใช้ WordPress REST API เทียบกับการใช้วิธีการแยกส่วนที่มีปลั๊กอินเพิ่มเติม วิธีการแยกส่วนนั้นเร็วขึ้นถึง 8 เท่า (ตัวอย่างขนาดใหญ่)

อย่างที่คุณเห็น ความแตกต่างนั้นรุนแรงมาก

ความกังวลด้านความปลอดภัย

มีข้อแม้บางประการที่คุณจะต้องพิจารณาให้ดี ก่อนอื่น เรากำลังโหลดไฟล์หลักของ WordPress ด้วยตนเอง ซึ่งในโลกของ WordPress นั้นไม่ใช่เรื่องใหญ่อะไร ทำไม? นอกจากความจริงที่ว่าการดึงไฟล์หลักด้วยตนเองอาจเป็นเรื่องยาก (โดยเฉพาะอย่างยิ่งหากคุณใช้การติดตั้งที่ไม่ได้มาตรฐานเช่น Bedrock) ก็อาจทำให้เกิดปัญหาด้านความปลอดภัยได้

หากคุณตัดสินใจใช้วิธีการที่อธิบายไว้ในบทความนี้ คุณต้องรู้วิธีเพิ่มความปลอดภัยให้กับเซิร์ฟเวอร์ของคุณ

ขั้นแรก เพิ่มส่วนหัว HTML เช่นเดียวกับในไฟล์ test.php :

 header( 'Access-Control-Allow-Origin: your-front-end-app.url' ); header( 'Content-Type: application/json' );

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

ประการที่สอง ปิดใช้งานการข้ามผ่านไดเรกทอรีของแอปของคุณ คุณสามารถทำได้โดยแก้ไขการตั้งค่า nginx หรือเพิ่ม Options -Indexes ให้กับไฟล์ . htaccess ของคุณ หากคุณใช้เซิร์ฟเวอร์ Apache

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

การตรวจสอบส่วนหัวการให้สิทธิ์ที่ส่งโดยแอปส่วนหน้าอาจมีลักษณะดังนี้:

 if ( ! isset( $_SERVER['HTTP_AUTHORIZATION'] ) ) { return; } $auth_header = $_SERVER['HTTP_AUTHORIZATION'];

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

บทสรุป

REST API นั้นยอดเยี่ยมเพราะสามารถใช้เพื่อสร้างแอปที่ครบครัน — การสร้าง ดึงข้อมูล อัปเดต และลบข้อมูล ข้อเสียของการใช้มันคือความเร็วของมัน

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

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

วิธีการที่อธิบายไว้ในบทความนี้ช่วยแก้ปัญหาความเร็วที่ WordPress REST API พบ และจะช่วยเพิ่มพลังให้คุณเป็นพิเศษเมื่อทำงานในโครงการ WordPress ที่แยกส่วน ในขณะที่เราอยู่ในภารกิจที่ไม่มีวันสิ้นสุดในการบีบมิลลิวินาทีสุดท้ายออกจากทุกคำขอและการตอบสนอง เราวางแผนที่จะเพิ่มประสิทธิภาพปลั๊กอินให้ดียิ่งขึ้นไปอีก ในระหว่างนี้ โปรดแบ่งปันความคิดของคุณในการเร่งความเร็ว WordPress แบบแยกส่วน!