ส่วนที่ 5 – WordPress และการเขียนโปรแกรมเชิงวัตถุ: ตัวอย่าง WordPress – การนำไปใช้: เมนูการดูแลระบบ
เผยแพร่แล้ว: 2022-02-04ในบทความก่อนหน้าของเราเกี่ยวกับ Object Oriented Programming เราได้พูดถึงการออกแบบที่เราคิดขึ้นมาในที่สุดสำหรับปลั๊กอินเชิงวัตถุของเรา
ตอนนี้ เราจะเข้าสู่ส่วนที่น่าตื่นเต้นที่สุด โดยเราจะเจาะลึกลงไปถึงวิธีที่เราใช้งานมัน!
เราจะแนะนำคุณเกี่ยวกับบางส่วนของการใช้งาน ทีละขั้นตอน พูดคุยเกี่ยวกับพื้นฐานของการเขียนโปรแกรมเชิงวัตถุ ไวยากรณ์ PHP แนวคิดหลักบางส่วน และเราจะพิจารณาถึงหลักการ SOLID
ในตอนท้ายของบทความนี้ หวังว่าคุณจะมีความเข้าใจ OOP ดีขึ้น และตื่นเต้นกับการเขียนปลั๊กอินเชิงวัตถุของคุณเอง!
เริ่มต้น
เราคิดว่าคุณคุ้นเคยกับการพัฒนาปลั๊กอิน WordPress โดยทั่วไป ดังนั้นเราจะเน้นที่แง่มุมเชิงวัตถุของปลั๊กอินของเรา หากคุณเพิ่งเริ่มพัฒนาปลั๊กอินหรือต้องการทบทวน คุณควรเรียนรู้วิธีสร้างปลั๊กอิน WordPress ตัวแรกของคุณก่อน
มาเริ่มกันเลยเหมือนที่เคยทำ โดยการสร้างไฟล์ prsdm-limit-login-attempts.php ใหม่ ภายใต้ไดเร็กทอรีปลั๊กอินของเรา (เช่น /wp-content/plugins/prsdm-limit-login-attempts)
ไฟล์ปลั๊กอินหลักจะรวมส่วนหัวของปลั๊กอินที่คุณคุ้นเคยอยู่แล้ว:
/** * Plugin Name: PRSDM Limit Login Attempts * Plugin URI: https://pressidium.com * Description: Limit rate of login attempts, including by way of cookies, for each IP. * Author: Pressidium * Author URI: https://pressidium.com * Text Domain: prsdm-limit-login-attempts * License: GPL-2.0+ * Version: 1.0.0 */
และคำสั่ง if แบบง่ายเพื่อป้องกันการเข้าถึงโดยตรง
if ( ! defined( 'ABSPATH' ) ) { exit; }
นั่นคือทั้งหมดที่เราต้องการในตอนนี้ เราจะกลับมาตรวจสอบไฟล์นี้อีกครั้งในภายหลัง!
การสร้างเมนูการบริหาร
เมื่อคุณกำลังพัฒนาปลั๊กอิน คุณมักจะต้องจัดเตรียมวิธีกำหนดค่าให้กับผู้ใช้ของคุณ นั่นคือที่มาของหน้าการตั้งค่า ในการสร้างหน้าเราจะเพิ่มเมนูการดูแลระบบที่ใช้ WordPress Settings API
ดังนั้น มาเริ่มคิดว่า API เชิงวัตถุ ของเราจะมีลักษณะอย่างไร
ตามหลักการแล้ว เราต้องการยกตัวอย่าง Pressidium_LLA_Settings_Page
ของเราและดำเนินการให้เสร็จสิ้น ในการสร้างอินสแตนซ์ของคลาส ต้องใช้คีย์เวิร์ด new
new Pressidium_LLA_Settings_Page();
ตอนนี้ ลองคิดดูว่าคลาส Pressidium_LLA_Settings_Page
ของเราจะหน้าตาเป็นอย่างไร
เราจะเริ่มต้นด้วยการสร้างคลาสใหม่โดยใช้คีย์เวิร์ดของ class
:
class Pressidium_LLA_Settings_Page {}
ชื่อคลาสของเราจะต้องนำหน้าด้วยตัวระบุที่ไม่ซ้ำกัน Pressidium_LLA_
เพื่อป้องกันการชนกันของการตั้งชื่อกับปลั๊กอิน WordPress อื่น ๆ คำนำหน้าป้องกันปลั๊กอินอื่น ๆ จากการเขียนทับและ/หรือเรียกชั้นเรียนของเราโดยไม่ได้ตั้งใจ ตราบใดที่ชื่อคลาสของเราไม่ซ้ำกัน—หรือเราใช้เนมสเปซ— จะไม่มีข้อขัดแย้งใดๆ กับปลั๊กอินอื่นๆ
ตัวสร้าง
ตอนนี้ เราจะขอเข้าสู่ admin_menu และ admin_init เพื่อให้ง่ายขึ้น เราจะเรียก add_action() ในตัวสร้างของเรา (การแจ้งเตือนสปอยเลอร์: เราจะเปลี่ยนแปลงในภายหลัง)
class Pressidium_LLA_Settings_Page { /** * Settings_Page constructor. */ public function __construct() { add_action( 'admin_menu', array( $this, 'add_page' ) ); add_action( 'admin_init', array( $this, 'register_sections' ) ); } }
คลาสที่มีคอนสตรัคเตอร์ ให้เรียกเมธอดนี้เมื่ออ็อบเจ็กต์ได้รับอินสแตนซ์ ดังนั้น __construct()
วิธีการจึงยอดเยี่ยมสำหรับการเริ่มต้นใดๆ ที่เราอาจต้องการดำเนินการ
มาดูการ add_action()
ของเราให้ละเอียดยิ่งขึ้น หากคุณเคยพัฒนาปลั๊กอิน WordPress มาก่อน คุณอาจคาดหวังสิ่งนี้:
add_action( 'admin_menu', 'my_plugin_prefix_add_page' );
แต่เรามี:
add_action( 'admin_menu', array( $this, 'add_page' ) );
คุณอาจสับสนเกี่ยวกับการใช้อาร์เรย์ที่นี่ เมื่อใดก็ตามที่เราต้องการส่งเมธอดของอ็อบเจ็กต์ที่สร้างอินสแตนซ์เป็น callback/callable เราสามารถใช้อาร์เรย์ที่มีอ็อบเจ็กต์ที่ดัชนี 0 และชื่อเมธอดที่ดัชนี 1
$นี้คืออะไร?
เป็นตัวแปรเทียมที่พร้อมใช้งานเมื่อมีการเรียกเมธอดจากภายในบริบทของอ็อบเจ็กต์ $this
คือค่าของวัตถุที่เรียก ในกรณีนี้ $this
คือตัวอย่างของ Pressidium_LLA_Settings_Page
นอกจากนี้ “ฟังก์ชัน” ทั้งหมดของเรายังเป็นเมธอด รวมอยู่ในคลาส ดังนั้นจึงไม่จำเป็นต้องเติมชื่อเมธอดของเรานำหน้า
เนมสเปซ
เนมสเปซใน PHP ช่วยให้เราสามารถจัดกลุ่มคลาสที่เกี่ยวข้อง อินเทอร์เฟซ ฟังก์ชัน ฯลฯ ป้องกันการชนกันของการตั้งชื่อระหว่างโค้ดของเรา และ PHP ภายในหรือคลาส/ฟังก์ชันของบุคคลที่สาม
มาใช้กันเลยดีกว่า ดังนั้นเราจึงไม่ต้องนำหน้าชั้นเรียนของเราไปข้างหน้า
เราจะประกาศเนมสเปซโดยใช้คีย์เวิร์ด namespace
namespace Pressidium;
เนมสเปซสามารถกำหนดได้ด้วยระดับย่อย
namespace Pressidium\Limit_Login_Attempts;
เนื่องจากเรากำลังสร้างหน้าการตั้งค่า เราจะประกาศเนมสเปซย่อย "หน้า" เพื่อจัดกลุ่มสิ่งที่เกี่ยวข้องกับหน้าการดูแลระบบเข้าด้วยกัน
namespace Pressidium\Limit_Login_Attempts\Pages;
ในที่สุด เราก็สามารถกำจัดคำนำหน้า Pressidium_LLA_
!
namespace Pressidium\Limit_Login_Attempts\Pages; class Settings_Page { // ...
ปลั๊กอิน WordPress อื่นที่มีคลาส Settings_Page
ไม่ใช่ปัญหาอีกต่อไป เนื่องจากคลาสและคลาสของเราจะไม่อยู่ในเนมสเปซเดียวกัน
เมื่อสร้างอินสแตนซ์ Settings_Page
ของเราในเนมสเปซเดียวกัน เราสามารถละเว้นได้:
namespace Pressidium\Limit_Login_Attempts\Pages; $settings_page = new Settings_Page();
เมื่อสร้างอินสแตนซ์ Settings_Page
ของเรานอกเนมสเปซ เราต้องระบุดังนี้:
namespace Another\Namespace; $settings_page = new \Pressidium\Limit_Login_Attempts\Pages\Settings_Page();
อีกทางหนึ่ง เราสามารถนำเข้าคลาสของเราด้วยตัวดำเนินการ use
:
use Pressidium\Limit_Login_Attempts\Pages\Settings_Page; $settings_page = new Settings_Page();
การเพิ่ม Hook Callbacks
ตอนนี้ เรามาประกาศ add_page()
และ register_sections()
เหล่านี้กัน
class Settings_Page { /** * Settings_Page constructor. */ public function __construct() { add_action( 'admin_menu', array( $this, 'add_page' ) ); add_action( 'admin_init', array( $this, 'register_sections' ) ); } /** * Add this page as a top-level menu page. */ public function add_page() { // TODO: Implement this method. } /** * Register sections. */ public function register_sections() { // TODO: Implement this method. } }
วิธีการ add_page() ของเราจะเรียกใช้ฟังก์ชัน add_menu_page() ของ WordPress
public function add_page() { add_menu_page( __( 'Limit Login Attempts Settings', 'prsdm-limit-login-attempts' ), __( 'Limit Login Attempts', 'prsdm-limit-login-attempts' ), 'manage_options', 'prsdm_limit_login_attempts_settings', array( $this, 'render' ), 'dashicons-shield-alt', null ); }
ดูเหมือนจะเป็นวิธีที่ซับซ้อนในการพัฒนาปลั๊กอิน WordPress เป็นการเรียกฟังก์ชันของ WordPress ด้วยขั้นตอนเพิ่มเติม
นั่นไม่ใช่ "นำมาใช้ใหม่" ได้อย่างแน่นอน เรายังคงต้องเขียนโค้ดพิเศษทั้งหมดนี้สำหรับทุกเมนู/หน้าการดูแลระบบที่เราต้องการเพิ่ม
การปรับโครงสร้างใหม่
ไปข้างหน้าและจัดองค์ประกอบโค้ดของเราใหม่เล็กน้อยเพื่อใช้ประโยชน์จากการเขียนโปรแกรมเชิงวัตถุและทำให้โค้ดของเรา นำกลับมาใช้ใหม่ ได้ เราจะเริ่มต้นด้วยการแทนที่ค่าฮาร์ดโค้ดของเราใน add_page()
ด้วยวิธีการสองสามวิธี เช่น:
public function add_page() { add_menu_page( $this->get_page_title(), // page_title $this->get_menu_title(), // menu_title $this->get_capability(), // capability $this->get_slug(), // menu_slug array( $this, 'render' ), // callback function $this->get_icon_url(), // icon_url $this->get_position() // position ); }
เราจะกำหนดเมธอดเหล่านี้ว่า protected
เพื่อให้สามารถเข้าถึงได้ภายในคลาสเองและโดยคลาสย่อย/พาเรนต์เท่านั้น
protected function get_page_title() { /* ... */ } protected function get_menu_title() { /* ... */ } protected function get_capability() { /* ... */ } protected function get_slug() { /* ... */ } protected function get_icon_url() { /* ... */ } protected function get_position() { /* ... */ }
ยอดเยี่ยม! ตอนนี้เราสามารถใช้คลาสนี้เป็นคลาสทั่วไปที่ใช้ซ้ำได้เพื่อขยายจาก
การออกแบบใหม่
เราบอกคุณแล้วว่าสิ่งนี้อาจเกิดขึ้นในที่สุด เรากำลังคิดใหม่เกี่ยวกับการออกแบบชั้นเรียนของเราขณะสร้างชั้นเรียน
เนื่องจากนี่จะเป็น คลาสพื้นฐาน ของเรา เราจะเปลี่ยนชื่อเป็นชื่อทั่วไป เช่น Admin_Page
จนถึงตอนนี้ดูเหมือนว่า:
class Admin_Page { /** * Admin_Page constructor. */ public function __construct() { add_action( 'admin_menu', array( $this, 'add_page' ) ); add_action( 'admin_init', array( $this, 'register_sections' ) ); } /** * Add this page as a top-level menu page. */ public function add_page() { add_menu_page( $this->get_page_title(), // page_title $this->get_menu_title(), // menu_title $this->get_capability(), // capability $this->get_slug(), // menu_slug array( $this, 'render' ), // callback function $this->get_icon_url(), // icon_url $this->get_position() // position ); } /** * Register sections. */ public function register_sections() { // TODO: Implement this method. } protected function get_page_title() { /* ... */ } protected function get_menu_title() { /* ... */ } protected function get_capability() { /* ... */ } protected function get_slug() { /* ... */ } protected function get_icon_url() { /* ... */ } protected function get_position() { /* ... */ } }
ตอนนี้ เราสามารถสร้าง Settings_Page
แยกกัน ซึ่ง ขยาย คลาสพื้นฐานของ Admin_Page
นั้น
class Settings_Page extends Admin_Page { // ... }
นั่นเป็นตัวอย่างที่ดีของ inheritance ซึ่งเป็นหนึ่งในแนวคิดหลักของการเขียนโปรแกรมเชิงวัตถุ เมื่อขยายคลาส คลาสย่อย— Settings_Page
ในกรณีนี้—รับช่วงต่อสาธารณะและเมธอด คุณสมบัติ และค่าคงที่ทั้งหมดที่ได้รับการป้องกันจากคลาสพาเรนต์
เราสามารถใช้ประโยชน์จากสิ่งนี้และตั้งค่าเริ่มต้นบางอย่างได้ ตัวอย่างเช่น เราจะตั้งค่าไอคอนทั่วไปสำหรับหน้าเมนูทั้งหมด โดยกำหนด get_icon_url()
ของเราดังนี้:
class Admin_Page { // ... /** * Return the menu icon to be used for this menu. * * @link https://developer.wordpress.org/resource/dashicons/ * * @return string */ protected function get_icon_url() { return 'dashicons-admin-generic'; } }
เว้นแต่คลาสจะแทนที่เมธอดเหล่านั้น พวกเขาจะคงฟังก์ชันเดิมไว้ ดังนั้น ตามค่าเริ่มต้น คลาสย่อยทั้งหมดจะใช้ไอคอนทั่วไปนั้น
อย่างไรก็ตาม หากเราต้องการตั้งค่าไอคอนอื่นสำหรับหน้าเมนูเฉพาะ เราสามารถ แทนที่ get_icon_url()
ในคลาสย่อยได้ดังนี้:
class Settings_Page extends Admin_Page { protected function get_icon_url() { return 'dashicons-shield-alt'; } }
มีค่าบางอย่างที่ต้องแตกต่างกันสำหรับแต่ละชั้นเรียนเด็ก ตัวอย่างเช่น กระสุนเมนู—อาร์กิวเมนต์ที่สี่ของ add_menu_page()
ควรจะไม่ซ้ำกันสำหรับแต่ละหน้าเมนู
หากเราจะกำหนดวิธีการนี้ในคลาสฐาน Admin_Page
ของเรา เราต้องการวิธีที่จะทำให้แน่ใจว่าคลาสย่อยทุกคลาสจะแทนที่เมธอดนี้ ดีเราสามารถทำสิ่งที่ดียิ่งขึ้น เราสามารถประกาศลายเซ็นของเมธอดและข้ามการดำเนินการไปโดยสิ้นเชิง
ป้อนวิธีการนามธรรม!
คลาสนามธรรมและวิธีการ
วิธีการที่กำหนดให้เป็น นามธรรม เพียงแค่ประกาศลายเซ็นของวิธีการและไม่สามารถกำหนดการใช้งานได้
/** * Return page slug. * * @return string */ abstract protected function get_slug();
คลาสใด ๆ ที่มีอย่างน้อยหนึ่งวิธีนามธรรม ต้อง เป็นนามธรรมด้วย นั่นหมายความว่า คลาส Admin_Page ของเราควรถูกกำหนดให้เป็นนามธรรมเช่นกัน
abstract class Admin_Page { // ...
สิ่งสำคัญคือต้องชี้ให้เห็นว่าคลาสที่กำหนดเป็นนามธรรมไม่สามารถสร้างอินสแตนซ์ได้ ดังนั้นเราจึงไม่สามารถสร้างอินสแตนซ์ Admin_Page
ได้โดยตรงอีกต่อไป
นี่คือการแสดงภาพของชั้นเรียนด้วย:
เมื่อสืบทอดจากคลาสนามธรรม คลาสย่อย ต้อง กำหนดวิธีการทั้งหมดที่ทำเครื่องหมายเป็นนามธรรมในการประกาศคลาสพาเรนต์ หมายความว่า Settings_Page
ของเราต้องใช้ get_slug()
class Settings_Page extends Admin_Page { // ... protected function get_slug() { return 'prsdm_limit_login_attempts_settings'; } // ... }
ในทำนองเดียวกัน เราควรใช้วิธีป้องกันที่เหลือตามที่ add_page()
ต้องการ
ก่อนดำเนินการต่อเกี่ยวกับวิธีการลงทะเบียนส่วนและฟิลด์ของหน้าผู้ดูแลระบบและแสดงเนื้อหา เรามาพูดถึงการตั้งค่าใน WordPress กันก่อน
การตั้งค่า API
เราจะถือว่าคุณคุ้นเคยกับ Settings API อยู่แล้ว แต่ในกรณีที่นี่คือส่วนสำคัญของมัน:
- settings_fields() — ส่งออกฟิลด์ nonce, action และ option_page สำหรับหน้าการตั้งค่า โดยทั่วไปฟิลด์แบบฟอร์มที่ซ่อนอยู่
- do_settings_sections() — พิมพ์ส่วนการตั้งค่าทั้งหมด (และฟิลด์) ที่เพิ่มไปยังหน้าการตั้งค่าเฉพาะ
- add_settings_section() — เพิ่มส่วนใหม่ในหน้าการตั้งค่า
- add_settings_field() — เพิ่มฟิลด์ใหม่ให้กับส่วนของหน้าการตั้งค่า
- register_setting() — ลงทะเบียนการตั้งค่าและข้อมูล
หากคุณไม่คุ้นเคยกับสิ่งนี้ คุณสามารถหยุดอ่านบทความนี้ชั่วคราว และดูบทความที่เกี่ยวข้องของเราเกี่ยวกับวิธีสร้างหน้าการตั้งค่าสำหรับปลั๊กอินที่กำหนดเอง
ตอนนี้เราอยู่ในหน้าเดียวกันแล้ว กลับไปที่เมธอด register_sections()
ของเรา เป็นอีกครั้งที่เราต้องย้อนกลับไปคิดเกี่ยวกับ API ของเรา
เนื่องจากเราได้กำหนด add_page()
ในคลาส Admin_Page
เราจะกำหนดเมธอด render()
ไว้ที่นั่นด้วย เราจะส่งคืนค่าของวิธีการอื่นๆ ของเราเป็นอาร์กิวเมนต์ไปยังฟังก์ชันของ WordPress
abstract class Admin_Page { // ... /** * Render this admin page. */ public function render() { ?> <div class="wrap"> <form action="options.php" method="post"> <h1><?php echo esc_html( $this->get_page_title() ); ?></h1> <?php settings_fields( $this->get_slug() ); do_settings_sections( $this->get_slug() ); submit_button( __( 'Change Options', 'prsdm-limit-login-attempts' ) ); ?> </form> </div> <?php } }
ด้วยวิธีนี้ เราจะไม่ต้องกังวลกับฟังก์ชัน WordPress เหล่านี้โดยตรงอีกต่อไป นั่นเป็นเพราะว่าหน้าผู้ดูแลระบบใด ๆ ที่เราอาจเพิ่มในอนาคตจะถูกสร้างขึ้นผ่านคลาสย่อยเช่นเดียวกับ Settings_Page
และการแสดงผลจะทำผ่านเมธอด render()
ที่สืบทอดมาของ Admin_Page
บทสรุป
ยอดเยี่ยม! เราได้สร้างคลาสที่รับผิดชอบในการลงทะเบียนเมนูการดูแลระบบและเพิ่มหน้าการตั้งค่า
ในบทความถัดไปของซีรีส์ เราจะสร้างหน้าการตั้งค่าต่อไปและลงทะเบียนส่วน ฟิลด์ และองค์ประกอบต่างๆ
คลิกที่นี่เพื่ออ่านตอนที่ 6 ใน Objected Oriented Programming Series
ดูสิ่งนี้ด้วย
- WordPress และการเขียนโปรแกรมเชิงวัตถุ – ภาพรวม
- ส่วนที่ 2 – การเขียนโปรแกรม WordPress และ Object Oriented: ตัวอย่างในโลกแห่งความจริง
- ส่วนที่ 3 – WordPress และการเขียนโปรแกรมเชิงวัตถุ: Α ตัวอย่าง WordPress – การกำหนดขอบเขต
- ส่วนที่ 4 – การเขียนโปรแกรม WordPress และ Object Oriented: ตัวอย่าง WordPress – การออกแบบ