Использование функций WordPress

Ситуация: стандартный запрос убивает скорость
Вы создаёте сайт для локальной сети ресторанов. Клиент хочет вывести на главной странице «Акции недели» — три последних поста из категории «akcii», а в подвале — пять случайных отзывов. Казалось бы, типовые задачи. Но после запуска страница грузится 6–7 секунд. Менеджер жалуется на падение конверсии, а владелец бизнеса просит «просто переустановить WordPress». Знакомая история?
Проблема: разработчик использовал WP_Query в лоб, без фильтрации колонок и без кэширования. Второй цикл выполнял ORDER BY RAND(), что на базе в 5 000 записей давало тяжелый файл сортировки. Третий запрос подтягивал мета-поля каждой записи отдельно. Типичный случай, когда «просто» приводит к катастрофе производительности.
Решение: рефакторинг через параметры и кэш
Мы переписали выборку. Для акций установили posts_per_page = 3 и явно указали fields = 'ids' — так база возвращает только идентификаторы, а не полные объекты. Для отзывов отказались от ORDER BY RAND() в пользу сохранения массива ID в транзитном кэше на час.
Вместо повторных вызовов get_post_meta() в цикле загрузили метаданные одним запросом через update_meta_cache(). Время генерации страницы упало до 1.7 секунд, а после подключения плагина объектного кэширования — до 0.9 секунды. Результат: владелец доволен, бюджет на хостинг не вырос.
Чтобы вы не повторяли чужих ошибок, разберем пять профессиональных приёмов работы с функциями WordPress, которые редко описывают в базовых туториалах.
Неочевидные параметры WP_Query: экономьте память
Самый частый миф: WP_Query всегда возвращает только то, что вы явно попросили. На практике объект по умолчанию подтягивает все поля таблицы wp_posts, мета-данные (update_post_meta_cache) и термы (update_post_term_cache). Если вам нужны только ID или заголовки, вы расходуете ресурсы впустую.
Профессионалы всегда указывают fields => 'ids' или 'id=>parent', когда не собираются вызывать the_post() или setup_postdata(). Для списка новостей на главной или меню достаточно идентификаторов.
Второй момент — сортировка. Никогда не используйте 'orderby' => 'rand' на выборке более 50 записей. Это заставляет MySQL сортировать всю таблицу. Лучше хранить список ID в настройках темы или в транзитном кэше и перемешивать уже готовый массив на PHP.
- fields => 'ids' — снижает нагрузку на память до 80% при больших каталогах.
- no_found_rows => true — отключает подсчёт общего количества записей (экономит запрос COUNT) для списков без пагинации.
- update_post_meta_cache => false — блокирует загрузку всех мета-полей, если вы не будете их трогать.
- update_post_term_cache => false — аналогично для таксономий.
- 'cache_results' => true — сохраняет результат в объектный кэш (работает только при наличии Redis/Memcached).
- 'suppress_filters' => true — отключает все хуки
posts_*для чистоты запроса (используйте с осторожностью). - 'date_query' — гибкая фильтрация по дате без ручного WHERE.
Hooks: действие vs фильтр — где грань?
Многие путают add_action и add_filter, используя их как взаимозаменяемые. Это приводит к трудноуловимым багам. Action — это событие: «сделай что-то в этот момент» (отправить письмо, записать в лог). Filter — это модификация данных: «измени значение и верни обратно». Фильтр обязан возвращать значение. Экшн — нет.
Профессиональный приём: при создании собственного фильтра всегда передавайте минимум один аргумент — изменяемую переменную. И возвращайте её в конце функции, иначе данные обнулятся. Для экшнов, наоборот, возврат необязателен, но если вы вернёте false — некоторые ядра могут прервать выполнение.
Ещё один нюанс: приоритеты. По умолчанию 10. Если два хука с одинаковым приоритетом — порядок выполнения не гарантирован. Для критичных операций ставьте приоритет 5 (ранний) или 15 (поздний).
- Определите цель: меняете данные (filter) или выполняете действие (action).
- Используйте
apply_filters( 'my_filter', $value, $arg2 )— всегда передавайте хотя бы один изменяемый параметр. - Для действий используйте
do_action( 'my_hook', $data )без возврата. - В файле functions.php группируйте хуки: сначала фильтры, потом экшны.
- Избегайте приоритетов от 0 до 3 — обычно они зарезервированы ядром.
- Не вешайте тяжелые SQL-запросы на
init— используйтеwp_loaded. - Тестируйте хуки с включенным
WP_DEBUG— он покажет ошибки при неправильной передаче аргументов.
Сниппеты в functions.php: правильная структура
Файл functions.php часто превращается в помойку из кусков кода с форумов. Профи пишут модульно: каждая группа функций — в отдельный include-файл внутри папки темы. Например, /inc/post-types.php, /inc/shortcodes.php, /inc/performance.php.
Главный файл темы подключает эти части через require_once. Это упрощает отладку и перенос функций между проектами. К тому же, при обновлении темы ваш кастомный код не потеряется, если вы разместили его в отдельном файле внутри дочерней темы.
Нюанс: functions.php загружается при каждой смене темы. Если вы добавили туда объявление кастомного типа записи, при переключении на другую тему этот тип исчезнет, и данные в базе станут «сиротами». Решение для серьёзных проектов — выносить регистрацию типов записей в функциональный плагин (mu-plugin).
- Используйте дочернюю тему — основной файл темы не трогайте, это база.
- Группируйте код по файлам — один файл = одна ответственность.
- Добавьте проверки существования функций (
if ( !function_exists() )) — для совместимости с плагинами. - Не используйте короткие теги PHP — только
- Кэшируйте тяжелые вычисления — используйте
set_transient()для результатов сложных запросов. - Пишите описание для каждой функции — через DocBlock, чтобы через год вы помнили, зачем это нужно.
Сложные запросы: JOIN и подзапросы без плагинов
Когда стандартный WP_Query не справляется — вам нужен кастомный SQL через $wpdb. Например, вывести товары, у которых цена (мета-поле) больше среднего значения по всей категории. Это простое подзапросное условие, но meta_query такое не поддерживает.
Решение: напишите прямой SQL с помощью $wpdb->prepare() и get_results(). Никогда не используйте query() без подготовленных выражений — это дыра в безопасности. Обязательно проверяйте, что возвращает запрос, с помощью wp_list_pluck().
Важно: результаты кастомного SQL не кэшируются WordPress автоматически. Обёрните вызов в if ( false === ( $results = get_transient( 'my_query' ) ) ) { ... set_transient() }. Время жизни транзиента выбирайте по частоте обновления данных.
- Подключите
global $wpdb;в начале функции. - Используйте
$wpdb->prepare( 'SELECT ID FROM %i WHERE ...', $wpdb->posts )—%iдля таблиц. - Возвращайте стандартный объект WP_Post или массив ID, чтобы вписаться в архитектуру.
- Всегда ставьте лимит записей (
LIMIT), иначе сайт упадёт при большом объёме. - Создайте отдельный метод или функцию для сложных запросов — не пишите их прямо в шаблоне.
Практический вывод: как избежать проблем
WordPress даёт огромную гибкость, но за каждую непродуманную функцию вы платите скоростью. В 2026 году, когда Core Web Vitals стали обязательным фактором ранжирования, каждый лишний запрос к базе может стоить вам позиций в поиске.
Профессиональный подход — всегда начинать с вопроса: «Могу ли я получить эти данные без SQL?». Если да — используйте wp_cache_get() или опции. Если нет — оптимизируйте WP_Query или пишите кастомный SQL с кэшированием. Регулярно профилируйте страницы с помощью Query Monitor, чтобы видеть узкие места.
И главное: не бойтесь разбираться в ядре. Функции WordPress написаны с умом, и часто внутри них уже есть готовые оптимизации — надо лишь знать их имена. Уделите час изучению WP_Query документации — это окупится десятками сэкономленных часов в будущем.
Добавлено: 24.04.2026
