✅ Новости WEB и WordPress, темы, плагины. Здесь мы делимся советами и лучшими решениями для веб-сайтов.

Виджеты WordPress: рефакторинг, часть 3

23

Что касается обновления WordPress Widget Boilerplate (все это отслеживается в ветке разработки ), мы прошли долгий путь с точки зрения рефакторинга его организации.

Виджеты WordPress: рефакторинг, часть 3

На данный момент у нас есть:

Теперь мы готовы приступить к рефакторингу этого кода в гораздо более объектно-ориентированной манере.

Поэтому, если вы еще не ознакомились с предыдущими сообщениями (на самом деле, с любым из них), я рекомендую сделать это, потому что обновление этого займет некоторое время. Там много кода, чтобы написать объяснение.

Давайте начнем.

Шаблон виджета WordPress: рефакторинг, часть 3

Возможно, самая большая проблема с Boilerplate заключается в том, что все инкапсулировано в одном классе.

Конечно, есть некоторые приятные вещи, такие как отделение наших представлений от логики на стороне сервера, но это все, что нужно.

Другие проблемы, которые возникают только при просмотре кода, включают:

  • добавление действий и фильтров в конструктор,
  • наличие методов, делающих несколько вещей,
  • отсутствие классов, ответственных за реализацию таких вещей, как регистрация зависимостей,
  • и так далее.

В этом посте мы собираемся начать процесс создания абстракций, которые мы в конечном итоге реализуем, чтобы разрушить богоподобную природу Boilerplate в его нынешнем виде.

Это будет разбито на несколько постов, чтобы я мог дать четкое объяснение того, почему мы делаем определенные вещи, которые мы делаем, а также объяснить примеры, лежащие в основе этого.

Если я сделаю это каким-либо другим способом, то серия упустит слишком много ценной информации, применимой к другим методам объектно-ориентированного программирования.

Что такое подписчик?

Система хуков WordPress, то есть доступные нам действия и фильтры, основана на шаблоне проектирования, управляемом событиями. Это означает, что всякий раз, когда что-то происходит, событие, WordPress запускает любой другой код, который подписался на это событие.

Поэтому, когда мы регистрируем функцию с помощью хука, мы подписываемся на событие. С этой целью я сторонник создания подписчиков для любого крючка, который нам понадобится.

Кроме того, подписчики обычно следуют единому формату. Это означает, что очень легко создать абстрактный класс, который реализует некоторые согласованные функции, а затем позволяет классу, реализующему абстрактный класс, сосредоточиться исключительно на бизнес-логике.

Один из самых простых способов продемонстрировать это — подписаться на файлы CSS и файлы JavaScript, поскольку они являются двумя наиболее распространенными вещами, которые мы используем при создании плагинов.

Создание абстрактного класса

Перед реализацией абстрактного класса давайте подробно разберем, что мы собираемся сделать для его создания.

  1. Нам нужно свойство, представляющее событие, на которое мы подписываемся.
  2. Нам нужна функция, которая срабатывает всякий раз, когда хук вызывается WordPress. Другой способ думать об этом — нам нужна функция, которую нужно реализовать всякий раз, когда данное действие или фильтр запускается WordPress.
  3. Нам нужны классы для реализации абстракции.

Во-первых, давайте определим абстрактные классы. Прямо из руководства по PHP читаем:

Классы, определенные как абстрактные, не могут быть созданы, и любой класс, содержащий хотя бы один абстрактный метод, также должен быть абстрактным. Методы, определенные как абстрактные, просто объявляют сигнатуру метода — они не могут определять реализацию.

Короче говоря, это означает, что мы не можем создать экземпляр абстрактного класса. Мы можем только создавать экземпляры классов, которые определяют реализацию.

Виджеты WordPress: рефакторинг, часть 3

Однако это не означает, что абстрактный класс не может реализовать конкретные вещи (например, определение ловушки). Но это означает, что есть определенные методы, которые не имеют реализации.

В противном случае мы просто остаемся с базовым классом.

Есть смысл? Давайте взглянем.

Создание абстрактного класса

В этом посте мы собираемся создать абстрактный класс специально для файлов CSS и JavaScript.

Помните, поскольку это абстрактный класс, конкретные подписчики могут называться так, как идентифицируют то, что они делают (то есть они могут называть себя как угодно, что представляет их цель). И мы доберемся до этого.

Но сначала абстрактный класс. Я поделюсь кодом, а затем объясню, что с ним происходит:

<?php

/*
 * This file is part of the 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 WordPressWidgetBoilerplateSubscriber;

/**
 * An abstract implementation of a subscriber that requires a hook and the ability to
 * start the class.
 */
abstract class AbstractSubscriber
{
    /**
     * @var string a reference to the hook to which the subscriber should be registered
     */
    protected $hook;

    /**
     * @param string $hook the hook to which the subscriber is registered
     */
    public function __construct(string $hook)
    {
        $this->hook = $hook;
    }

    /**
     * @return string the hook to which the subscriber is registered
     */
    public function getHook(): string
    {
        return $this->hook;
    }

    /**
     * Implements the domain logic for the concrete class implementating this subcriber.
     */
    abstract public function load();
}
  1. Обратите внимание, что созданное нами свойство защищено. Это делается для того, чтобы реализующие классы могли получить к нему доступ, но все, что находится за его пределами, не может.
  2. Я создал функцию для извлечения хука, который станет очевидным позже. Как правило, я ненавижу реализовывать функциональность, которая не очевидна сразу, но это важно, учитывая, куда мы движемся.
  3. Существует абстрактная функция load. Именно здесь любой класс, реализующий эту функцию, будет размещать свою бизнес-логику, как мы скоро увидим.
  4. Мне нравится документировать назначение функций, когда это необходимо, чтобы они находились в одном месте, а затем позволять реализующим классам предоставлять документацию, необходимую для их реализации. Вы также увидите это на мгновение.

Теперь, когда у нас есть абстрактный класс, последнее, что нам нужно сделать, это убедиться, что он помещен в правильный каталог и имеет пространство имен. Если вы читали, начиная с предыдущего поста, то вы, вероятно, смогли догадаться, где он будет находиться, исходя из пространства имен в коде.

Виджеты WordPress: рефакторинг, часть 3

А если нет, не беспокойтесь. Выяснение пространств имен и того, что нет, может занять немного времени. Я надеюсь, что благодаря этим сообщениям о членстве и этим примерам со временем все станет ясно.

Создание конкретных классов

Теперь давайте реализуем этот конкретный класс, чтобы добавить как таблицы стилей, так и исходники JavaScript, которые у нас есть. Однако вы заметите, что они очень похожи.

Единственное, что отличается, — это реализация функции загрузки, которая именно так и должна работать.

Таблицы стилей

Учитывая приведенный выше абстрактный класс, теперь нам нужно создать класс для регистрации таблиц стилей. Поскольку у нас есть две таблицы стилей, мы собираемся создать два класса:

  1. первый класс будет отвечать за регистрацию таблицы стилей для панели инструментов и, в частности, для страницы виджета WordPress,
  2. второй класс будет отвечать за регистрацию плагина для реального блога.

Давайте назовем каждый из этих AdminStylesheetSubscriber и PublicStylesheetSubscriber соответственно.

Во- первых, подписчик таблицы стилей администратора :

<?php

/*
 * This file is part of the 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 WordPressWidgetBoilerplateSubscriber;

/**
 * The subscriber responsible for loading the stylesheet on the Widget administration page.
 */
class AdminStyleAssetSubscriber extends AbstractSubscriber
{
    /**
     * {@inheritdoc}
     */
    public function __construct(string $hook)
    {
        parent::__construct($hook);
    }

    /**
     * Adds the administrative stylesheet to the widget administration page.
     */
    public function load()
    {
        if ('widgets' !== get_current_screen()->id) {
            return;
        }

        wp_enqueue_style(
            'wordpress-widget-boilerplate',
            plugin_dir_url(dirname(__DIR__)).'assets/css/admin.css'
        );
    }
}

Обратите внимание, что здесь используется функция get_current_screen(), которую я использовал в предыдущих сообщениях, чтобы убедиться, что мы добавляем зависимости только там, где это необходимо.

Теперь общедоступный подписчик JavaScript. При этом используется функция is_admin(), чтобы убедиться, что мы не находимся в административной области WordPress.

<?php

/*
 * This file is part of the 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 WordPressWidgetBoilerplateSubscriber;

/**
 * The subscriber responsible for loading the stylesheet on the blog.
 */
class PublicStyleAssetSubscriber extends AbstractSubscriber
{
    /**
     * {@inheritdoc}
     */
    public function __construct(string $hook)
    {
        parent::__construct($hook);
    }

    /**
     * Adds the stylesheet to the public-facing side of the site.
     */
    public function load()
    {
        if (is_admin()) {
            return;
        }

        wp_enqueue_style(
            'wordpress-widget-boilerplate',
            plugin_dir_url(dirname(__DIR__)).'assets/css/widget.css'
        );
    }
}

Очевидно, нам еще предстоит создать экземпляры этих классов. Это будет позже в сериале.

JavaScript

Подписчики JavaScript мало чем отличаются, как вы уже догадались. Мы разделим их в зависимости от области приложения, в которой они сосредоточены, и назовем их соответствующим образом.

Во- первых, подписчик admin JavaScript :

<?php

/*
 * This file is part of the 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 WordPressWidgetBoilerplateSubscriber;

/**
 * The subscriber responsible for loading the JavaScript on the Widget's adminsitration page.
 */
class AdminScriptAssetSubscriber extends AbstractSubscriber
{
    /**
     * {@inheritdoc}
     */
    public function __construct(string $hook)
    {
        parent::__construct($hook);
    }

    /**
     * Adds the administrative JavaScript to the widget administration page.
     */
    public function load()
    {
        if ('widgets' !== get_current_screen()->id) {
            return;
        }

        wp_enqueue_script(
            'wordpress-widget-boilerplate',
            plugin_dir_url(dirname(__DIR__)).'assets/js/admin.js'
        );
    }
}

И общедоступный подписчик JavaScript:

<?php

/*
 * This file is part of the 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 WordPressWidgetBoilerplateSubscriber;

/**
 * The subscriber responsible for loading the JavaScript on the blog.
 */
class PublicScriptAssetSubscriber extends AbstractSubscriber
{
    /**
     * {@inheritdoc}
     */
    public function __construct(string $hook)
    {
        parent::__construct($hook);
    }

    /**
     * Adds the JavaScript to the public-facing side of the site.
     */
    public function load()
    {
        if (is_admin()) {
            return;
        }

        wp_enqueue_script(
            'wordpress-widget-boilerplate',
            plugin_dir_url(dirname(__DIR__)).'assets/js/widget.js'
        );
    }
}

Опять же, эти классы еще не могут быть созданы, но мы сосредоточимся на этом в следующем посте.

Абстракции и интерфейсы

Помните, что абстракции и интерфейсы разные, но их легко спутать. Интерфейсы содержат абсолютно нулевую реализацию. Вместо этого они гарантируют, что любой класс, реализующий интерфейс, будет реализовывать все методы.

Абстрактные классы, с другой стороны, могут иметь некоторую функциональность, реализованную в абстрактном классе, оставляя код, специфичный для предметной области, такой как загрузка таблиц стилей и JavaScript, соответствующему методу.

Это станет очевидным, если уже не стало, по мере того, как мы будем углубляться в эту серию. А пока — и как обычно — не забудьте заглянуть в ветку разработки, чтобы увидеть, где мы находимся с кодом.

Источник записи: tommcfarlin.com

Этот веб-сайт использует файлы cookie для улучшения вашего опыта. Мы предполагаем, что вы согласны с этим, но вы можете отказаться, если хотите. Принимаю Подробнее