✅ Nowości, motywy, wtyczki WEB i WordPress. Tutaj dzielimy się wskazówkami i najlepszymi rozwiązaniami dla stron internetowych.

Widżety WordPress: Refaktoryzacja, część 3

23

Jeśli chodzi o aktualizację WordPress Widget Boilerplate (wszystko to jest śledzone w gałęzi deweloperskiej), przeszliśmy długą drogę, jeśli chodzi o refaktoryzację tego, jak jest zorganizowany.

Widżety WordPress: Refaktoryzacja, część 3

Do tej pory mamy:

Teraz jesteśmy gotowi do rozpoczęcia refaktoryzacji tego kodu w znacznie bardziej zorientowany obiektowo sposób.

Więc jeśli jeszcze nie nadrobiłeś poprzednich postów (naprawdę którykolwiek z nich), polecam to zrobić, ponieważ uaktualnienie tego zajmie trochę czasu. Jest dużo kodu do napisania wyjaśnienia.

Zacznijmy.

WordPress Widget Boilerplate: Refaktoryzacja, część 3

Prawdopodobnie największym problemem związanym z Boilerplate jest to, że wszystko jest zamknięte w jednej klasie.

Jasne, jest kilka fajnych rzeczy, takich jak oddzielanie naszych poglądów od logiki po stronie serwera, ale to wszystko.

Inne problemy, które pojawiają się tylko z samego patrzenia na kod, to:

  • dodawanie akcji i filtrów w konstruktorze,
  • posiadanie metod robiących więcej niż jedną rzecz,
  • brak klas odpowiedzialnych za implementację takich rzeczy jak rejestracja zależności,
  • i tak dalej.

W tym poście zamierzamy rozpocząć proces tworzenia abstrakcji, które ostatecznie zaimplementujemy, aby przełamać boską naturę Boilerplate w obecnej formie.

Zostanie to podzielone na kilka postów, abym mógł przedstawić solidne wyjaśnienie, dlaczego robimy pewne rzeczy, które robimy, a także wyjaśnić przykłady, które za tym stoją.

Jeśli zrobię to w inny sposób, seria pomija zbyt wiele cennych informacji, które można zastosować w innych praktykach programowania obiektowego.

Kim jest subskrybent?

System podpięć WordPressa – czyli dostępne akcje i filtry – opiera się na wzorcu projektowym opartym na zdarzeniach. Oznacza to, że za każdym razem, gdy coś się wydarzy, wydarzenie, WordPress uruchomi dowolny inny kod, który zasubskrybował to wydarzenie.

Więc kiedy rejestrujemy funkcję z hakiem, subskrybujemy zdarzenie. W tym celu jestem fanem tworzenia subskrybentów dla dowolnego haka, którego będziemy potrzebować.

Co więcej, abonenci zazwyczaj stosują spójny format. Oznacza to, że naprawdę łatwo jest utworzyć klasę abstrakcyjną, która implementuje część spójnych funkcji, a następnie pozwala klasie implementującej klasę abstrakcyjną skupić się wyłącznie na logice biznesowej.

Jednym z najłatwiejszych sposobów, aby to zademonstrować, jest subskrybowanie plików CSS i plików JavaScript, ponieważ są to dwie najczęstsze rzeczy, których używamy podczas tworzenia wtyczek.

Tworzenie klasy abstrakcyjnej

Zanim zaimplementujemy klasę abstrakcyjną, przedstawmy dokładnie, co zamierzamy zrobić, aby to stworzyć.

  1. Potrzebujemy właściwości, która reprezentuje wydarzenie, które subskrybujemy.
  2. Potrzebujemy funkcji uruchamiającej się za każdym razem, gdy podpięcie jest uruchamiane przez WordPress. Innym sposobem myślenia o tym jest to, że potrzebujemy funkcji do zaimplementowania za każdym razem, gdy dana akcja lub filtr jest uruchamiany przez WordPress.
  3. Potrzebujemy klas, aby zaimplementować abstrakcję.

Najpierw zdefiniujmy klasy abstrakcyjne. Wprost z podręcznika PHP czytamy:

Klasy zdefiniowane jako abstrakcyjne nie mogą być tworzone, a każda klasa, która zawiera co najmniej jedną metodę abstrakcyjną, musi być również abstrakcyjna. Metody zdefiniowane jako abstrakcyjne po prostu deklarują sygnaturę metody – nie mogą definiować implementacji.

W skrócie oznacza to, że nie możemy w rzeczywistości stworzyć instancji klasy abstrakcyjnej. Możemy jedynie tworzyć instancje klas, które definiują implementację.

Widżety WordPress: Refaktoryzacja, część 3

Nie oznacza to jednak, że klasa abstrakcyjna nie może implementować konkretnych rzeczy (takich jak definicja haka). Ale oznacza to, że istnieją pewne metody, które nie mają implementacji.

W przeciwnym razie zostaje nam tylko podstawowa klasa.

Ma sens? Spójrzmy.

Tworzenie klasy abstrakcyjnej

W tym poście stworzymy klasę abstrakcyjną specjalnie dla plików CSS i JavaScript.

Pamiętaj, ponieważ jest to klasa abstrakcyjna, konkretni subskrybenci mogą być nazwani czymś, co identyfikuje ich działanie (czyli mogą nazywać siebie wszystkim, co reprezentuje ich cel). I do tego dojdziemy.

Ale najpierw klasa abstrakcyjna. Podzielę się kodem, a następnie wyjaśnię dokładnie, co się z nim dzieje:

<?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. Zauważ, że utworzona przez nas właściwość jest chroniona. Dzieje się tak, aby klasy implementujące miały do ​​niego dostęp, ale nic poza nim nie.
  2. Stworzyłem funkcję do pobierania haka, która stanie się widoczna później. Zazwyczaj nienawidzę implementowania funkcjonalności, która nie jest od razu oczywista, ale jest to coś ważnego, biorąc pod uwagę, dokąd zmierzamy.
  3. Istnieje funkcja abstrakcyjna o nazwie load. W tym miejscu każda klasa, która implementuje tę funkcję, będzie zawierała swoją logikę biznesową, jak zobaczymy za chwilę.
  4. Lubię dokumentować przeznaczenie funkcji, gdy jest to konieczne, aby były w jednym miejscu, a następnie pozwolić klasom implementującym dostarczyć dokumentację, którą muszą dostarczyć podczas ich implementacji. Za chwilę to też zobaczysz.

Teraz, gdy mamy już klasę abstrakcyjną, ostatnią rzeczą, którą musimy zrobić, to upewnić się, że jest ona umieszczona we właściwym katalogu i w przestrzeni nazw. Jeśli śledziłeś, zaczynając od poprzedniego posta, prawdopodobnie mogłeś odgadnąć, gdzie będzie się znajdować, na podstawie przestrzeni nazw w kodzie.

Widżety WordPress: Refaktoryzacja, część 3

A jeśli nie, nie martw się. Ustalenie przestrzeni nazw i tego, co nie, może zająć trochę czasu. Mam więc nadzieję, że dzięki tym wpisom członkowskim i przykładom stanie się to jasne z czasem.

Tworzenie klas betonu

Teraz zaimplementujmy tę konkretną klasę, aby dodać oba arkusze stylów i źródła JavaScript, które posiadamy. Zauważysz jednak, że są bardzo podobne.

Jedyną różnicą jest implementacja funkcji ładowania, która dokładnie tak powinna działać.

Arkusze stylów

Biorąc pod uwagę powyższą klasę abstrakcyjną, teraz musimy stworzyć klasę do rejestracji arkuszy stylów. Ponieważ mamy dwa arkusze stylów, stworzymy dwie klasy:

  1. pierwsza klasa będzie odpowiedzialna za rejestrację arkusza stylów dla dashboardu, a konkretnie dla strony widżetu WordPress,
  2. druga klasa będzie odpowiedzialna za rejestrację wtyczki do właściwego bloga.

Wywołajmy odpowiednio każdy z tych AdminStylesheetSubscriber i PublicStylesheetSubscriber.

Po pierwsze, subskrybent arkusza stylów administratora :

<?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'
        );
    }
}

Zauważ, że używa to funkcji get_current_screen(), której używałem w poprzednich postach, aby upewnić się, że dodajemy zależności tylko tam, gdzie jest to konieczne.

Teraz publiczny subskrybent JavaScript. Używa funkcji is_admin(), aby upewnić się, że nie znajdujemy się w obszarze administracyjnym WordPressa.

<?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'
        );
    }
}

Oczywiście musimy jeszcze utworzyć instancję tych klas. To nadejdzie w dalszej części serii.

JavaScript

Jak można się domyślić, subskrybenci JavaScript nie różnią się zbytnio. Oddzielimy je w zależności od obszaru aplikacji, na którym się skupiają, i odpowiednio je nazwiemy.

Po pierwsze, subskrybent JavaScript administratora :

<?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'
        );
    }
}

Oraz publiczny subskrybent 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'
        );
    }
}

Ponownie, tych klas nie można jeszcze utworzyć, ale skupimy się na tym w nadchodzącym poście.

Abstrakcje i interfejsy

Pamiętaj, że abstrakcje i interfejsy są różne, ale łatwo je pomylić. Interfejsy zawierają absolutnie zerową implementację. Zamiast tego zapewniają gwarancję, że każda klasa, która implementuje interfejs, zaimplementuje wszystkie metody.

Z drugiej strony, klasy abstrakcyjne mogą mieć pewne funkcjonalności zaimplementowane w klasie abstrakcyjnej, pozostawiając kod specyficzny dla domeny – taki jak ładowanie arkuszy stylów i JavaScript – do odpowiedniej metody.

Stanie się to widoczne, jeśli jeszcze tego nie zrobiło, im dalej wejdziemy w tę serię. W międzyczasie – i jak zwykle – nie zapomnij zajrzeć do gałęzi deweloperskiej, aby zobaczyć, na czym stoimy z kodem.

Źródło nagrywania: tommcfarlin.com

Ta strona korzysta z plików cookie, aby poprawić Twoje wrażenia. Zakładamy, że nie masz nic przeciwko, ale możesz zrezygnować, jeśli chcesz. Akceptuję Więcej szczegółów