Widgets WordPress : refactorisation, partie 7
Dans les derniers articles, nous avons fait beaucoup de travail pour amener le code au point de refactorisation qui sera couvert dans cet article.
Plus précisément, nous avons couvert :
Tous ces éléments vont jouer un rôle dans ce que nous allons faire aujourd’hui.
Le passe-partout du widget WordPress : refactorisation, partie 7
Pour ceux qui connaissent l’ API WordPress Widgets, vous savez probablement qu’elle n’a pas beaucoup changé au cours des dernières années.
De plus, il ne se compose en réalité que de quatre fonctions (dont l’une est le constructeur) :
- Le constructeur est chargé de définir plusieurs propriétés sur le widget, le plus souvent son nom et sa description.
- La fonction widget est responsable du rendu du contenu du widget.
- La fonction de formulaire est responsable de l’affichage du formulaire dans la zone d’administration de WordPress lorsque vous travaillez avec le widget.
- La fonction de mise à jour est chargée de mettre à jour les options qui sont enregistrées dans la base de données (ou initialisées puis d’enregistrer les options qui n’existent peut-être pas encore dans la base de données).
La bonne chose est que cette approche particulière est réalisée en héritant d’une fonctionnalité pour la classe WP_Widget.
Le problème, cependant, est que c’est beaucoup de travail pour une seule classe.
Au lieu de cela, nous devrions séparer chacune des fonctions dans son propre domaine de fonctionnalité.
Comme pour tout ce qui concerne la programmation, il y aura des façons dont certaines choses sont claires sur la façon dont elles peuvent être faites, puis il y aura des choses qui peuvent être faites de plusieurs façons.
Ce que je vais vous présenter, c’est comment je l’aborde pour l’instant. Cela pourrait changer à l’avenir, ou peut-être pas, et d’autres pourraient avoir une vision différente.
Quoi qu’il en soit, l’implémentation sera beaucoup plus orientée objet et donnera à chaque classe son propre ensemble de responsabilités.
La première question, cependant, est de savoir comment diviser une classe avec quatre fonctions et qui hérite d’une classe parente ?
Mise à jour du Bootstrap
Tout d’abord, il y a quelques choses que nous devons ajuster dans le bootstrap du plugin. A savoir, nous devons faire ce qui suit:
- instancier le registre et le rendre disponible via le projet,
- mettre à jour la classe Plugin pour qu’elle accepte un registre et charge les abonnés,
- revoir le bootstrap
Voici un aperçu des trois éléments ci-dessus.
1 Instancier le Registre
Puisque nous avons déjà couvert cela plus tôt dans la série, il devrait être clair comment procéder.
D’abord, voyez le code suivant :
<?php
// Setup a filter so we can retrieve the registry throughout the plugin.
$registry = new Registry();
add_filter('wpwBoilerplateRegistry', function() use ($registry) {
return $registry;
});
Ensuite, notez que nous instancions le registre (nous parlerons de son espace de noms dans un instant), puis nous l’accrochons à un filtre personnalisé qui nous permet d’y accéder à tout moment dans le plug-in.
2 Mettre à jour la classe du plugin
Ensuite, nous devons mettre à jour la classe du plugin principal (qui réside dans le répertoire src) afin qu’elle référence le registre et charge tous les abonnés enregistrés :
<?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());
}
}
Notez, cependant, que nous n’avons pas encore vraiment configuré d’abonnés. Nous avons commencé cela plus tôt dans la série et il est maintenant temps d’y revenir, mais nous le ferons plus tard.
Nous devons cependant ajouter une fonction – même si elle est temporaire – afin que nous puissions ajouter des classes qui ne sont pas des abonnés explicites aux événements :
<?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);
}
Cela sera retravaillé plus tard car nous transformerons les classes principales en abonnés plus tard.
3 Revoir le Bootstrap
Avant d’aller plus loin, je pense qu’il est important de revoir le bootstrap. Bien que votre en-tête et votre documentation puissent varier, il est important de noter que nous faisons les choses suivantes :
- namespacer le bootstrap,
- empêcher l’accès au fichier,
- appeler le chargeur automatique,
- mise en place du registre,
- et lancer le plugin.
Cela semble beaucoup mais le code est assez court :
<?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();
À ce stade, cependant, il est temps d’examiner ce que c’est que de diviser la classe enfant de l’ API Widgets standard en quelque chose qui correspond au modèle de code avec lequel nous travaillons.
Fractionner une classe enfant
Cette partie va probablement s’étendre sur quelques articles car il y a un peu de travail à faire, mais nous allons commencer par créer notre propre classe de widgets qui héritera de la classe de base Widget.
Tout d’abord, allez-y et créez un répertoire API dans le répertoire src et ajoutez un fichier appelé Widget.php. C’est là que résideront les bases du widget. Nous aborderons les feuilles de style administratives et publiques et les fichiers JavaScript dans le prochain article.
À ce stade, les bases du fichier devraient ressembler à ceci :
<?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;
}
}
Notez qu’il prend un seul argument. J’ai utilisé widget-name mais vous pouvez utiliser ce que vous voulez tant qu’il représente votre widget.
Cela permet de montrer que la classe est correctement instanciée et chargée lorsque le plugin est activé. Si vous ne voyez pas cela, c’est que quelque chose ne va pas (ce que nous reviendrons dans un moment).
Ensuite, il est important de s’assurer que cette classe est ajoutée au Registre. Ajoutez donc les lignes suivantes du code dans le bootstrap :
<?php
// Add the Widget base class to the Registry.
$registry->add('widget', new Widget('widget-name'));
Et maintenant, lorsque vous activez le plugin, vous devriez voir ceci :
Si ce n’est pas le cas, assurez-vous de consulter le code dans la branche de développement pour vous assurer que vous disposez de tout ce qui est décrit dans cet article.
Mise en œuvre des abonnés
Dans les prochains articles, nous verrons comment nous pouvons implémenter des abonnés pour le côté public du site (c’est-à-dire là où le contenu du widget est affiché). Et nous ferons de même pour la zone d’administration du site.
Enfin, nous porterons notre attention sur le code responsable de la sécurisation et de la sérialisation des données (lire : mettre à jour notre widget), puis nous verrons à quoi ressemble la version finale d’un passe-partout mis à jour.
Dans cet article, cependant, la stratégie principale que nous utilisons consiste à diviser une classe enfant afin qu’elle puisse toujours être utilisée avec d’autres classes à l’aide d’interfaces et de classes de base déjà définies dans la base de code.
