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

Moderniser son code WordPress - Meetup AFUP Novembre 2017

Jeremy Desvaux de Marigny
November 28, 2017
47

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. Novembre 2018. Meetup AFUP
    Moderniser son
    code WordPress
    @jdmweb

    View Slide

  2. "Bonjour je m’appelle Jérémy
    et je bosse principalement sur
    WordPress chez Wonderful,
    une agence de communication"

    View Slide

  3. " Bouuuuuuuuuu
    WordPress c’est de la meeerde!"
    x devs (plus ou moins) anonymes

    View Slide

  4. - « 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

    View Slide

  5. 1 - Le Bricolage

    View Slide

  6. - index.php
    - style.css avec en-têtes
    Prérequis pour un thème
    6

    View Slide

  7. Plugin:
    - plugins/monplugin.php avec en-têtes
    Prérequis pour un plugin
    7

    View Slide

  8. - 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

    View Slide

  9. 2 - La Base de code

    View Slide

  10. • 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

    View Slide

  11. 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

    View Slide

  12. 3 - « Bon, on fait quoi alors? »

    View Slide

  13. - 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

    View Slide

  14. 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

    View Slide

  15. - Services!
    - Container d’injection de dépendance,
    - MVC (Controllers + vue, voire templating)
    Ce que l’on peut faire aussi
    15

    View Slide

  16. 4 - En pratique

    View Slide

  17. - 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

    View Slide

  18. - Penser le fonctionnement
    - Traduire ce fonctionnement en interface
    - Implémenter l’interface par x services
    - Injecter ces services
    Méthode possible
    18

    View Slide

  19. « 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)

    View Slide

  20. 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

    View Slide

  21. 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

    View Slide

  22. 22
    Architecture de fichiers

    View Slide

  23. 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": "^[email protected]"
    },
    "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

    View Slide

  24. Orchestration
    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();
    };

    View Slide

  25. Exemple de rangement
    Full objet
    Rangé
    Un objet par
    responsabilité
    Facilement overridable
    (le hook ou le service)
    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']);
    }
    }

    View Slide

  26. Exemple d’interfaçage entre vous et WordPress
    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);

    View Slide

  27. Transversaliser les plugins et capitaliser dessus :
    Créer des vendors composer privés ou public.
    Intégration continue
    Pour aller plus loin
    27

    View Slide

  28. • 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é

    View Slide

  29. 29
    Architecture de fichiers

    View Slide

  30. Let’s discuss!
    Merci
    Jérémy Desvaux de Marigny
    Lead Dev @agencewonderful
    @jdmweb

    View Slide