Заранее думать о масштабировании, по максимуму использовать стандартные решения Wordpress, сделать тему WP своими руками, заботиться об удобстве верстальщика, упороться по мобильности — и обновить блог компании так, чтобы его любили читатели, редакция и руководство. У нас получилось.


Блог PromoPult


Блогу компании Promopult уже 9 лет. За это время он пережил несколько трансформаций. О последней рассказывает Сергей Глазов, технолог нашего блога и других важных штук в системе Promopult.


Это уже не обсуждается, ибо стало нормой: быстрый и простой стандарт для блога компании, персоны, личного, да вообще, какого угодно — WordPress. Можно поспорить, но факт остается фактом.


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



Что было на (моем) старте — в 2016 году


Редко когда разработчик создает и продумывает всё с нуля. Чаще же получается так, что уже (чаще даже — давно, с отдельной историей) есть проект, который нужно поддерживать. Редизайн, правки, огромные ТЗ и требования. И в условиях существующего всего нужно как-то оперативно ориентироваться и решать задачи.


Я принял блог в 2016 году, когда у него уже была длинная история и не все так прекрасно, как хотелось.


Так выглядел блог SeoPult в начале 2016 года


  1. Старый дизайн блога с девятилетней историей.
  2. Отсутствие мобильной/планшетной версии в каком-либо виде.
  3. Больше 600 постов.
  4. Структурные проблемы с контентом и его организацией: 20+ категорий и девять с лишним сотен тегов (сейчас больше, но мы уже остановились).
  5. В планах уже есть ребрендинг и переезд на новый домен. Блога это тоже касается.
  6. Длинная цепочка действий при работе с кодом.
  7. Работа без контроля версий (.git).

Первые задачи: мобилизация и дизайн


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


Статистика в Яндекс.Метрике


Параллельно с этими работами рисовался новый дизайн.


Я как разработчик работал в паре с дизайнером, без лишней цепочки посредников в обсуждении, так что процесс коммуникации был быстрее и живее. Очевидный факт, конечно, но почему-то в многих процессах им пренебрегают. И получается так, что дизайнер делает что-то сильно оторванное от реальности. Разговаривайте ртом и обсуждайте все моменты. Каждый участник процесса заинтересован сделать хорошо и круто. Но не каждый понимает, что процесс — связанная цепочка, и если отдельный исполнитель на своем участке работ что-то упустит или не сделает — следующим в процессе людям будет тяжело.


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


Как было у нас с работой над кодом в блоге


Существовала DEV-версия блога с отдельной тест-базой данных. Работа с файлами происходила на удалённом сервере, тестирование проходило по отдельному адресу, недоступному во внешнем мире. После работы, тестирования и рождения какой-то единицы смысла — она выкатывалась на боевой блог через обращение к админу. Что делал он — отдельная магия.


Для блога, где что-то меняется один раз за год, — отличный процесс. Но с новой редакцией и её потребностями такой процесс был бы большой болью.


Что хотелось получить, как говорится, «в идеальном мире»


Весь код лежит в .git-репозитории. Боевой вариант блога — master-ветка этого репозитория. Вся работа с кодом происходит через коммиты в dev-ветку или другие ветки, связанные с отдельными большими задачами.


После того, как задача сделана — создаётся Pull Request (PR) и/или Merge Request (MR) с набором правок. Смысл в MR b PR один и тот же, но в разных сервисах — разное название. У нас GitLab, поэтому — Merge Request.


При создании MR становится доступным временный адрес вида имя-git-ветки-test.dev.blog.promopult.ru, доступный только по IP для живой проверки на тест-окружении.


Код в созданном MR ревьюится и проверяется в автоматическом (линтеры кода, которые проверяю синтаксис по заранее определенным правилами) и в ручном режиме (вертикаль власти в команде, на всё пристально смотрит своим военно-морским выпуклым внимательным глазом тимлид). После прохождения ревью — из интерфейса браузера .git-репозитория нажимается кнопка «Merge» и все изменения появляются в эфире боевого блога через какой-то краткий очевидный промежуток времени.


Редизайн, первый подход


План работ по редизайну блога:


  1. Вёрстка статичного прототипа по дизайн-макетам всех страниц;
  2. Превращение («натяжка») вёрстки в WordPress-тему.

Вёрстка — отдельный этап работ. Для удобной работы со стилями (CSS), разметкой и JS в проекте был использован набор плагинов и модулей, который собирается через Gulp-задачи, описанные в сборщике SPT (Start Project Template).


Ключевые слова, которые используется в сборщике статичной темы блога: HTML, CSS, JS, Babel, Gulp, PostCSS, SCSS, Nunjucks.


По завершению работы над вёрсткой структура была такой (указаны только каталоги первого уровня):


+-- design        # Дизайн, макеты и всякое
+-- app/          # Исходники проекта: отдельные модули
+-- dist/         # Собранный вариант проекта (html-файлы) и вся статика
+-- gulpfile.js/  # Конфиг Gulp.js
L-- package.json  # Файл-конфиг сборщика: пакеты, скрипты

Каждый отдельный визуальный смысловой элемент на странице, например, карточка поста (/components/article_card/), представлял из себя папку, в которой был:


— файл разметки (article_card.html),


— файл стилей (article_card.scss),


— файл JS (article_card.js).


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


На выходе сборщик создавал папку dist, в которой содержались готовые html-файлы страниц для наглядного просмотра в браузере на этапе правок и согласований, а также один файл стилей все темы и два JS-файла: один файл (app.js) описывал логику и поведение сайта, второй (vendor.js) содержал все библиотеки, используемые для сайта (jQuery, fotorama, magnific-popup и другие).


Дальше всё это нужно превратить в WordPress-тему и продумать файловую структуру. Чтобы можно было удобно работать со статичной вёрсткой и рядом же лежала WP-тема.


Список макетов, которые приготовил дизайнер. Они совпадают с файлами WordPress-темы блога:


  • Главная страница (файл home.php).
  • Страница отдельной записи/поста (single.php).
  • Вид отдельной текстовой страницы (page.php).
  • Страница подписки на рассылку (subscribe.php).
  • Ошибка 404 (404.php).
  • Отдельная страница тега (tag.php).
  • Отдельная страница категории (category.php).
  • Поиск и результаты поиска (search.php).

Рабочий процесс с таким подходом и разделением на статичный вариант и WordPress-вариант темы происходит так: если нужно что-то поправить в визуальной части — правки вносятся в статичном варианте и после теста переносятся в тему. Если правки нужны в какой-то не визуальной части — то изменяются только файлы WP-темы.


Папка с темой блога — bsp. Она расположена по пути в папке с темами самого блога:


+-- wp-content/           # Пользовательские файлы WordPress-сайта
¦  +-- themes/            # Темы сайта
¦  ¦  +-- app/            # Исходники статичной темы
¦  ¦  ¦  +-- gulpfile.js/ # Gulp-задачи для сборки
¦  ¦  +-- dist/           # Сборка статичной темы
¦  ¦  ¦  +-- assets/      # Ресурсы: JS, CSS и графика 
¦  ¦  +-- bsp/            # WP-Тема блога PromoPult
¦  ¦  ¦  +-- assets/      # Ресурсы: JS, CSS и графика, копирование из `/dist/`
¦  ¦  ¦  +-- home.php     # Главная страница блога и другие файлы в корне темы

Место wordpress-темы очевидно и предопределено файловой структурой самого WordPress.


Других тем в директории с темами нет — всё стандартное удалено. Есть миф о повышении производительности таким образом, но мы этого не заметили. Это сделано скорее для порядка в коде. Не нужно хранить то, что не используется и точно не будет использовано.


Также в .git лежат и все WP-плагины, которые используются. На нашем сайте это — Google XML Sitemaps, RSS for Yandex Turbo, RusToLat и WP-PostViews.


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


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


То есть рядом с основной темой bsp добавилась директория /app, в которой размещены исходники вёрстки темы и gulp-сборщик. Но в таком варианте был один сложный момент: статичные файлы генерировались в отдельную директорию, и чтобы изменения были в WP-теме, нужно было копировать статичные файлы стилей и скриптов в папку assets внутри темы.


Второй подход: новый вариант структуры



В первые недели это было решено простым консольным скриптом, которые копировал собранные файлы из статичной темы в WP-тему. Лишнее действие влечёт к ошибкам. Поэтому вариант был только в исправлении структуры.


У нас есть три важных директории (все пути от корня):


  1. WP-тема: /wp-content/themes/bsp
  2. Исходники статичной темы: /app
  3. Собранная статичная тема: /dist

А внутри неё — assets с файлами стилей, графикой и JS


Нужно расположить всё так, чтобы файлы статики стилей и скриптов собрались в нужную папку (/wp-content/themes/bsp/assets).


Новый вариант структуры оказался таким:


+-- gulpfile.js/       # Gulp-задачи для сборки
+-- wp-content/        # Пользовательские файлы WordPress-сайта
¦  +-- plugins/        # WP-плагины
¦  +-- themes/         # Темы сайта
¦  ¦  +-- bsp/         # Тема блога PromoPult
¦  ¦  ¦  +-- app/      # Исходники статичной темы
¦  ¦  ¦  +-- assets/   # Ресурсы: JS, CSS и графика (автогенерация)
¦  ¦  ¦  +-- home.php  # Главная страница блога и другие файлы в корне темы
+-- wp-admin/          # WP-файлы для админки
+-- wp-includes/       # WP-файлы системы

В корне всего проекта лежат gulp-задачи — и исполняются из корня. В конфиге gulp-задач описана структура, что статичные файлы собираются из директории wp-content/themes/bsp/app в wp-content/themes/bsp/assets без каких-то дополнительных действий типа копирования и т.п.


Файлы WP-темы остаются без изменений и работа происходит по старому сценарию: правки в статике > перенос в WP-файлы. Статика CSS и JS генерируется сразу в папке с темой и всё просто работает.


Пример MR для блога PromoPult


Всё это было про процесс работы. Теперь про то, как устроен сам блог.


Блог PromoPult: как всё устроено


Самая главная сила блога — команда. Редактор, авторы, верстальщики.


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


Чек-лист перед публикацией


Любую работу важно контролировать. Вёрстка статьи — стандартный, формализованный процесс, который спокойно можно представить в виде чек-листа.


Идею увидели у ребят из EmailSoldiers. Решили применить у себя.


Чек-лист публикации поста в блоге PromoPult


Если какой-то пункт не отмечен — система предупредит перед публикацией.


По клику на ссылки, подчеркнутые ссылки в элементе списка — подсвечиваем конкретный пункт.


Дополнительные настройки поста в админке


Чек-лист составлен в том же порядке, что и дополнительные настройки поста в админке.


Настройки поста в админке блога


Тесно переплетены с чек-листом публикации, описанным выше.


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


  • Описания для SEO-мета тегов.
  • Описания для OpenGraph-тегов, которые используют соцсети при расшаривании материала и формируют симпатичные карточки статей.
  • Удобная работа с картинками-обложками для постов. Одна картинка обязательна — она добавляется в карточку поста в плитке публикаций, которая отображается на главной и на странице рубрики или тега.
  • Дополнительные настройки темы: пост может быть с обложкой или без, есть краткий текст-анонс, который мы показываем в шапке с обложкой, и он же используется в описании статьи в рассылке дайджеста.

Экран с разделом настроек поста в блоге PromoPult


Раздел настроек поста реализован через мета-боксы и пользовательские поля в WordPress.


Через мета-бокс добавлен и чек-лист публикации.


В шаблонах работа с полями устроена просто: если поле не пустое и заполнено — достаем значение и показываем. Например, вот так выводится блок-реакция на пост:


<?php if (get_post_meta($post->ID, 'postreaction', true)) { ?>
<div class="article_reaction">
<div class="label-reaction"><span><?php echo get_post_meta($post->ID, 'postreaction', true); ?></span></div>
</div><!-- /.article_reaction -->
<?php } ?>

Пример вывода реакции на карточке поста:


Вывод реакции на карточке поста

Приятные мелочи


Есть несколько приятных мелочей, которые, может быть, никто и не видит. Но если кто-то заметил — хорошо.


Например, даты публикации поста в карточках и в отдельном посте у нас в кириллице и умеют склоняться. Почему-то этого нет в коробке WordPress. Если дата публикации в текущем году, то год у нас не показывается, если год отличается от текущего — дата показывается вместе с годом публикации.


Счётчик комментариев поста. Долго спорили о том, что «0 комментариев» или «нет комментариев» очень смущает. Решение очень простое: не показывать счётчик комментариев вообще, если комментариев меньше одного.


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


Свои собственные лайки: комментирование или расшаривание ссылки в соцсетях — долгое дело по меркам темпа потребления контента, а вот жмакнуть «лайк» и дать понять, что статья клёвая — просто и быстро. Мы сделали свои простые лайки и вывели счётчик в карточку поста. И лайки прибывают довольно быстро. А так как они стоят внизу статьи — это еще и сигнал, что текст дочитали.


Кнопка «Лайкнуть пост» в блоге PromoPult


Сделали тёмную тему для своего блога — нынче модно такое. С учётом модульной структуры (по сути сайт — набор блоков, которые как-то между собой комбинируются) и организации стилей получилось сделать довольно быстро.


Про интересное техническое


В теме есть минификация кода разметки, CSS и JS. CSS и JS сжимается через gulp-задачи в сборщике статики, а вот минификация разметки сделана через WordPress-хук WP_HTML_Compression.


А в комментарии в разметке мы добавили промокод для тех, кому интересно, как устроен сайт изнутри и кто первым делом идёт смотреть исходный код:


Исходный код блога PromoPult


Кэширование CSS и JS. Чтобы файлы стилей и скриптов кэшировались, но всегда были актуальными, если мы что-то переделали — используем filemtime(). Многие в таком случае используют ?<?php echo time(); ?>. Но такой вариант загружает файл и делает запрос при каждом обращении.


Лучше использовать такой трюк:


<link rel="stylesheet" type="text/css" href="<?php echo get_template_directory_uri(); ?>/assets/styles/style.css?t=<?php echo filemtime(get_theme_file_path().'/assets/styles/style.css'); ?>" />

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


Какие плагины используем


Несмотря на возможность и желание в некоторых случаях обойтись своим решением, плагины всё же мы используем. Список у нас такой:


  • Google XML Sitemaps — для генерации XML-карты сайта для роботов;
  • RSS for Yandex Turbo — турбо-страницы для Яндекса;
  • RusToLat — транслитерация русских символов URL в английские;
  • WP-PostViews — считает просмотры материалов;
  • Classic Editor — включает классический WordPress-редактор вместо нового блочного Gutenberg;
  • Ограничение попыток авторизации — это для безопасности: при нескольких ошибочных попытках логина — баним входящего на настраиваемый промежуток времени;
  • AMP — AMP-страницы для Google.

Советы-выводы для тех, кто работает над блогом компании


  • Советую в начале работы над проектом сразу думать о масштабировании.
  • Обязательно использовать .git в работе. Для 2019 года, конечно, странный совет, но этот совет может спасти кого-то от седых волос и выговора, когда что-то пойдет не так.
  • Разработку и работу над WordPress-темой лучше разделить на два этапа: сначала верстать что-то статичное, а уже свёрстанное «натягивать» как тему на WordPress.
  • Если есть возможность — время, команда и понимание того, зачем вам всё это, — делайте тему сами, без использования готовых вариантов. Выиграете в порядке и понимании того, как всё устроено. Не будете плодить костыли.
  • Используйте стандартные хуки и возможности WordPress, если ваш блог построен на нём. Кастомизировать и сделать удобное решение можно быстро и просто.
  • Делайте удобно для пользователя и редакции.
  • Не забывайте про социальные сети и микроразметку.
  • Не забывайте про мобильные версии.
  • Не забывайте про регулярные обновления плагинов и системы.
  • Выбирайте только проверенные плагины.

Работа над блогом продолжается — оставайтесь с нами.

Комментарии (18)


  1. mihdan
    27.06.2019 17:06

    Вместо RusToLat пора давно использовать Cyr2Lat.


    1. PromoPult Автор
      01.07.2019 13:05

      Вы ведь есть среди авторов плагина Cyr2Lat. Расскажите, пожалуйста, чем они отличаются и почему именно нужно использовать Cyr2Lat?


      1. mihdan
        01.07.2019 13:30

        — Поддержка PHP 5.6 — 7.4
        — Поддержка новый версий WordPress 5+
        — Страница настроек в админке.
        — Изменение таблиц траслитераций в админке или по хуку
        — Работа с ACF, WPML и еще несколькими популярными плагинами
        — Фоновые задачи конвертации (актуально если на сайте больше 10к записей)
        — Интерфейс конвертации для WP-CLI
        — Исправление более 30 ошибок старых форков
        — 100% покрытие тестами
        — ООП интерфейс

        Ну и много-много улучшений, которые остались под капотом и которые можно видеть в ченджлоге.


        1. PromoPult Автор
          01.07.2019 13:44

          А если прям сейчас заменить RusToLat на Cyr2Lat — какие проблемы могут всплыть?


          1. mihdan
            01.07.2019 14:12

            Проблем быть НЕ должно, так как сейчас cyr2lat при установке ничего не делает, чтобы не ломать чужие урлы, как это делают форки.

            Единственное что может быть — некоторые буквы в RusToLat НЕ соответствовали ГОСТ, а в cyr2lat они по ГОСТ, поэтому могут быть отличие в буквах Ё, Й, Я, Ш, Щ.

            Сайт при этом сломаться не должен.


  1. mihdan
    27.06.2019 17:08

    Введия для поста — похоже на ошибку в чеклисте.


    1. PromoPult Автор
      01.07.2019 13:05

      Да, действительно. Спасибо за внимательность, исправили.


  1. mihdan
    27.06.2019 17:13

    Например, даты публикации поста в карточках и в отдельном посте у нас в кириллице и умеют склоняться. Почему-то этого нет в коробке WordPress


    В ядре есть date_i18n(), которая и занимается этим.


    1. PromoPult Автор
      01.07.2019 13:06

      Спасибо! Есть повод переписать то, что есть у нас.
      Если кому-то тоже интересно, то начать можно с этого: developer.wordpress.org/reference/functions/date_i18n и/или wp-kama.ru/function/date_i18n


  1. monochromer
    27.06.2019 21:07

    Лучше использовать такой трюк:
    <link rel="stylesheet" type="text/css" href="<?php echo get_template_directory_uri(); ?>/assets/styles/style.css?<?php echo time(); ?>" />
    

    Наверно, хотели написать filemtime() вместо time()?


    1. PromoPult Автор
      27.06.2019 21:37

      Да, при верстке использовали не тот пример кода. Спасибо, что указали на ошибку.


  1. m0ze
    27.06.2019 21:38

    Спасибо, было интересно почитать. Жаль только, что вы не затронули вопросы нагрузки, самого WordPress'а версии 5+ и все возможные его косяки «из коробки» конкретно в вашем проекте, если что-то «выпиливали» из стандартного функционала, то что именно и почему, какой под этот блог выбрали хостинг и пр.

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

    Плюс, вижу, вы не спешите обновляться с версии 5.1.1 до 5.2.2 (хотя уже в 5.2 закрывается ряд уязвимостей) — почему?

    Ещё у вас страницы с записями авторов немного странно выглядят blog.promopult.ru/author/admin :)


    1. PromoPult Автор
      28.06.2019 12:54

      > Ещё у вас страницы с записями авторов немного странно выглядят blog.promopult.ru/author/admin :)
      Уже поправили, спасибо:)

      2. Насчет обновления версии Wordpress: обновляться до 5.2 мы планируем в ближайшее время (основные уязвимости ветки 5.1 исправлены в 5.1.1).


      1. VolCh
        29.06.2019 20:13

        Кстати, как с таким подходом обновления проходят? Вы же сам вордпресс в репозитории храните?


        1. PromoPult Автор
          30.06.2019 11:58

          Да, сам WordPress и всё связанно с ним (без пользовательских медиа-файлов) хранится в репозитории. Это накладывает определённые особенности на процесс обновления, но в целом всё это — ручное обновление версии WP: wordpress.org/support/article/updating-wordpress/#manual-update

          На ревью--ветке всё тестируется и в не пиковые часы (ночь любого выходного дня) по посещаемости, выкатывается.
          Скоро как раз новое обновление ставить.


    1. PromoPult Автор
      01.07.2019 13:10

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

      Стараемся делать аккуратно и хорошо с теми идеями, которые закладывались при разработке темы. Но иногда плагины — тоже хорошо. Конечно, зависит от задачи.

      Спасибо вам за солидарность.

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


  1. vlad-yermolayev
    30.06.2019 11:57

    Расскажите пожалуйста где Вы храните БД? Например для того, чтобы поднять такую же копию как на продакшене мы берем файлы c master, а как быть с БД?


    1. PromoPult Автор
      01.07.2019 13:12

      БД живёт своей жизнью. БД, как и всё на сервере регулярно бэкапится. Если нужно что-то где-то развернуть — берётся свежий дамп базы.

      Заботится о копиях БД для использования нужно, если проекты на WP идут потоком, как в студиях. У нас такого кейса просто нет. Поднимается БД, блог, настраиваются бэкапы и начинается работа уже с кодом, через git.