Кратко: $wpdb — глобальный объект WordPress для прямых запросов к базе данных. Когда стандартных средств мало (нужен сложный JOIN, разовая выборка или массовое обновление), $wpdb позволяет написать SQL напрямую. Главное правило безопасности — никогда не подставлять данные пользователя в запрос конкатенацией: только $wpdb->prepare с плейсхолдерами %s и %d, а для типовых операций — методы $wpdb->insert, $wpdb->update и $wpdb->delete, которые экранируют значения сами. Ниже — разбор основных методов, готовые примеры запросов, защита от SQL-инъекций и типичные ошибки.
Что такое $wpdb и когда она нужна
$wpdb — это экземпляр класса wpdb, глобальная переменная WordPress, через которую ядро, плагины и темы общаются с MySQL. Она уже подключена к базе: логин, пароль и имя таблицы знать не нужно, префикс таблиц учитывается автоматически через свойства $wpdb->posts, $wpdb->postmeta и другие.
Когда $wpdb действительно нужна. Во-первых, сложные выборки, которые не умеет WP_Query: объединение нескольких таблиц, агрегаты вроде COUNT и GROUP BY, запросы к своим таблицам плагина. Во-вторых, массовые операции: обновить сразу тысячу метаполей одним запросом вместо тысячи вызовов update_post_meta. В-третьих, работа с кастомными таблицами, которые ваш плагин создал при активации.
Когда $wpdb не нужна. Если задача решается стандартными средствами — WP_Query, get_posts, get_option, get_post_meta — используйте их: они учитывают кэш, хуки и фильтры. Прямой SQL обходит большинство слоёв WordPress, поэтому это инструмент «на особый случай», а не замена стандартному API. Про высокоуровневую работу с запросами подробно написано в материале WP_Query в WordPress: продвинутая работа с запросами.
Четыре метода для чтения данных
Для выборок у $wpdb есть четыре основных метода. Разница — в форме результата.
| Метод | Что возвращает | Типовой сценарий |
|---|---|---|
| get_results() | Массив строк (объектов или массивов) | Список записей по сложному условию |
| get_row() | Одну строку | Данные конкретного элемента |
| get_var() | Одно значение из первой ячейки | Счётчик, ID, одно поле |
| get_col() | Одномерный массив значений одного столбца | Список ID или email-адресов |
Простой пример: получить заголовки пяти последних записей типа post прямо из таблицы posts.
global $wpdb;
$titles = $wpdb->get_results(
"SELECT ID, post_title
FROM {$wpdb->posts}
WHERE post_type = 'post'
AND post_status = 'publish'
ORDER BY post_date DESC
LIMIT 5",
ARRAY_A
);
foreach ( $titles as $row ) {
echo esc_html( $row['post_title'] );
} Обратите внимание: имя таблицы подставляется через {$wpdb->posts}, а не написано вручную с префиксом wp_. Если на сайте префикс изменён ради защиты, запрос с жёстко прописанным wp_posts просто не сработает. Результат запрошен как ARRAY_A — массив ассоциативных массивов, с ним удобно работать в цикле; по умолчанию метод возвращает объекты.
Подготовленные запросы: защита от SQL-инъекций
Главная опасность прямых запросов — SQL-инъекция. Если подставить в запрос данные из формы, URL или cookies через конкатенацию, злоумышленник впишет в параметр кусок SQL и получит доступ к данным. Единственный правильный способ подставить переменную — обернуть запрос в $wpdb->prepare с плейсхолдерами: %s для строк, %d для целых чисел, %f для дробных.
global $wpdb;
$author_id = intval( $_GET['author'] );
$rows = $wpdb->get_results(
$wpdb->prepare(
"SELECT ID, post_title
FROM {$wpdb->posts}
WHERE post_author = %d
AND post_status = 'publish'",
$author_id
),
ARRAY_A
); prepare работает как sprintf: заменяет плейсхолдеры экранированными значениями. Число плейсхолдеров должно совпадать с числом аргументов.
| Плейсхолдер | Тип данных | Пример значения |
|---|---|---|
| %s | Строка | Заголовок, slug, email |
| %d | Целое число | ID записи, автора, количество |
| %f | Дробное число | Цена, рейтинг, координата |
Для поиска по подстроке маску % ставят в значение, а не в плейсхолдер запроса:
global $wpdb;
$search = '%' . $wpdb->esc_like( 'Word' ) . '%';
$rows = $wpdb->get_results(
$wpdb->prepare(
"SELECT ID, post_title
FROM {$wpdb->posts}
WHERE post_title LIKE %s
AND post_status = 'publish'",
$search
),
ARRAY_A
); Здесь esc_like экранирует специальные символы LIKE в пользовательской строке, а плейсхолдер %s подставляет готовую маску безопасно. Полностью «голых» запросов с переменными быть не должно — это правило номер один при работе с базой.
Запись, обновление и удаление без ручного SQL
Для типовых операций записи у $wpdb есть вспомогательные методы: insert, update, delete и replace. Они собирают корректный SQL сами и экранируют значения по указанным форматам. Это удобнее и безопаснее, чем писать INSERT и UPDATE вручную.
global $wpdb;
$table = $wpdb->prefix . 'myplugin_log';
// Вставка
$wpdb->insert(
$table,
array(
'user_id' => get_current_user_id(),
'action' => 'form_submit',
'created_at'=> current_time( 'mysql' ),
),
array( '%d', '%s', '%s' )
);
// Обновление
$wpdb->update(
$table,
array( 'action' => 'form_resubmit' ),
array( 'user_id' => 5 ),
array( '%s' ),
array( '%d' )
);
// Удаление
$wpdb->delete(
$table,
array( 'user_id' => 5 ),
array( '%d' )
); Третий и пятый аргументы — форматы значений: %d число, %s строка, %f дробное. Методы возвращают число затронутых строк или false при ошибке. Если в update совпадут старые и новые значения, вернётся 0, а это не ошибка — не путайте эти два случая при проверке результата.
Кэш, производительность и массовые операции
Прямые запросы минуют объектный кэш WordPress: результат get_results не попадёт в кэш, и на посещаемом сайте один и тот же тяжёлый запрос будет выполняться снова и снова. Если выборка вызывается часто, кэшируйте результат вручную через wp_cache_get и wp_cache_set.
global $wpdb;
$cache_key = 'top_authors_v1';
$data = wp_cache_get( $cache_key );
if ( false === $data ) {
$data = $wpdb->get_results(
"SELECT post_author, COUNT(*) AS total
FROM {$wpdb->posts}
WHERE post_status = 'publish'
AND post_type = 'post'
GROUP BY post_author
ORDER BY total DESC
LIMIT 10",
ARRAY_A
);
wp_cache_set( $cache_key, $data, '', 3600 );
} Второй практический приём — массовые операции одним запросом. Вместо цикла из тысячи update_post_meta делается один UPDATE с JOIN по таблице метаполей: это на порядки быстрее и почти не грузит базу. Но именно поэтому перед экспериментами с прямой записью крайне важно иметь свежий бэкап: ошибка в запросе без WHERE обновит всю таблицу. Регулярное резервное копирование — обязательная часть работы с базой, о настройке написано в статье резервное копирование WordPress: как настроить бэкапы.
Типичные ошибки при работе с $wpdb
Первая и самая дорогая ошибка — конкатенация переменных в SQL вместо prepare. Даже если переменная «точно число», приводите её intval или пропускайте через %d: привычка спасает от инъекций в будущем коде. Вторая ошибка — забытый global $wpdb внутри функции: без него переменная пуста, и код молча не работает. О том, как ловить такие ошибки, рассказано в материале WP_DEBUG и отладка WordPress.
Третья ошибка — жёстко прописанный префикс таблиц вместо {$wpdb->prefix} и готовых свойств вроде {$wpdb->posts}. Четвёртая — проверка результата: get_results возвращает пустой массив и при отсутствии данных, и при ошибке запроса; реальную причину показывает $wpdb->last_error. Пятая — тяжёлые запросы без кэша на каждой странице: COUNT по большой таблице в шапке сайта способен замедлить весь проект, а тема ускорения через кэширование разобрана в гайде кэширование WordPress для новичков.
Шестая ошибка — прямой SQL там, где достаточно стандартного API. Записи, созданные мимо wp_insert_post, не триггерят хуки, и плагины об их появлении не узнают. Если логика завязана на хуки, используйте высокоуровневые функции, а про устройство хуков напомнит статья хуки WordPress: actions и filters.
Как отладить запрос
У $wpdb есть встроенные диагностические свойства. $wpdb->last_query хранит последний выполненный SQL, $wpdb->last_error — текст ошибки MySQL, $wpdb->num_rows — число строк результата. Их достаточно для большинства проблем: вывели last_error после запроса — и увидели, что таблицы нет или опечатка в колонке.
global $wpdb;
$result = $wpdb->get_results( "SELECT * FROM {$wpdb->posts} LIMIT 3" );
if ( null === $result ) {
error_log( 'SQL error: ' . $wpdb->last_error );
}
if ( '1' === WP_DEBUG ) {
error_log( 'Last query: ' . $wpdb->last_query );
} Для глубокого профилирования включите константу SAVEQUERIES — WordPress начнёт складывать все запросы в $wpdb->queries с временем выполнения. На боевом сайте её держать выключенной: лог замедляет работу. Если запросы нужны внешним инструментам, иногда удобнее идти через REST API WordPress, а разовые операции по базе быстрее выполнять из консоли — этому посвящён гайд WP-CLI для новичков: установка и основные команды.
Когда выбрать другой инструмент
Прежде чем писать SQL, проверьте, нет ли готового решения. Выборка записей — WP_Query и get_posts: они учитывают кэш и статусы. Метаполя — get_post_meta, update_post_meta, get_user_meta. Опции — get_option и update_option. Счётчики — wp_count_posts. Свои таблицы оправданы, когда данных много и их структура не влезает в посты и метаполя; как правильно создавать такие таблицы при активации плагина, описано в материале как создать свой плагин WordPress с нуля.
Ещё один слой альтернативы — данные пользователя и права: их достают через get_userdata и проверяют возможностями, а не запросами к таблице users. Работу с ролями и правами разбирает статья пользовательские роли и права доступа в WordPress. И помните про безопасность в целом: прямой SQL — точка входа для инъекций, поэтому он должен быть лишь одним из слоёв защиты, описанных в материале безопасность WordPress для новичков: 10 настроек.
Чек-лист безопасной работы с $wpdb
Соберём правила в короткий список, который стоит проговаривать перед каждым коммитом с прямым SQL. Во-первых, любое значение из внешних данных — только через $wpdb->prepare, никаких склеек строк. Во-вторых, таблицы — только через свойства $wpdb или {$wpdb->prefix}, никаких жёстких имён. В-третьих, для вставки, обновления и удаления — методы insert, update, delete вместо ручного SQL.
В-четвёртых, перед массовой записью — свежий бэкап и проверка WHERE дважды. В-пятых, тяжёлые выборки кэшируются, а разовые административные скрипты выполняются один раз и удаляются. В-шестых, ошибки логируются через last_error, а не молча игнорируются. И в-седьмых, если запрос повторяется в нескольких местах — вынесите его в функцию или обёртку в отдельном файле плагина: так проще и тестировать, и кэшировать. Много готовых приёмов для таких обёрток собрано в подборке полезных сниппетов для functions.php, а разовые задачи по расписанию удобно запускать через планировщик wp-cron.

Частые вопросы про $wpdb
Что такое $wpdb в WordPress простыми словами?
Это встроенный «мост» между WordPress и базой данных MySQL. Объект $wpdb уже подключён к базе с нужными доступами, знает префикс таблиц и даёт методы для чтения и записи данных. Им пользуются, когда стандартных функций вроде WP_Query недостаточно: сложные JOIN, счётчики, массовые обновления, работа с таблицами плагина.
Почему нельзя подставлять переменные в SQL напрямую?
Из-за SQL-инъекций: если в запрос попадают данные из формы, адреса страницы или cookies без экранирования, злоумышленник может дописать свой SQL и прочитать или изменить данные. Защита — $wpdb->prepare с плейсхолдерами %s и %d либо методы insert, update, delete, которые экранируют значения автоматически.
Чем отличаются get_results, get_row и get_var?
Формой результата. get_results возвращает массив всех строк выборки, get_row — одну строку, get_var — одно значение из первого столбца первой строки, get_col — массив значений одного столбца. Для списков берите get_results, для счётчиков и отдельных полей — get_var, это экономит память и код.
Как узнать, что запрос к базе данных завершился ошибкой?
Проверьте свойство $wpdb->last_error сразу после запроса — там текст последней ошибки MySQL, а $wpdb->last_query содержит сам SQL. Для записи методы insert, update, delete возвращают false при ошибке и число затронутых строк при успехе; ноль затронутых строк — это не ошибка, а совпадение данных.
Замедляет ли сайт использование $wpdb?
Сама по себе — нет, но прямые запросы не кэшируются WordPress, поэтому тяжёлая выборка на каждой странице заметно грузит базу. Кэшируйте результат через wp_cache_get и wp_cache_set, делайте массовые операции одним запросом вместо цикла и не выполняйте счётчики по большим таблицам в шаблоне сайта.
Что лучше: $wpdb или WP_Query?
По умолчанию — WP_Query: он учитывает кэш, хуки и права, и его достаточно для большинства выборок записей. $wpdb берите для задач, которые WP_Query не решает: объединение таблиц, GROUP BY, запросы к своим таблицам, массовые обновления. Грубое правило: если запрос можно выразить параметрами WP_Query — пишите WP_Query.
Вывод
$wpdb — это контролируемый спуск на уровень ниже стандартного API WordPress: с подготовленными запросами и методами insert, update, delete он безопасен и открывает возможности, которых нет у WP_Query, — от сложных JOIN до массовых обновлений и работы с таблицами плагина.
Правила простые: переменные — только через prepare, таблицы — только через свойства $wpdb, массовые операции — одним запросом, тяжёлые выборки — с кэшем, а перед любой прямой записью — свежий бэкап. Тогда прямой SQL становится точным инструментом, а не источником рисков.
Если нужно доработать сайт: написать сложные выборки, ускорить тяжёлые запросы или сделать плагин со своими таблицами — эту задачу можно передать одной команде. Мы работаем с базой WordPress аккуратно: с бэкапами, тестами и проверкой на реальных данных. Посмотрите услуги разработки и продвижения сайтов, изучите портфолио выполненных проектов и почитайте блог о WordPress и продвижении. Опишите задачу через форму контактов — предложим решение и рассчитаем стоимость.



