У вчорашньому дописі я розповідав про конструктори плагінів WordPress і обґрунтування того, чому хуки не повинні бути в конструкторі.
Хоча я згадав кілька способів обробки реєстрації гаків, я не став вдаватися в деталі кожної з цих стратегій. Як на мене, вони заслуговують на окрему статтю, щоб надати якомога більше деталей про те, як щось налаштувати.
Наприклад, один із методів, якими я поділився:
- За допомогою WordPress можна створити клас, який підтримує реєстр об’єктів і хуків.
Іншими словами, мова йде про реєстрацію хуків WordPress за допомогою об’єктно-орієнтованого підходу для зменшення зв’язку та підвищення зв’язку між компонентами плагіна.
Але що це взагалі означає? Які переваги він приносить, як його налаштувати та як ним користуватися?
Реєстрація хуків WordPress
Якщо ви читаєте це, ви, ймовірно, знайомі з системою підключення WordPress, порядком їх запуску та тим, як функція або клас можуть зареєструвати свої функції в WordPress, щоб вони могли виконувати будь-яку роботу, яку вони потребують.
І ми часто бачимо, як класи роблять це самостійно. Залежно від проекту, роблю сам. Для тих, хто не знайомий, загалом це виглядає приблизно так :
<?php
add_action( 'plugins_loaded', 'acme_start' );
/**
* Start the machine.
* https://www.youtube.com/watch?v=ysoMOefPyRs
*/
function acme_start() {
$plugin = new AcmeColumn();
}
Але все це можна розбити на більш згуртовані класи, щоб зрештою дати їм ще менше відповідальності (хороша річ) і зменшити зв’язок між класом або набором класів із WordPress.
Приклад дизайну, який я розберу в цій публікації.
Однак суперечливий характер цього полягає в тому, що для цього знадобиться принаймні ще один клас. Але ось як це працює.
Налаштування
Для цілей цього прикладу ми будемо використовувати простий клас, який реєструватиме певний тип дії з WordPress. Ідея архітектури виглядає приблизно так:
- Є основний клас, який має функцію, яку ми хочемо підключити до WordPress.
- Існує клас, який відповідає за організацію підключення функції класу до WordPress.
Досить легко, чи не так? Але ось у чому заковика: клас, відповідальний за реєстрацію функцій даного класу в WordPress, є тим пунктом, який вимагає дизайнерського рішення.
По-перше, давайте викличемо клас HookRegistry, щоб ми могли посилатися на нього належним чином. Далі давайте викличемо клас із функціями, які ми хочемо підключити, AcmeColumn, щоб просто представити клас, який додає новий стовпець на панель інструментів сторінки в адміністративній області WordPress.
Після цього дизайнерське рішення зводиться до наступного:
- Чи повинен HookRegistery знати про AcmeColumn?
- Чи повинен AcmeColumn знати про HookRegistry?
Я знаю, що є інші способи організувати це, а також є стратегії, як це впоратися (наприклад, інверсія контролю ), і це теми, які варто вивчити, але щоб зберегти цю початкову ідею максимально простою, я наведу це для майбутній пост.
Використання класу
Враховуючи параметри вище, ми передамо екземпляр AcmeColumn у HookRegistry, коли екземпляри класів створюються під час початкового процесу запуску плагіна WordPress. Це може виглядати приблизно так :
<?php
add_action( 'plugins_loaded', 'acme_start' );
/**
* Start the machine.
* https://www.youtube.com/watch?v=ysoMOefPyRs
*/
function acme_start() {
$registry = new HookRegistry();
$acme_column = new AcmeColumn( $registry );
$acme_column->start();
}
Далі, коли настане час, щоб AcmeColumn зареєстрував свою функцію в WordPress, ми викличемо HookRegistry і дамо йому вказівку зробити це.
По- перше, AcmeColumn :
<?php
class AcmeColumn {
private $registry;
public function __construct( $registry) {
$this->registry = $registry;
}
public function start() {
$registry->add_hook( 'filter', 'manage_edit-page_columns', $this, 'add_page_column' );
}
public function add_page_column( $page_columns) {
$page_columns['template'] = 'Acme Column';
return $page_columns;
}
}
Потім HookRegistry :
<?php
class HookRegistry {
public add_hook( $type, $name, $object, $method) {
$type = strtolower( $type );
if ('filter' !== $type || 'action' !== $type) {
return new WP_Error( '1', 'No proper hook type defined.' );
}
}
private function add_filter( $name, $object, $method) {
add_filter( $name, array( $object, $method) );
}
private function add_action( $name, $object, $method) {
add_action( $name, array( $object, $method) );
}
}
Крім того, ми можемо підтримувати список різних класів і хуків, які були зареєстровані. Це може бути корисним, а може й ні, залежно від вашої реалізації, тому я ділюся лише як «ось те, що ви можете зробити».
І це може виглядати так (з використанням простого асоціативного масиву):
<?php
class HookRegistry {
private $registry;
public function __construct() {
$this->registery = array();
}
public add_hook( $id, $type, $name, $object, $method) {
$type = strtolower( $type );
if ('filter' !== $type || 'action' !== $type) {
return new WP_Error( '1', 'No proper hook type defined.' );
}
if ('filter' === $type) {
$this->add_filter( $name, $object, $method );
} else {
$this->add_action( $name, $object, $method );
}
$hook_info = array(
$type,
$name,
$object,
$method,
);
$this->registry[ $id ] = $hook_info;
}
private function add_filter( $name, $object, $method) {
add_filter( $name, array( $object, $method) );
}
private function add_action( $name, $object, $method) {
add_action( $name, array( $object, $method) );
}
}
Зверніть увагу, що в класі вище він тепер приймає $id як параметр. Є кілька способів ідентифікації інформації, яка надходить до реєстру, найпростіший із яких – створити ідентифікатор самостійно.
Однак, якщо ви хочете використовувати щось на кшталт назви хука або назви класу, це теж спрацює. Просто зауважте, що оскільки це асоціативний масив, він може підтримувати лише одне значення на ключ, тому ви можете в кінцевому підсумку викинути попередні дані, якщо не будете обережні.
Незважаючи на це, я вважаю це необов’язковим, але якщо це реалізовано, важливо переконатися, що у вас є відповідні функції для отримання екземпляра об’єкта за допомогою ключа.
Один з багатьох
Як і будь-яку іншу роботу, пов’язану з цим типом роботи, її можна перебудувати або переорієнтувати так, щоб вона працювала інакше або відповідала вашим потребам. Мета полягає не в тому, щоб показати остаточну модель того, як щось робити, а в тому, як підійти до неї та адаптувати її (як і будь-який шаблон проектування).
Крім того, це має на меті переконатися, що наші класи зберігають обов’язки, для яких вони створені, і водночас дозволяє їм реєструватися в WordPress за потреби. Однак цього разу клас не повинен робити це сам.
Замість цього він передає відповідальність класу, який несе виключну відповідальність за реєстрацію зазначених хуків. Таким чином, хоча він вводить більше класів, він збільшує згуртованість і зменшує зчеплення.
Це забезпечує переваги в обслуговуванні, тестуванні та загальному дизайні.