Віджети WordPress: рефакторинг, частина 7
У кількох останніх публікаціях ми виконали багато роботи, щоб привести код до точки рефакторингу, про яку йтиметься в цій статті.
Зокрема, ми розглянули:
- гачки,
- реєстр, _
- і передплатники.
Усе це зіграє свою роль у тому, що ми збираємося робити сьогодні.
Шаблон віджетів WordPress: рефакторинг, частина 7
Для тих, хто знайомий з API віджетів WordPress, ви, ймовірно, знаєте, що він не сильно змінився за останні кілька років.
Крім того, він насправді складається лише з чотирьох функцій (одна з яких є конструктором):
- Конструктор відповідає за налаштування кількох властивостей віджета, найчастіше його назви та опису.
- Функція віджета відповідає за рендеринг вмісту віджета.
- Функція форми відповідає за відображення форми в області адміністрування WordPress при роботі з віджетом.
- Функція оновлення відповідає за оновлення параметрів, які зберігаються в базі даних (або ініціалізуються, а потім зберігаються параметри, які ще не існують у базі даних).
Приємно те, що цей конкретний підхід досягається шляхом успадкування функціональності для класу WP_Widget.
Однак проблема полягає в тому, що це дуже багато роботи для одного класу.
Замість цього ми повинні розділити кожну з функцій на окрему функціональну область.
Як і в будь-якій іншій сфері програмування, є способи, за допомогою яких деякі речі будуть зрозумілі щодо того, як їх можна зробити, а потім будуть деякі речі, які можна зробити різними способами.
Те, що я збираюся представити, це те, як я зараз підходжу до цього. Це може змінитися в майбутньому, а може й ні, і інші можуть по-іншому сприйняти це.
Незважаючи на це, реалізація буде набагато більш об’єктно-орієнтованою та дасть кожному класу власний набір обов’язків.
Однак перше питання полягає в тому, як ми розділяємо клас із чотирма функціями, які успадковуються від батьківського класу?
Оновлення Bootstrap
По-перше, є кілька речей, які нам потрібно налаштувати у програмі завантаження плагіна. А саме, нам потрібно зробити наступне:
- створити екземпляр реєстру та зробити його доступним через проект,
- оновити клас плагіна, щоб він приймав реєстр і завантажував передплатників,
- перевірити завантажувальну програму
Ось огляд усіх трьох із зазначених вище.
1 Створіть екземпляр реєстру
Оскільки ми вже розглядали це раніше в серії, має бути зрозуміло, як це зробити.
Спочатку перегляньте наступний код :
<?php
// Setup a filter so we can retrieve the registry throughout the plugin.
$registry = new Registry();
add_filter('wpwBoilerplateRegistry', function() use ($registry) {
return $registry;
});
Далі зауважте, що ми створюємо екземпляр реєстру (ми поговоримо про його простір імен на мить), а потім підключаємо його до спеціального фільтра, який дає нам доступ до нього в плагіні, коли забажаємо.
2 Оновіть клас плагіна
Далі нам потрібно оновити основний клас плагіна (який знаходиться в каталозі src ), щоб він посилався на реєстр і завантажував усіх зареєстрованих передплатників :
<?php
/*
* This file is part of WordPress Widget Boilerplate
* (c) Tom McFarlin <tom@tommcfarlin.com>
*
* This source file is subject to the GPL license that is bundled
* with this source code in the file LICENSE.
*/
namespace WordPressWidgetBoilerplate;
use WordPressWidgetBoilerplateUtilitiesRegistry;
/**
* The base class for this plugin. Maintains a copy of the registry and starts
* all of the objects that should hook into WordPress.
*/
class Plugin
{
/**
* @var Registry a reference to the simple container used to maintain plugin objects
*/
private $registry;
/**
* @param Registry $registry a reference to the simple container used to maintain plugin objects
*/
public function __construct(Registry $registry)
{
$this->registry = $registry;
}
/**
* Iterates through each of the subscribers maintained in the registry and registers them
* to the proper WordPress hook.
*/
public function start()
{
array_map(function ($subscriber) {
add_action($subscriber->getHook(), [$subscriber, 'load']);
}, $this->registry->getRegisteredSubscribers());
}
}
Однак зауважте, що ми ще не налаштували підписників. Ми почали це раніше в серії, і тепер настав час повернутися до цього, але ми зробимо це пізніше.
Однак нам потрібно додати функцію – навіть якщо вона тимчасова – щоб ми могли додати класи, які не є явними передплатниками подій:
<?php
/**
* @return array all of the the objects that aren't subscribers registered with WordPress
*/
public function getRegisteredObjects()
{
$objects = [];
foreach ($this->registry as $object) {
if (!$object instanceof AbstractSubscriber) {
$objects[] = $object;
}
}
return array_filter($objects);
}
Пізніше це буде перероблено, оскільки пізніше ми перетворимо основні класи на підписників.
3 Перегляньте Bootstrap
Перш ніж йти далі, я вважаю, що важливо переглянути програму початкового завантаження. Хоча ваш заголовок і документація можуть відрізнятися, важливо зазначити, що ми робимо наступне:
- простір імен початкового завантаження,
- заборона доступу до файлу,
- виклик автозавантажувача,
- налаштування реєстру,
- і запуск плагіна.
Звучить багато, але код досить короткий :
<?php
/**
* WordPress Widget Boilerplate
*
* The WordPress Widget Boilerplate is an organized, maintainable boilerplate for building
* widgets using WordPress best practices.
*
* @package WordPressWidgetBoilerplate
* @author Your Name <email@example.com>
* @license GPL-3.0+
* @link http://example.com
* @copyright 2018 - 2019 Your Name or Company Name
*
* @wordpress-plugin
* Plugin Name: WordPress Widget Boilerplate
* Plugin URI: https://github.com/tommcfarlin/wordpress-widget-boilerplate
* Description: An object-oriented foundation for building WordPress Widgets.
* Version: 1.0.0
* Author: Tom McFarlin
* Author URI: https://tommcfarlin.com
* Text Domain: widget-name
* License: GPL-3.0+
* License URI: http://www.gnu.org/licenses/gpl-3.0.txt
* Domain Path: /lang
*/
namespace WordPressWidgetBoilerplate;
use WordPressWidgetBoilerplateUtilitiesRegistry;
use WordPressWidgetBoilerplatePlugin;
// Prevent this file from being called directly.
defined('WPINC') || die;
// Include the autoloader.
require_once __DIR__. '/vendor/autoload.php';
// Setup a filter so we can retrieve the registry throughout the plugin.
$registry = new Registry();
add_filter('wpwBoilerplateRegistry', function() use ($registry) {
return $registry;
});
// Start the machine.
(new Plugin($registry))->start();
Однак зараз настав час поглянути на те, як це – розділити дочірній клас зі стандартного API віджетів на щось, що відповідає моделі коду, з яким ми працюємо.
Розбиття дочірнього класу
Ця частина, ймовірно, охопить кілька дописів, оскільки попереду ще трохи роботи, але ми почнемо зі створення нашого власного класу віджетів, який успадковуватиме базовий клас Widget.
По-перше, створіть каталог API у каталозі src і додайте файл під назвою Widget.php. Тут будуть розміщені основи віджета. У наступній публікації ми розглянемо адміністративні та загальнодоступні таблиці стилів і файли JavaScript.
На цьому етапі основний файл має виглядати так :
<?php
/*
* This file is part of WordPress Widget Boilerplate
* (c) Tom McFarlin <tom@tommcfarlin.com>
*
* This source file is subject to the GPL license that is bundled
* with this source code in the file LICENSE.
*/
namespace WordPressWidgetBoilerplateAPI;
use WP_Widget;
class Widget extends WP_Widget
{
/**
* @var string unique identifier for your widget
*/
protected $widgetSlug;
/**
* Initializes the plugin by setting its properties and calling the parent class with the description.
*
* @param mixed $widgetSlug
*/
public function __construct($widgetSlug)
{
$this->widgetSlug = $widgetSlug;
// TODO: update description
parent::__construct(
$this->getWidgetSlug(),
__('Widget Name', $this->getWidgetSlug()),
[
'classname' => $this->getWidgetSlug().'-class',
'description' => __('Short description of the widget goes here.', $this->getWidgetSlug()),
]
);
}
/**
* Return the widget slug.
*
* @return string slug variable
*/
public function getWidgetSlug()
{
return $this->widgetSlug;
}
/**
* TODO: This is a temporary message to show that the Boilerplate has loaded.
*/
public function load()
{
$html = '<p style="text-align:center; background: #fff; padding: 1em; border: 1px dotted gray; margin: 2em 2em 2em 14em;">';
$html .= 'The Widget Boilerplate is loaded.';
$html .= '</p>';
echo $html;
}
}
Зверніть увагу, що він приймає один аргумент. Я використовував назву віджета, але ви можете використовувати будь-яку назву, якщо вона представляє ваш віджет.
Це означає, що клас належним чином створюється та завантажується під час активації плагіна. Якщо ви цього не бачите, значить, щось не так (це ми негайно перевіримо).
Далі важливо переконатися, що цей клас додано до реєстру. Тож додайте наступні рядки коду в завантажувальну програму:
<?php
// Add the Widget base class to the Registry.
$registry->add('widget', new Widget('widget-name'));
І тепер, коли ви активуєте плагін, ви повинні побачити наступне:
Якщо ні, обов’язково перегляньте код у гілці розробки, щоб переконатися, що у вас є все, що описано в цій публікації.
Реалізація передплатників
У наступних публікаціях ми розглянемо, як ми можемо реалізувати підписку на загальнодоступній стороні сайту (тобто там, де відображається вміст віджетів). І ми зробимо те ж саме для адміністративної частини сайту.
Нарешті, ми звернемо нашу увагу на код, який відповідає за захист і серіалізацію даних (читайте: оновлення нашого віджета), а потім подивимося, як виглядає остаточна версія оновленого шаблону.
Однак у цьому дописі основною стратегією, яку ми використовуємо, є поділ дочірнього класу, щоб його можна було використовувати з іншими класами за допомогою інтерфейсів і базових класів, які вже визначені в базі коду.
