Структуризация проекта в WordPress, Laravel Blade и не только

в 11:41, , рубрики: classy, laravel blade, theme, wordpress, Проектирование и рефакторинг

WordPress можно любить, можно не любить, но сложно не согласиться с тем, что он решает проблемы. В последнее время разработка под WordPress ушла далеко от создания примитивных блогов с 4-5 информационными страницами. Все больше и больше компаний используют WordPress как инструмент для создания полноценных пользовательских систем с большим количеством внутренней логики. Печальная правда в том, что он совершенно не приспособлен для этого. Но увы, понимание этого приходит только с очередным запуском проекта в production.

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

Возможно, ситуация, описанная мною вам знакома, возможно нет. После 5 лет разработки в экосистеме WordPress я понял, что нужно что-то менять. Нужно переосмыслить структуризацию проекта, ввести правила организации логики и вывода, решить проблему повторяемости кода. Так и родилась идея написать wordpress theme framework — Classy.

image

Если вы разрабатывали темы под WordPress, вы знаете, что каждый view, будь то представление того, как будет выглядеть открытая статья (single-post.php), или страница со списком всех статей (archive-post.php), требует репрезентации в основной директории темы. Подобное решение возможно имеет смысл при несложном проекте, но как только проект обрастает логикой — это становится проблемой.

Пример количества файлов на средней сложности проекте:

├── 404.php
├── README
├── archive-gallery.php
├── archive-inspiration.php
├── archive-rent.php
├── archive-vendor.php
├── attachment.php
├── category.php
├── comments.php
├── footer-rent.php
├── footer-vendor.php
├── footer.php
├── functions.php
├── gulpfile.js
├── header-rent.php
├── header-vendor.php
├── header.php
├── image.php
├── index.php
├── page-diy-ideas.php
├── page-edit-vendor-profile.php
├── page-local-blogs.php
├── page-login.php
├── page-my-favorites.php
├── page-my-listings.php
├── page-my-messages.php
├── page-my-profile.php
├── page-new-listing.php
├── page-password-reset.php
├── page-register.php
├── page-vendor-guide.php
├── page-vendors.php
├── page-wedding-ideas.php
├── page.php
├── screenshot.png
├── search.php
├── searchform.php
├── sidebar-home.php
├── sidebar-rent.php
├── sidebar-vendor.php
├── sidebar-filters.php
├── sidebar-general.php
├── sidebar-user.php
├── single-inspiration.php
├── single-rent.php
├── single-gallery.php
├── single-vendor.php
├── single.php
├── style.css
├── tag.php
├── taxonomy-location.php
├── template-about.php
├── template-activate-account.php
├── template-become-a-member.php
├── template-contact.php
├── template-default.php
├── template-faq.php
├── template-grab-a-badge.php
├── template-map.php
├── template-new-inspiration.php
├── template-new-rent.php
└── template-welcome.php

«Это все и мы знаем, но что ты предлагаешь?” — спросите вы. А я предлагаю простую вещь, которая с недавнего апдейта WordPress, а именно с версии 4.4 наконец стала полностью доступна — вынести все view в соответствующую папку, а в корне оставить просто index.php, который будет брать на себя весь render:

Classy::render();

и то, что раньше выглядело как:

├── archive-rent.php
├── single-rent.php
├── header-rent.php
├── footer-rent.php
└── sidebar-rent.php

теперь выглядит как:

├── views
│ ├── rent
│ │ ├──archive.blade.php
│ │ ├──single.blade.php
│ │ ├──layout.blade.php

Организованнее? Думаю, да.

Как это работает?

Если вы знакомы с иерархией WordPress, то знаете, что при обработке запроса, он пытается найти самое специфичное представление для данного запроса и спускается вниз пока не дойдет до index.php, собственно, того файла, на который мы и поставили основной Classy::render().

image

В данном случае Classy::render выполняет две функции, одну для поиска view (ClassyTemplate::get_template()) и другую для поиска scope (ClassyScope::get_scope()). Эти 2 функции, повторяют алгоритм поиска view который используют wordpress, но делают они это раздельно, дважды. Это позволяет нам иметь независимую архитектуру представления и данных.

Зачем, спросите вы? Очень часто возникают ситуации при разработке, когда одни и те же данные необходимо отобразить по-разному. К примеру, у нас есть множество templates, которые являются не более, чем разновидностью дизайна для page.php. Так почему же не прописать один раз данные в scope/page.php и просто разработать отдельные view для templates: view/page/dark.php, view/page/light.php, и т.д. Вследствие этого, мы уменьшаем количество повторяемого кода, так как scope у нас приготавливается единожды.

Так что там с WordPress 4.4?

Ах да, совсем забыл рассказать про это. В WordPress 4.4 наконец-то появилась возможность модифицировать список шаблонов, которые отображаются пользователю в административной панели. Теперь, благодаря хуку “theme_page_templates”, мы можем этот список переписывать и добавлять в него наши зарегистрированные по новому способу шаблоны.

А регистрируются они очень просто. К примеру, мы хотим создать шаблон about. Для этого мы создаем представление view/page/about.blade.php и вверху файла указываем Template Name: About. То есть, в конечном счете, наш view будет выглядеть так:

{{-- Template Name: About --}}

@extends('base.default')

@section('content')
    @if ($post)
        <article class=“about">
            <h1>{{ $post->title() }}</h1>

            <section class="body">
                {{ $post->content() }}
            </section>
        </article>
    @endif
@stop

Концепция моделей

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

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

В нашем случае есть модель — ClassyPost, которую может расширить любая другая модель custom post type.

Laravel Blade

Использование template engine в разработке WordPress — дело каждого, но опыт показал, что он помогает уменьшить время разработки проекта, делая его более структурированным, а код приятным и легким для чтения. До недавних пор я использовал Timber, который является имплементацией template engine — Twig, но в нем есть ряд минусов:

1) Выполнение php функций. Думаю тут можно обойтись без комментариев, потому что оно выглядит вот так:

{{function('edit_post_link', 'Edit', '<span class="edit-link">', '</span>')}}

В то время, как Laravel Blade позволяет выполнять php код и та же самая функция будет выглядеть так:

{{ edit_post_link('Edit', '<span class="edit-link">', '</span>') }}

2) Скорость. Timber не самый быстрый фреймворк и его основной проблемой является перегруженность функционалом. На маленьких проектах это незаметно, но когда вы имеете дело с проектами с большей посещаемостью — это становится болевой точкой. Моей же идеей было сохранить минималистичность фреймворка, чтобы там было только то, что действительно используется в проекте.

Заключение

Проект Classy является полностью Open-Source. Моей изначальной идеей было помочь решить проблему с организацией проекта в WordPress, с которой сталкиваюсь я и мои коллеги и, надеюсь, эта реализация поможет и другим. В текущей реализации возможны баги, но я буду активно работать над их устранением. С нетерпением жду ваших отзывов о проделанной работе.

Репозиторий в GitHub.

Автор: anrw

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js