Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Moderniser son code WordPress - Meetup AFUP Nov...

Jeremy Desvaux de Marigny
November 28, 2017
120

Moderniser son code WordPress - Meetup AFUP Novembre 2017

Présentation donnée dans le cadre d'un meetup de l'AFUP Montpellier en novembre 2017 à propos des opportunités d'industrialisation de son code WordPress.

Jeremy Desvaux de Marigny

November 28, 2017
Tweet

Transcript

  1. - « Acheter un thème 30$ et changer 3 fichiers,

    tu me fais rire! » - « Mettre x plugins chopés à droite à gauche c’est du bricolage » - « On dirait du code spaghetti des années 90 » - « C’est pas fait pour faire du dev » - « J’y connais rien et en fait je n’ai pas réussi à faire ce que je voulais » « Mais Pourquoi? » 4
  2. - Peu de règles / Grande flexibilité. Faire bien =

    + d’efforts - Votre choix = votre responsabilité - Les tutos - Achat de thème - Choix de plugin D’où vient le bricolage alors? 8
  3. • Programmation objet • PSR • Gestion des dépendances •

    Autoloader / namespaces / PSR4 • Injection de dépendance • Des objets à responsabilité précise • Tests automatisés • Intégration continue "C’est du vieux code" / "C’est pas fait pour faire du dev" 10
  4. Et WordPress du coup? 11 • Programmation objet • PSR

    • Gestion des dépendances • Autoloader / namespaces / PSR4 • Injection de dépendance • Des objets à responsabilité précise • Tests automatisés • Intégration continue • OUCH
  5. - Archi composer - WordPress = vendor - Accès à

    packagist - wpackagist = accès à tous les plugins du repo WP - satis = packages privés + Autoloader et PSR4 Pour composer : On passe sur bedrock 13
  6. Cas 1 : Subir (Core objects, ex wpdb, variables globales)

    Cas 2 : Interfacer / Abstraire (Core concepts ex: routing, API) Cas 3 : Coder en full objet (code plugin ET thème) Pour l’objet : 3 cas de figure 14
  7. - Services! - Container d’injection de dépendance, - MVC (Controllers

    + vue, voire templating) Ce que l’on peut faire aussi 15
  8. - Full objet, namespaces / PSR4 autoloading - Pas de

    fichier à rallonge, on range - Une responsabilité = un objet - Main plugin file - Activator / Deactivator -Hook service, ShortCode service, Routing service, ListTable service… Maintenant la pratique : mon plugin 17
  9. - Penser le fonctionnement - Traduire ce fonctionnement en interface

    - Implémenter l’interface par x services - Injecter ces services Méthode possible 18
  10. « Et si jamais on veut changer ce morceau, quel

    impact ça a sur le code?. » = la question qui guide (et qui vous fait créer des services)
  11. US: En back, je veux administrer les actualités. En front,

    je veux afficher une liste d’actualités paginées, puis le détail d’une actu au clic. Exemple : actualités 20
  12. En back: - Requêter : un repository - Afficher :

    une ListTable - Form édition : un service pour ça - Soumission: un service pour ça Pourquoi tant de services ? - Implémentation WordPress ou autre (web service JSON, SOAP…) - Injection d’un override sur mesure Stratégie 21
  13. Utilisation de composer { "name": "agencewonderful/wwp-actu", "description": "Plugin wwp-actu", "type":

    "wordpress-plugin", "minimum-stability": "dev", "prefer-stable": true, "authors": [ { "name": "Jeremy Desvaux", "email": "[email protected]" } ], "require": { "agencewonderful/wonderwp-plugin-core": "^1.0.0@dev" }, "autoload": { "psr-4": { "WonderWp\\Plugin\\Actu\\": "includes" } }, "repositories": [ { "type": "composer", "url": "https://won.wonderful.fr/satis/packages-mirror" } ] } Gestion de dépendance De version Autoload
  14. Orchestration <?php namespace WonderWp\Plugin\Actu; use WonderWp\Framework\AbstractPlugin\AbstractManager; use WonderWp\Framework\AbstractPlugin\AbstractPluginManager; … class

    ActuManager extends AbstractPluginManager { public function register(Container $container) { parent::register($container); //Register Config $prefix = $this->getPluginName(); $this->setConfig('path.root', plugin_dir_path(dirname(__FILE__))); $this->setConfig('path.url', plugin_dir_url(dirname(__FILE__))); $this->setConfig('textDomain', WWP_ACTU_TEXTDOMAIN); //Register Controllers $this->addController(AbstractManager::ADMIN_CONTROLLER_TYPE, function () { return new ActuAdminController($this); }); $this->addController(AbstractManager::PUBLIC_CONTROLLER_TYPE, function () { return $plugin_public = new ActuPublicController($this); }); //Register Services $this->addService(ServiceInterface::ACTIVATOR_NAME, function () { //Activator return new ActuActivator(WWP_PLUGIN_ACTU_VERSION); }); $this->addService(ServiceInterface::HOOK_SERVICE_NAME, $container->factory(function () { //Hook service return new ActuHookService(); })); $this->addService(ServiceInterface::ASSETS_SERVICE_NAME, function () { //Asset service return new ActuAssetsService(); }); $container[$prefix . '.repository'] = function () { return new ActuRepository(); };
  15. Exemple de rangement Full objet Rangé Un objet par responsabilité

    Facilement overridable (le hook ou le service) <?php namespace WonderWp\Plugin\Core; use WonderWp\Framework\DependencyInjection\Container; use WonderWp\Framework\Hook\AbstractHookService; class WwpHookService extends AbstractHookService { /** @inheritdoc */ public function run(WwpAdminChangerService $adminChangerService) { //Admin Login add_action('login_head', [$adminChangerService, 'customize_login_screen']); add_action('admin_menu', [$adminChangerService, 'forceDashboard']); //Admin pages add_action('admin_head', [$adminChangerService, 'jsConfig']); add_action('admin_head', [$adminChangerService, 'customizeLogo']); add_action('admin_menu', [$adminChangerService, 'customizeMenus']); add_action('admin_init', [$adminChangerService, 'registerPanels']); add_action('save_post', [$panelService, 'savePanels']); add_action('manage_pages_custom_column', [$tableManagerService, 'modifiedColumnValue'], 10, 2); add_filter('manage_edit-page_columns', [$tableManagerService, 'addModifiedColumn']); add_filter('manage_edit-page_sortable_columns', [$tableManagerService, 'addModifiedSortableColumn']); add_action('manage_posts_custom_column', [$tableManagerService, 'modifiedColumnValue'], 10, 2); add_filter('manage_edit-post_columns', [$tableManagerService, 'addModifiedColumn']); add_filter('manage_edit-post_sortable_columns', [$adminChangerService, 'addModifiedSortableColumn']); } }
  16. Exemple d’interfaçage entre vous et WordPress <?php namespace WonderWp\Plugin\Core\Framework\Repository; class

    PostRepository implements RepositoryInterface { /** * @inheritDoc * @return \WP_Post */ public function find($id) { return get_post($id); } /** * @inheritDoc * @return \WP_Post[] */ public function findAll() { $criteria = [ 'numberpost' => -1, ]; return get_posts($criteria); } /** * @inheritDoc * @return \WP_Post[] */ public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null) { if (!empty($limit)) { $criteria['numberposts'] = $limit; } else { $criteria['numberposts'] = -1; } if (!empty($offset)) { $criteria['offset'] = $offset; } return get_posts($criteria); } Full objet PSR4 use \WonderWp\PostRepository; $repo = new PostRepository(); $post = $repo->find(1);
  17. Transversaliser les plugins et capitaliser dessus : Créer des vendors

    composer privés ou public. Intégration continue Pour aller plus loin 27
  18. • Passer sur bedrock • Coder en full objet son

    thème et ses plugins • Réappliquer les concepts de code moderne dans vos devs • Middleware entre vous et le code WP qui ne vous plait pas En résumé