Привет, Хабр! Это мой первый пост, поэтому поделюсь с вами кейсом ускорения работы одного сайта на WP + WooCommerce. Сам занимаюсь веб-разработкой, последние два года только на фрилансе. Не претендную на идеальную статью, я сам каждый день учусь новому, но в статье максимально стараюсь избегать неточностей. Статья будет полезна джунам и миддлам кто разрабатывает сайты, кто занимается оптимизацией сайтов и кто хочет посмотреть на работу php кода "с высоты". Для себя из полезного можно узнать как связать вместе OpenServer, PhpStorm и xDebug. Один раз настраиваете и можно потом запросто делать отладку. И так, начнём. Есть сайт. Работает на WP + wooCommerce. Количество продуктов ~21 000, категорий ~4 000. Куча своих таксономий, пользовательских типов записей. Генерация одной страницы занимает 4-5 секунд, иногда доходит до 10. Пользователи со всей статикой и с задержками сети ждут ещё 2-3 секунды. Задача: надо выявить что так тормозит сайт.Конфигурация сервера: CentOS 8, ISPmanager 6 Lite. RAM 16 Гб, 4 процессора (именно какие не смог узнать, там VDS не показал с теми доступами что у меня были, а я сильно не интересовался, ну тут это не особо важной роли играет).Для такой конфигурации и трафика который не превышает в сутки 500 уников такая долгая генерация однозначно патология. Взялся изучать... Для начала сделал бекапы. Установил плагин Query Monitor который абы как показывает запросы в БД. Зацепка есть: около ~15000 запросов.  У WooCommerce есть такая проблема - по умолчанию при выводе категорий он показывает сколько там находится продуктов рядом с названием категории в скобках. Если кому интересно, issue. Так вот, Query Monitor сможет показать свойственный этой особенности запросы и одной строчкой можно исправить ситуацию. Но на этот раз проблема в другом.  На первый взгялд не понять в чем проблема. Тяжелых плагинов нет, тема не на каком-то Elementor или WP Bakery, создан с нуля и расширена плагином Advanced Custom Fields, все файлы разбиты по папкам и названы адекватно. Копаем глубже. С помощью плагина Duplicator быстро взял копию сайта. Исключил все медиа, изображения, архивы и папку wp-content/uploads целиком. Они нам не нужны для анализа, но могут здорово раздуть архив что сервер упрётся в лимит, либо браузер покажет 504 Gateway time out.  У меня установлен OpenServer версии 5.3.8, создаю директорию, закидываю файл с архивом и с файлом installer.php что выдаёт duplicator. Перехожу по адресу mydevsite.domain/installer.php и заполняю все данные что просит dup-installer. Не буду тут долго останавливаться, поднять копию сайта проще простого. Открываю проект в phpStorm. IDE довольно удобный, но для текущего кейса можно было и без него обойтись. Поэтому если у вас другой IDE не торопитесь уходить, нам он нужен только для просмотра логов xDebug. Если у вас как и у меня установлен OpenServer то отдельно устанавливать расширение xDebug не надо, он уже установлен, достаточно в конфигурации php.ini раскомментировать нужные строчки и немного настроить. Если что-то другое документация к xdebug тут. Чтобы открыть php.ini надо проделать следующее: Клик по иконке OpenServer в нижнем меню -> Дополнительно -> Конфигурация -> php7.4.  У меня php версии 7.4, если у вас другая версия там будет соответствующее название.  В открывшемся окне с конфигами находим строчку ;zend_extension = xdebug и убираем с начала строки точку с запятой (раскомментируем). Чуть ниже в окне будут уже сами конфиги xdebug. Опускаемся или находим поиском строку [xdebug] и вносим правки ниже: Тут xdebug.mode указывает что мы хотим профилировать и трассировать код. По умолчанию там стоит off. Есть ещё другие режимы, но на них не буду останавливаться, этих двух нам достаточно. xdebug.start_with_request указывает что включать режим отладки надо не всегда, а только если передать специальный параметр (через POST, GET или COOKIE, удобнее всего GET параметр). И да, этот параметр по умолчанию закомментирован, не забудьте раскомментировать. Всё. xDebug готов, перезапускаем OpenServer. Теперь при переходе на любую страницу нам достаточно прописать ключ get параметра XDEBUG_PROFILE и php будет собирать отладочную информацию и записывать в папку что указан по пути xdebug.output_dir (у меня стоит путь по умолчанию). Про другие особенности можно прочитать тут.Вид URL будет иметь такой вид mydevsite.domain/?XDEBUG_PROFILE если надо собрать информацию с главной страницы. В моем случае я снял снепшот с главной страницы.  Для просмотра логов я использую phpStorm. Но гугл подсказывает что для vsCode или Atom тоже есть решения. В самом верхнем меню находим раздел Tools и в списке Analyze Xdebug Profiler Snapshot. Нас попросит выбрать файл, переходим по пути где указали запись файлов, у меня по умолчанию это {{ папка openServer где он установлен }}/userdata/temp/xdebug/  Если всё сделано правильно там будет записанный файл с названием cachegrind.out.{{ какие-то цифры }}. Выбираем, ждём когда phpStorm обработает всё и вуаля, у нас есть работа скриптов с высоты.  phpStorm показывает логи в красивом и удобном виде. На первом окне смотрим сколько вообще времени заняло выполнение скрипта. Но нас интересует вкладка Call Tree (ниже выделил куда кликать). И так у нас уже есть какие-то цифры. Раскрываем по одному файлы чтобы понять где лежит проблемный участок. Нас интересует ветка с файлом template-loader.php, нам надо ускорить написанную с нуля тему, а не копать в сторону ядра WP/ Ориентируясь цифрами, сколько процентов какая ветка сожрала, опускаемся до нужного файла и участка кода. В моем случае функция get_heder использовала 42% от всего времени. Смотря ещё глубже нахожу что это функция get_catalog_menu который жрал 36%. Кавабанга! Находим файл в котором находится функция. Можно кликнуть по ПКМ и сделать jump to source. В нашем случае это оказался файл menu.php.  Вкратце - функция выбирает каждый раз все 4 000 категории и как-то делая проверки строит из них меню. Каждая проверка условии для одной категории это одно обращение к БД. В целом кусок кода довольно тяжелый. Разработчик учёл что эта функция сильно нагружает код и сделал кеширование через WP Object Cache. Но не учёл что кеш работает только если сервер поддерживает кеширование и на сайте WP установлен плагин для объектного кеширования. А в моем случае на сервере он не работал и кеш не создавался. Про эту особенность можно прочитать тут. Заказчик сказал что сайт мало когда редактируется, категории тем более, поэтому не стали переделывать код и оставили всё как есть для удобства. Только вместо объектного кеширования сделал хранение кеша в транзиентах.  И была такая же функция, только для менюшек в сайдбаре. Их тоже сделал чтобы кешировались. Итог - сайт летит.  Поверх всего провёл ещё ряд других оптимизаций и настройку сервера (сжатие gzip, время жизни кеша для статики, апдейт версии php до 8.0, очистка базы данных от мусора, вынесение стилей и скриптов в отдельные файлы). Результаты до/после тут только после исправления всего двух функций. После были выполнены ещё другие мелкие оптимизации, настроен плагин полностраничного кеширования и суммарно для конечного пользователя сайт работает раза 4-5 быстрее. Отклик кешированных страниц занимает ~400мс, а не кешированных в зависимости от типа 1,5-2 секунд.В целом заказчик доволен. Мы не ставили цель разогнать сайт до максимума на данном этапе. В будущем возможно с ростом трафика будем ещё переделывать кодовую базу. Пока на этом всё. Мне будет интересно прочесть комментарии от других разработчиков что можно было делать лучше, а где были допущены ошибки. Веб-разработчик