Прошло уже 10 лет с публикации моей предыдущей статьи на тему организации проекта на WordPress для удобной работы. Старый текст до сих пор кто-то добавляет в закладки и ставит звезды на Github, хотя многие вещи, актуальные на тот момент, устарели, а задачи поменялись. Если раньше я работал над большим количеством корпоративных сайтов, по принципу «сделал и забыл», то сейчас у меня в работе несколько долгоживущих новостных ресурсов с посещаемостью доходящей до миллиона хостов в сутки. Эти проекты требуют постоянного участия разработчика, и есть большая ответственность перед заказчиком за поломки.

Коллаж Gemini и Photoshop
Коллаж Gemini и Photoshop

Какая вообще проблема

WordPress очень популярен в журналистской среде, изначально он предназначен для публикации текстов. Фактически это стандарт индустрии, и множество сайтов СМИ: журналов, газет и интернет-медиа сделаны на нем. С другой стороны, WordPress исторически позиционирует себя как простой движок для быстрой сборки сайтов мышкой с крайне низким порогом входа для разработчика, что на самом деле ошибочно. От сюда мы можем увидеть как в 2026 году кто-то пытается делать серьезный проект устанавливая плагины через админку прямо на боевом сервере и редактируя файлы по FTP. Такой подход приводит к катастрофе в 100% случаев, когда сайт начинает расти.

В этой статье я расскажу, как улучшить свой опыт работы с WordPress, прикрутив к нему современные инструменты, поделюсь личным опытом и наработками, которые я собираю в репозитории: https://github.com/IvanZhuck/wordpress-sandbox

WordPress и git

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

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

Об этом я писал в предыдущей статье. На базе одной этой функции построен проект Bedrock от компании roots. Он демонстрирует как можно установить ядро WordPress как composer-зависимость, что дает возможность не тащить ядро, сторонние плагины и темы оформления в свой репозиторий, а управлять этим всем через composer.json, как в любом популярном php-фреймворке. На базе Bedrock строится вся дальнейшая работа.

WordPress Sandbox

Свою сборку на базе Bedrock я назвал Sandbox (песочница) т.к. она предназначена для работы на локальной машине разработчика, а не на боевом сервере. Сборка использует Docker-конфигурацию для разработки. На продакшене я обычно запускаю сервер либо на голом железе, либо с использованием LXC/LXD-контейнеров. Если вы захотите использовать Docker образ из этой сборки на боевом сервере, то она потребует доработки, хоть и не значительной.

Прежде всего развернем и запустим сборку, затем я расскажу о том как работает каждая ее часть.

Приступим.

0. На вашем компьютере должен быть установлен Docker и доступна команда make. Если вы работаете на Windows, то вам потребуется WSL для работы в локальном Linux-окружении.

1. Клонируйте репозиторий:

git clone git@github.com:IvanZhuck/wordpress-sandbox.git

2. Перейдите в директорию проекта:

cd wordpress-sandbox

3. Копируйте файл конфигурации:

cp .env.example .env

В файле .env вам потребуется задать настройки вашего приложения. Особое внимание стоит уделить параметрамLOCAL_UID и LOCAL_USER, там нужно указать id и имя пользователя на хост-машине, чтобы пользователь внутри контейнера был создан с такими же id и имененм. Это нужно для того, чтобы файлы монтируемые внутрь Docker контейнера принадлежали одному и тому же пользователю и в контейнере и на хост-машине. Остальные настройки стоит задать по вашему желанию.

4. Соберите проект:

make build

Эта команда запустит билд docker compose, он скачает недостающие образы контейнеров, а также соберет образ приложения из docker/php/Dockerfile

5. Сгенерируйте самоподписанный TLS-сертификат и ключ к нему:

make generate-ssl-keys

Без этого шага не запустится Nginx внутри контейнера.

6. Установите зависимости Composer:

make composer-install

Если все прошло успешно, то ваш новый WordPress-сайт станет доступен по адресу https://localhost:44301/. Порт можно заменить в файле .env через параметр LOCAL_DEV_PORT_HTTPS.

Если же сайт недоступен, то дебаг стоит начать с просмотра docker ps на предмет корректного запуска всех контейнеров.

Структура файлов проекта

Рассмотрим основные директории и файлы.

config/  - состоит из файла application.php, куда попадают все настройки приложения. А директория environments содержит файлы конфигурации под текущую настройку среды выполнения. Изменить которую можно в .env параметром WP_ENV.

docker/  - настройки контейнеров.

web/ - директория приложения, в нее смотрит веб-сервер, там находится точка входа в приложение index.php.

web/wp - сюда попадет ядро WordPress после установки, оно не хранится в git

web/app - в эту директорию устанавливаются плагины и темы, прочие директории приложения, например uploads, хранятся тоже в этой директории. Сюда попадает все, что не ядро WordPress, но что должно исполняться и быть доступным внутри приложения.

local-plugins/ и local-themes/ - директории локальных тем и плагинов WordPress. В эту директорию помещают плагины и темы, которые должны попасть в репозиторий проекта, но исполняться они будут из web/app/plugins и web/app/themes, туда Composer поместит символьные ссылки на них.

Makefile - содержит все доступные команды make.

composer.json - конфигурация Composer, о ней ниже.

docker-compose.ym, docker-compose.dev.yml, docker-compose.override.yml.example - конфигурация для Docker Compose, о ней также ниже.

phpcs.xml - файл-конфигурации PHP Code Sniffer. Команда make phpcs запускает статический анализатор вашего кода, а make phpcbf сразу вносит исправления, если это возможно. WordPress имеет свои стандарты кодирования, стоит придерживаться их, если вы разрабатываете плагины и темы для размещения где-либо публично. Внутри же своих проектов я придерживаюсь стандарта PSR12, так как мне и другим программистам, с которыми я сотрудничаю, он привычнее.

wp-cli-update-languages.sh - скрипт установки файлов локализации WordPress. Языковые файлы скачиваются с помощью команды make wp-update-translations. Задать языки можно в файле .env в параметре WP_LANGUAGE. Если сайт использует сразу несколько языков, то их стоит указать через запятую.

wp-cli.yml - конфигурация для WP-CLI, в ней мы сообщаем скрипту, что он имеет дело с нестандартной структурой проекта:

path: web/wp
server:
   docroot: web

Composer

Composer настраивается через файл composer.json и работает точно так же как и в любом другом PHP-фреймворке. За исключением нескольких отличий:

1. Плагины и темы загружаются с https://wpackagist.org/. Имена таких пакетов начинаются с wpackagist-plugin/... и wpackagist-theme/.... После загрузки они попадают в web/app/plugins и web/app/themes соответственно. Содержимое этих директорий игнорируется git.

2. Плагины из local-plugins/ устанавливаются также как обычные зависимости, если они имеют собственный composer.json.

...
  "repositories": [  
    {
      "type": "path",
      "url": "local-plugins/*"
    }
  ],
  "require": {
     "local-plugins/my-plugin": "1.0"
  }
...

С темами работает аналогично.

3. Если вам нужно установить сторонний плагин, который невозможно установить из wpackagist и его поставщик не дает возможности установки через composer или хотя бы загрузке по постоянной ссылке (это часто бывает с платными плагинами, например Polylang Pro), то следует поместить его в директорию local-plugins/ как есть, а в composer.json проекта добавить следующее:

...
  "repositories": [
    {
      "type": "package",
      "package": {
        "name": "polylang/polylang-pro",
        "version": "3.7.8",
        "type": "wordpress-plugin",
        "dist": {
          "type": "path",
          "url": "local-plugins/polylang-pro"
        }
      }
    }
  ],
  "require": {
    "polylang/polylang-pro": "*"
  }
...

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

Docker

WordPress Sandbox использует готовые контейнеры для: Mariadb, Redis, Nginx и контейнер приложения, который мы собираем на месте. В зависимости от функционала сайта к этому списку я чаще всего добавляю ClickHouse и Manticore, но они нужны не всегда, поэтому в стандартном исполнении их нет. Конфигурация контейнеров находится в файле docker-compose.yml. Кроме того в корне проекта присутствует еще два файла конфигурации docker-compose.dev.yml и docker-compose.override.yml. Предполагается, что в эти файлы выносятся настройки для разработчика.

Над проектом может работать несколько программистов, поэтому docker-compose.dev.yml общий для всех, а docker-compose.override.yml индивидуален для каждого разработчика и в репозиторий не попадает. Команды make build и make up подхватывают только docker-compose.dev.yml, а команды make build-override и make up-override оба файла.

Самый популярный сценарий использования: у одного разработчика компьютер на Windows, ему не надо делать дополнительных действий, чтобы ловить события Xdebug из контейнера. А у другого разработчика Linux, и чтобы у него работал Xdebug, ему нужно связать host.docker.internal с IP-адресом на хост-машине. Чтобы этого добиться, достаточно создать у себя локальный файл docker-compose.override.yml с содержимым:

services:
  app:
    extra_hosts:
      - host.docker.internal:host-gateway

и запустить контейнер командой make up-override, добавив host-gateway в /ect/hosts на хост-машине. Таким образом в репозиторий не попадет лишних личных файлов, и у всех все будет работать.

Dockerfile контейнера приложения находится в docker/php. Файл основан на образе php:8.4-fpm. Помимо самого интерпретатора PHP в этот контейнер устанавливаются все необходимые для работы расширения, Xdebug, Сomposer и Node.js вместе c pnpm.

Если для вашего проекта требуется другая версия php, просто измените ее в Dockerfile перед выполнением make build. Добавлять/удалять библиотеки и другой софт, который нужен внутри приложения, также следует в этом файле.

Остальная структура директории docker/ должна быть интуитивно понятна. В поддиректориях лежат соответствующие названию директории файлы настроек. Стоит обратить внимание на docker/nginx/default.conf.template - это файл конфигурации виртуального хоста Nginx, скорее всего вам придется вносить в него изменения под ваш проект. Изменения применяются как обычно после рестарта контейнера.

Тема оформления

В «песочнице» присутствует заготовка темы WordPress, точнее заготовка ее фронта. Исходный код находится в директории local-themes/izwp/src, а собранная тема находится в local-themes/izwp/wp-theme. Именно эта директория потом линкуется в web/app/themes. Таким образом исходники темы находятся за пределами области видимости веб-сервера и никак не могут быть скачаны через браузер.

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

Для сборки использую Webpack. Стили собираю отдельно с помощью команды sass в секции scripts файла package.json.

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

10 лет назад я использовал npm, потом перешел на Yarn, так как он был быстрее. Теперь же в качестве менеджера зависимостей фронтенд части я пользуюсь pnpm. Он замечателен тем, что скачивает все зависимости в свою директорию в корне проекта, а от туда создает символьные ссылки в нужные места. Так одна и та же библиотека скачивается только один раз, даже если присутствует в нескольких package.json внутри одного проекта.

От куда внутри одного сайта на WordPress несколько package.json? Новая философия WordPress опирается на блочный редактор. Документация по разработке блоков рассматривает каждый отдельный блок, как отдельное приложение, со своими зависимостями и сборщиком.

Раньше я собирал все блоки одним экземпляром Webpack и хранил зависимости внутри одного package.json. Это хорошо работало до тех пор, пока сайты не состаривались. Собранные блоки по-прежнему работают, но добавление новых требует свежих версий библиотек, а старые на них ругаются, надо их постоянно рефакторить. Это не всегда удобно, и не всегда на это есть время. Поэтому я пришел к тому, что один блок - один сборщик, у него свои зависимости и линтеры. Он полностью изолирован от всего остального. Так я могу оперативно перекидывать блоки между разными сайтами вообще не обращая внимание на совместимость фронтенд-библиотек. Ничего не ломается и не тратит мое время.

Вместо заключения

WordPress коварен своей простотой. Много разработчиков сломало о него ни одну мышь, которой по идее нужно собирать сайт, но как только требования к проекту усложняются, она летит в стену, так как ничего не получается. Разрабатывая сайты для СМИ я также сломал не мало мышей, но в итоге накопил большое количество опыта, которым хочу делиться.

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

  • Если проект разрабатывается более чем одним разработчиком.

  • Если в проект постоянно вносятся изменения.

  • Если период жизни проекта хочется растянуть и не ограничивать 1-2 годами от полной переделки до полной переделки.

  • Если все это происходит одновременно.

Спасибо, что прочитали!

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
На какую тему написать следующую статью?
0%Оптимизация производительности WordPress для большого новостного сайта0
0%Автоматизация деплоя с zero downtime для WordPress0
0%Разработка WordPress-тем для своих проектов. Жонглируем php, react и twig, чтобы всем угодить0
0%Организация бизнес-логики в сложном WordPress-проекте0
Никто еще не голосовал. Воздержавшихся нет.