Схема базы данных
Типы контента в WordPress
Детали таблицы
Связь контента и таблиц базы данных
Класс базы данных WordPress
Использование $wpdb
Создание своего подключения к базе данных
query — произвольный запрос к Базе Данных WordPress
get_var — получение определенной ячейки таблицы
get_row — выбор строки таблицы
get_col — выбор столбца таблицы
get_results — выборка комбинированных результатов
insert — вставка новой записи (строки) в таблицу
update — обновление записи (строки) в таблице
delete — удаление строки из таблицы
prepare — защита запроса от SQL инъекций
Другие способы очистить запрос
(show/hide/print)_error — показать или спрятать ошибки SQL
get_col_info — получить информацию о колонке
flush — сброс кэша
Свойства (переменные) класса
Функции SQL
Пример работы с базой данных в плагине
Понимание и работа с данными в WordPress.
Табличная структура WordPress весьма единообразна. Каждая таблица в базе данных содержит уникальное поле с ID, являющееся главным ключом к таблице, а также один или более индексов в полях, что улучшает скорость возврата данных при выполнении запросов. Есть только одно предупреждение, касающееся редакций, приложений и пользовательских типов записей. Любая единица этой информации сохраняется как новая запись в таблице wp_posts и получает уникальный ID. Это означает, что ID
публикуемых записей могут отличаться друг от друга более чем на единицу. Например, у первой записи может быть ID 1, тогда как у второй — 15. Все зависит от того, как много дополнительной информации было добавлено между записями.
Типы контента в WordPress
Прежде чем разбирать данные хранящиеся в базе WordPress, рассмотрим типы контента. Существуют такие стандартные типы контента:
- Записи (posts)
- Страницы (pages)
- Пользовательские типы записей (custom post types)
- Вложения (attachments)
- Ссылки (links)
- Элементы меню (navigation menu items)
Эти типы контента имеют такие данные контента:
- Категории (categories)
- Метки (tags)
- Пользовательские таксономии (custom taxonomies and terms)
- Метаданные (post metadata)
Кроме того существует типы контента, хранящиеся в ином виде:
- Виджеты (widgets)
- Опции (options)
- Пользователи (users)
- Сайты для MU WordPress
- Нестандартный контент (hardcoded content), который добавляют некоторые темы/плагины.
- Сторонний контент (third party content) (например RSS)
Все эти типы контента хранятся в таблицах базы данных или в файлах настроек тем/плагинов. Каждый тип может быть представлен как отдельной записью в таблице, так и её частью. Кроме, того они могут быть связаны с данными в других таблицах. Например, данные о записях связаны с данными о пользователях, так что WordPress знает, кто является автором, какой записи.
| Таблица | Данные | Связи с другими таблицами |
| wp_posts | Содержит записи всех типов Записи, страницы, вложения, редакции, пользовательские записи | wp_postmeta через post_id
wp_term_relationships через post_id |
| wp_postmeta | Метаданные записей, страниц и т.д. (произвольные поля). | wp_posts через post_id |
| wp_comments | Комментарии которые подключаются к записи по ее ID. | wp_posts через post_id |
| wp_commentmeta | Метаданные комментариев | wp_comments через comment_id |
| wp_term_relationships | Связи между таксономиями и записями, страницами и т.д. соединяет элементы таксономии с контентом, создавая таблицу принадлежности. Отображает такие элементы, как название метки или категории, для соответствующей страницы или записи. | wp_posts через post_id
wp_term_taxonomy через term_taxonomy_id |
| wp_term_taxonomy | Таксоном Эта таблица позволяет иметь категории и метки с одинаковыми названиями, помещая их в разные таксономии (включая категории и метки) | wp_term_relationships через term_taxonomy_id |
| wp_terms | Ваши категории, метки и термины пользовательских таксономий
содержит все элементы таксономии, определенные для веб-сайта, |
wp_term_taxonomy через term_id |
| wp_links | Ссылки в вашем блоке (как правило, сейчас не используется) | wp_term_relationships через link_id |
| wp_users | Пользователи (имя пользователя, пароль, электронный адрес). | wp_posts через post_author |
| wp_user_meta | Метаданные для каждого пользователя (имя/фамилия, псевдоним, уровень пользователя и т. д.). | wp_users через user_id |
| wp_options | Опции и настройки сайта
(устанавливаются в админке на странице настроек и в темах/плагинах) |
Отсутвуют |
- Таблицы базы данных по умолчанию имеют префикс wp_. Вы можете его изменить (например, при установке).
- Таблица wp_posts является самой важно. Именно в ней храниться большинство данных.
- Только одна таблица не связана с другими — таблица wp_options. В ней хранятся данные о сайте и настройках WordPress, которые не имеют отношения к записям или пользователям.
- Две таблицы используются для хранения данных о таксономии.
- В таблицах wp_users и wp_comments данные не связаны. В настройках WordPress можно указать, что только зарегистрированные пользователи могут оставить комментарий. Не смотря на это, WordPress не хранит связи о комментариях и пользователе, который их отправил.
- WordPress MU иметь некоторые дополнительные таблицы.
Связь контента и таблиц базы данных
Ознакомившись с типами контента в WordPress и таблиц базы данных, используемых для их хранения, можно провести между ними соответствие. В приведенном ниже перечне показано, какие таблицы базы данных используется для хранения какого типа контента.
| Тип контента | Таблица |
| Записи (posts) | wp_posts |
| Страницы (pages) | wp_posts |
| Пользовательские типы записей (custom post types) | wp_posts |
| Вложения (attachments) | wp_posts |
| Ссылки (links) | wp_links |
| Элементы меню (navigation menu items) | wp_posts |
| Категории (categories) | wp_terms |
| Метки (tags) | wp_terms |
| Пользовательские таксономии (custom taxonomies) | wp_term_taxonomy |
| Термины пользовательских таксономий (custom terms) | wp_terms |
| Метаданные (post metadata) | wp_postmeta |
| Виджеты (widgets) | wp_options |
| Опции (options) | wp_options |
| Пользователи (users) | wp_users |
| Нестандартный контент (hardcoded content) | wp_posts (если добавлен к записям)
wp_options (если добавлен к виджетам) Файлы тем/плагинов |
| Сторонний контент (third party content) | wp_posts (если добавлен к записям)
wp_options (если добавлен к виджетам) Файлы тем/плагинов |
Класс базы данных WordPress
В WordPress есть один класс объекта с функциями для работы непосредственно
в базе данных. Этот класс базы данных называется wpdb и располагается в wp-includes/wp-db.php. Каждый раз, когда вы запрашиваете базу данных WordPress с помощью кода РНР, вы используете класс wpdb. Основная причина для использования этого класса — возможность выполнения WordPress ваших запросов
максимально безопасным способом.
Хуки из класса:
Возвращает: Экземпляр класса.
Использование $wpdb
Методы класса wpdb() не должны вызываться напрямую
WordPress предоставляет глобальную переменную, $wpdb, которая является экземпляром уже настроенного класса для обращения с базами данных WordPress. Всегда используйте глобальную переменную $wpdb. (Не забудьте про глобализацию $wpdb когда используете её в каких либо пользовательских функциях)
Объект $wpdb может обращаться с любым количеством таблиц, но только одной базой данных — базой данных WordPress. В редких случаях, если вам понадобится подключится к другой базе данных, вам придется создать экземпляр нового объекта из класса wpdb с соответствующими подробностями соединения для пользовательской базы данных. Для чрезвычайно сложных установок с множеством баз данных, рассмотрите возможность использования hyperdb
Создание своего подключения к базе данных
Нужно понимать, что один объект класса wpdb{} работает с одной БД — с текущей базой данных WordPress. Если нужно работать параллельно с какой-либо другой БД, то нужно создать еще один объект класса wpdb с указанием новых параметров соединения, отличных от тех что указаны в wp-config.php. Делается это так:
global $wpdb2;
$wpdb2 = new wpdb( ‘имя_пользователя БД’, ‘пароль БД’, ‘название БД’, ‘localhost’ );
// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if( ! empty($wpdb2->error) ) wp_die( $wpdb2->error );
// Готово, теперь используем функции класса wpdb
$results = $wpdb2->get_results(«SELECT * FROM table»);
Для сложных соединений с несколькими БД (репликами), есть хороший плагин, который рекомендуют разработчики WP — hyperdb. Этот плагин расширяет возможности базового класса wpdb. Устанавливается он не как обычный плагин и требует определенных знаний работы с базами данных (в противном случае, толку от этого плагина не будет)
query — произвольный запрос к Базе Данных WordPress
Позволяет выполнять любые запросы к базе данных WordPress. В общем случае, она подразумевает выполнение не SELECT запросов, хотя и они могут также выполняться (но для них существуют $wpdb->get_results и другие функции см. ниже).
Возвращает
Число/false. Вернет количество строк, которые были задействованы в результате запроса (удалены/изменены/выбраны). Если запрос вызвал ошибку, то будет возвращено значение false
global $wpdb;
$wpdb->query(‘query’);
Имейте ввиду, что как и для всех функций класса wpdb, передаваемые параметры нужно очистить от SQL инъекций, сделать это можно двумя способами: esc_sql($user_entered_data_string) или $wpdb->prepare( ‘query’ , value_parameter[, value_parameter … ] ). Подробнее читайте Защита запросов от SQL инъекций.
Примеры
#1. Удалить произвольное поле ‘gargle’ и его значение у поста 13
global $wpdb;
$wpdb->query(«DELETE FROM $wpdb->postmeta WHERE post_id = ’13’ AND meta_key = ‘gargle'»);
#2. Установить родительскую страницу 7 для страницы 15
global $wpdb;
$wpdb->query(«
UPDATE $wpdb->posts SET post_parent = 7
WHERE ID = 15 AND post_status = ‘static'»);
get_var — получение определенной ячейки таблицы
Получает значение первой колонки и первой строки из результата запроса.
Чтобы получить значение второй ячейки из второй строки результата, используйте второй и третий параметры: $column_offset = 1, $row_offset = 1.
Возвращает Значение колонки: число, строку, дату и т.д.
- Если запрос получает значение одной колонки, то функция вернет это значение (без всяких массивов).
- Если запрос получает одну строку и несколько колонок, то функция вернет значение первой колонки (ячейки).
- Если запрос получает несколько строк и колонок, то вернется значение первой строки первой колонки.
- Вернет NULL, если результата нет.
global $wpdb;
$wpdb->get_var(‘query’, $column_offset, $row_offset );
query(строка) Запрос который нужно выполнить. Можно установить этот параметр в значение null, тогда функция вернет результат последнего запроса, который был выполнен классом (сохраняется в переменной)
column_offset(число) Нужная колонка (отступ по колонкам). по умолчанию 0 — первая колонка
row_offset(число) Нужная строка (отступ по строкам). по умолчанию 0 — первая строка
Примеры
#1. Выведем на экран количество пользователей
$user_count = $wpdb->get_var($wpdb->prepare(«SELECT COUNT(*) FROM $wpdb->users;»));
echo ‘<p>Количество пользователей равно: ‘ . $user_count . ‘</p>’;
#2. Выведем на экран количество определенных произвольных полей
// определяем произвольный ключ, который нужно посчитать
$meta_key = ‘miles’;
$allmiles=$wpdb->get_var($wpdb->prepare(«SELECT sum(meta_value) FROM $wpdb->postmeta WHERE meta_key = %s», $meta_key));
echo ‘<p>Общее количество произвольных полей miles: ‘.$allmiles . ‘</p>’;
#3. Набор выводов статистики блога
### Общее Количество авторов блога
function get_totalauthors() {
global $wpdb;
$totalauthors = intval($wpdb->get_var(«SELECT COUNT(ID) FROM $wpdb->users LEFT JOIN $wpdb->usermeta ON $wpdb->usermeta.user_id = $wpdb->users.ID WHERE $wpdb->users.user_activation_key = » AND $wpdb->usermeta.meta_key = ‘».$wpdb->prefix.»user_level’ AND (meta_value+0.00) > 1″));
return $totalauthors;
}
### Общее Количество постов
function get_totalposts() {
global $wpdb;
$totalposts = intval($wpdb->get_var(«SELECT COUNT(ID) FROM $wpdb->posts WHERE post_type = ‘post’ AND post_status = ‘publish'»));
return $totalposts;
}
### Общее Количество страниц
function get_totalpages() {
global $wpdb;
$totalpages = intval($wpdb->get_var(«SELECT COUNT(ID) FROM $wpdb->posts WHERE post_type = ‘page’ AND post_status = ‘publish'»));
return $totalpages;
}
### Общее Количество комментариев
function get_totalcomments() {
global $wpdb;
$totalcomments = intval($wpdb->get_var(«SELECT COUNT(comment_ID) FROM $wpdb->comments WHERE comment_approved = ‘1’»));
return $totalcomments;
}
### Общее Количество комментаторов
function get_totalcommentposters() {
global $wpdb;
$totalcommentposters = intval($wpdb->get_var(«SELECT COUNT(DISTINCT comment_author) FROM $wpdb->comments WHERE comment_approved = ‘1’ AND comment_type = »»));
return $totalcommentposters;
}
### Общее Количество ссылок
function get_totallinks() {
global $wpdb;
$totallinks = intval($wpdb->get_var(«SELECT COUNT(link_id) FROM $wpdb->links»));
return $totallinks;
}
get_row — выбор строки таблицы
Получает одну строку таблицы в виде объекта. Если результат запроса содержит больше одной строки, то функция получит только первую строку результата. Чтобы получить вторую строку из запроса, укажите параметр $row_offset = 1.
Возвращает
Объект/массив/null. Вернет null, если не удалось получить данные.
global $wpdb;
$wpdb->get_row(‘query’, $output_type, $row_offset); //’query’ — запрос который нужно выполнить
output_type
Одна из трех констант. по умолчанию OBJECT. Может быть:
- OBJECT — результат будет возвращен в виде объекта.
- ARRAY_A — результат будет возвращен в виде ассоциативного массива.
- ARRAY_N — результат будет возвращен в виде пронумерованного массива.
row_offset(число)
Номер возвращаемой строки результата запроса. 0 — это первая строка (установлено по умолчанию)
Примеры
#1. Получим всю информацию о ссылке 10
global wpdb;
$mylink = $wpdb->get_row(«SELECT * FROM $wpdb->links WHERE link_id = 10»);
// Теперь, свойства (переменные) $mylink — это названия
//колонок из таблицы $wpdb->links со значениями полей таблицы:
echo $mylink->link_id; // выведет на экран «10»
#2. С использованием константы:
global wpdb;
$mylink = $wpdb->get_row(«SELECT * FROM $wpdb->links WHERE link_id = 10», ARRAY_A);
// результатом будет ассоциативный массив
echo $mylink[‘link_id’]; // выведет на экран «10»
или
$mylink = $wpdb->get_row(«SELECT * FROM $wpdb->links WHERE link_id = 10», ARRAY_N);
// результатом будет пронумерованный массив
echo $mylink[1]; // выведет на экран»10″
get_col — выбор столбца таблицы
Функция выбирает данные целой колонки таблицы и возвращает их в виде одномерного массива.
Если запрос вернул больше чем одну колонку (столбец), то функция вернет только данные первого столбца, остальное можно будет получить из переменной last_result. Можно указать отступ в $column_offset, чтобы получить данные не первого столбца, а, например, второго: $column_offset = 1.
Массив с данными запроса. Пустой массив, если не удалось получить данные.
$wpdb->get_col( $query, $column_offset );
$query — запрос который нужно выполнить, можно установить этот параметр в значение null, тогда функция вернет результат последнего запроса, который был произведен
$column_offset(число)
Флаг указывающий какую колонку возвращать. По умолчанию 0 (первая колонка).
Список постов которые имеют определенное произвольное поле (Color), но отсортированы они по значению другого произвольного поля (Display_Order).
global wpdb;
$meta_key1 = ‘Color’;
$meta_key2 = ‘Display_Order’;
$postids = $wpdb->get_col($wpdb->prepare(«
SELECT key1.post_id
FROM $wpdb->postmeta key1
INNER JOIN $wpdb->postmeta key2
on key2.post_id = key1.post_id
and key2.meta_key = %s
WHERE key1.meta_key = %s
ORDER BY key2.meta_value+(0) ASC»,
$meta_key2,$meta_key1));
if ($postids) {
echo ‘List of ‘. $meta_key1 . ‘ posts, sorted by ‘ . $meta_key2 ;
foreach ($postids as $id) {
$post=get_post(intval($id));
setup_postdata($post);?>
<p><a href=»<?php the_permalink() ?>» rel=»bookmark» title=»Permanent Link to <?php the_title_attribute(); ?>»><?php the_title(); ?></a></p>
<?php }}
get_results — выборка комбинированных результатов
Различные данные из нескольких строк таблицы могут быть получены при использовании метода get_results. Функция возвращает результат запроса в массиве, каждый элемент которого представляет собой результат функции get_row, т.е. в каждом элементе массива находятся все запрашиваемые данные одной строки.
Возвращает массив/объект/null.
- Результат запроса в виде массива объектов (OBJECT, OBJECT_K), массива массивов (ARRAY_A, ARRAY_N).
- Вернет пустой массив: array() — когда строк по запросу не найдено или ошибка запроса.
- Вернет NULL — когда запрос пустая строка или передан неправильный тип вывода ($output_type).
$wpdb->get_results(‘query’, output_type);
query(строка) — запрос который нужно выполнить, можно установить этот параметр в значение null, тогда функция вернет результат последнего запроса, который был произведен.
output_type(строка)
Флаг указывающий как нужно вернуть данные. По умолчанию OBJECT. есть 4 варианта:
- OBJECT — вернет массив объектов с числовыми ключами — элементы массива будут объекты полученных данных.
- OBJECT_K — похож на предыдущий, только в индексах главного массива будут значения первой колонки результата запроса. При этом обратите внимание, что если в индекс будут попадать одинаковые значения, то данные будут стирать друг друга…
- ARRAY_A — вернет нумерованный двумерный массив, каждый вложенный элемент которого будет ассоциативным массивом, в котором ключом будет название колонки.
- ARRAY_N — вернет нумерованный двумерный массив, каждый вложенный элемент которого будет так же нумерованным массивом.
Пример
#1. Получим ID и заголовки черновиков, ID автора которых равен 5 и выведем на экран заголовки постов.
global wpdb;
$fivesdrafts = $wpdb->get_results(«SELECT ID, post_title FROM $wpdb->posts
WHERE post_status = ‘draft’ AND post_author = 5″);
foreach ($fivesdrafts as $fivesdraft) {
echo $fivesdraft->post_title; }
insert — вставка новой записи (строки) в таблицу
Вставляет указанные данные в указанную таблицу.
$wpdb->insert() включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET[‘foo’]…
Возвращает
true/false.
true — при успешной записи данных;
false — если данные не были вставлены в таблицу.
После добавления данных созданное значение AUTO_INCREMENT можно получить в переменной: $wpdb->insert_id
$wpdb->insert( $table, $data, $format );
table(строка) — название таблицы в которую будем вставлять данные.
data(строка) — данные которые нужно вставить (‘колонка куда вставлять’ => ‘что вставлять’).
format(строка) — формат данных который будет ассоциирован с указанными значениями в параметре $data, если не указать, то для всех значений $data будет указан формат строки. Возможные форматы данных:
%s — строка;
%d — целое число
%f — дробное число.
При указании формата, WordPress переводит переданные данные в указанный формат перед тем, как сохранить данные в базу данных
Пример
#1. Вставим в значение в строку таблицы table, где первое значение строка, а второе число:
$wpdb->insert(
‘table’,
array( ‘column1’ => ‘value1’, ‘column2’ => 123 ),
array( ‘%s’, ‘%d’ ))
update — обновление записи (строки) в таблице
Возвращает
Число (кол-во обраб. строк), 0 или false.
- число — сколько строк было обработано
- 0 — запрос был выполнен корректно, но ни одна строка не была обработана.
- false — запрос провалился или ошибка запроса.
Так как возвращается 0, если никакие поля не были обновлены (изменены), но запрос был выполнен корректно, проверку результата запроса на ошибку нужно делать с учетом типа возвращаемых данных $res === false.
$wpdb->update() включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET[‘foo’]…
$wpdb->update( $table, $data, $where, $format = null, $where_format = null );
table(строка) — название таблицы которую нужно обновить.
data(массив) — данные которые нужно обновить (‘название колонки’ => ‘новое значение’).
where(массив) — ассоциированный массив с условием для замены (WHERE) ( ‘название колонки’ => ‘чему равно’).
format(массив/строка) — формат данных который будет ассоциирован с указанными значениями в параметре $data.
where_format(массив/строка) — формат данных который будет ассоциирован с указанными значениями в параметре $where. Возможные значения формата: %s — строка; %d — любое число; %f — FLOAT число. Если не указать формат, то все значения в WHERE будут обработаны как строки.
Примеры
#1. Обновим строку ID которой равен 1
Значение первой колонки строка, значение второй колонки число:
$wpdb->update( ‘table’,
array( ‘column1’ => ‘value1’, ‘column2’ => $_GET[‘val’] ),
array( ‘ID’ => 1 ));
#2. Тоже самое с указанием типов передаваемых данных
$wpdb->update( ‘table’,
array( ‘column1’ => ‘value1’, ‘column2’ => $_GET[‘val’] ),
array( ‘ID’ => 1 ),
array( ‘%s’, ‘%d’ ),
array( ‘%d’ ));
delete — удаление строки из таблицы
Удаляет строки из таблицы по переданному в параметр $where условию.
$wpdb->delete() включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET[‘foo’]…
Возвращает
Число/false. Число удаленных строк или false
$wpdb->delete( $table, $where, $where_format = null );
$table(строка) (обязательный)- название таблицы.
$where(массив) (обязательный) — массив условий, по которым будут выбираться строки для удаления, например: array(‘id’ => 25, ‘title’ => ‘книги’) удалит строку с полями id=25 и title=книги
$where_format(строка/массив) — формат данных который будет ассоциирован с указанными значениями в параметре $where. Возможные значения формата: %s — строка; %d — любое число; %f — FLOAT число. Если не указать формат, то все значения в WHERE будут обработаны как строки. По умолчанию: null
Примеры
// Удалим строку с полем ID=1 из таблицы table
$wpdb->delete( ‘table’, array( ‘ID’ => 1 ) );
// Укажем формат значения $where
$wpdb->delete( ‘table’, array( ‘ID’ => ‘1’ ), array( ‘%d’ ) );
prepare — защита запроса от SQL инъекций
В SQL есть такое понятие как «внедрение в запрос SQL кода«, сделать это можно когда в запрос передаются динамические данные. Например, в запрос передаются значение input полей формы, тогда в поле формы можно указать данные, которые в итоге станут частью SQL запроса. Так можно внедриться в запрос и что-нибудь испортить или просто нарушить код самого запроса. Выглядит это примерно так:
SELECT * FROM table WHERE id = ‘$var’
// если $var будет равно например «2′ AND id = (DROP TABLE table2)»
// то у получиться
SELECT * FROM table WHERE id = ‘2’ AND id = (DROP TABLE table2)’
Таким образом можно внедриться в сам запрос и изменить его.
Чтобы этого не произошло запросы с передаваемыми в них переменными нужно обрабатывать методом wpdb::prepare():
$sql = $wpdb->prepare( ‘query’ [ parameter1, parameter2 … ] );
query(строка)
Запрос. В нем можно использовать заменители:
- %d — число
- %s — строка
- %f — дробное число (число с плавающей точкой, с версии 3.3).
Использование знака % в любых других случаях может вызывать ошибку, поэтому его нужно претворять еще одним %. Например, чтобы использовать команду LIKE %вхождение%, ее нужно записать так: LIKE %%вхождение%%.
Также можно указывать все холдеры из функции sprintf(). Но делать это надо аккуратно. Например, это может быть удобно тут:
$wpdb->prepare(‘SELECT * FROM table WHERE field = %1$d OR field2 = %1$d’, 2 );
//> SELECT * FROM table WHERE field = 2 OR field2 = 2
Но для строк в таком случае крайние скобки не ставятся, из нужно ставить в самом запросе:
$wpdb->prepare(‘SELECT * FROM table WHERE field = «%1$s» OR field2 = «%1$s»‘, ‘»str’ );
//> SELECT * FROM table WHERE field = «\»str» OR field2 = «\»str»
parameter(строка/массив)
Переменные, которые относятся к заменителям. Считаются слева направо. Переменные можно указать через запятую, как в php функции sprintf() или во втором параметре можно передать массив для замены.
Заметка: с версии WP 3.5 wpdb::prepare() обязательно должны быть переданы минимум 2 параметра: запрос и значение переменной, иначе появится php ошибка.
Примеры
#1. Добавим произвольное поле к посту 10:
$metakey = «‘крах’ БД»;
$metavalue = «WordPress может ‘сломать’ Базу Данных если не экранировать запрос.»;
$wpdb->query(
$wpdb->prepare(
«INSERT INTO $wpdb->postmeta ( post_id, meta_key, meta_value ) VALUES ( %d, %s, %s )»,
10, $metakey, $metavalue ) );
Как видно из примера, с prepare() нет необходимости заботиться об экранировании кавычек и прочего, что может навредить запросу.
#2. Такой же пример
Только тут все переменные передаются во втором параметре в виде массива:
$metakey = «‘крах’ БД»;
$metavalue = «WordPress может ‘сломать’ Базу Данных если не экранировать запрос.»;
$wpdb->query(
$wpdb->prepare(
«INSERT INTO $wpdb->postmeta ( post_id, meta_key, meta_value ) VALUES ( %d, %s, %s )»,
array(10, $metakey, $metavalue) ));
Передавать параметры в виде массива, может быть полезно, когда мы заранее не знаем количество аргументов, которые нужно будет передать.
Другие способы очистить запрос:
esc_sql()
Также, для очистки запроса можно обработать каждую переменную отдельно, нужно обрабатывать функцией esc_sql().
$name = esc_sql( $name );
$status = esc_sql( $status );
$wpdb->get_var( «SELECT something FROM table WHERE foo = ‘$name’ and status = ‘$status'» );
$wpdb->prepare() предпочтительнее чем esc_sql(), т.к. она исправляет некоторые ошибки форматирования.
wpdb->esc_like()
Чтобы подготовить строку для использования в LIKE части SQL запроса, используйте $wpdb->esc_like( $text ):
global $wpdb;
$link = $wpdb->esc_like( $link ); // подготовим строку для LIKE аргумента
$link = esc_sql( $link ); // очистим переменную
$link = ‘%’ . $link . ‘%’; // создадим полную переменную поиска LIKE
// найдем комментарии в тексте или ссылке автора, есть указанная ссылка
$spammy = $wpdb->query(«SELECT comment_approved FROM $wpdb->comments
WHERE (comment_content LIKE ‘$link’ OR comment_author_url LIKE ‘$link’)
AND comment_approved = ‘spam’ LIMIT 1;»);
(show/hide/print)_error — показать или спрятать ошибки SQL
Есть возможность управлять ошибками, включать или выключать показ ошибок для последнего запроса:
$wpdb->show_errors(); // включит показ ошибок
$wpdb->hide_errors(); // выключит показ ошибок
Также можно вывести на экран саму ошибку, если таковая имеется:
$wpdb->print_error();
get_col_info — получить информацию о колонке
Есть возможность узнать информацию о колонках последнего запроса, для этого нужно использовать метод get_col_info. Это может пригодится, когда был возвращен объект, о данных которого мы ничего не знаем. Функция вернет массив с информацией об определенных в запросе колонках. Если в запросе колонки не определены, то функция вернет информацию о всех колонках таблицы.
$wpdb->get_col_info( $type, $offset );
$type(строка) — в этом параметре указывается какую информацию нам нужно получить. По умолчанию: name. Вот список возможных вариантов:
- name — название колонки.
- table — название таблицы к которой принадлежит колонка.
- max_length — максимальная длинна данных колонки
- not_null — 1 если ячейка колонки не может принимать значение NULL
- primary_key — 1 если колонка является первичным ключом
- unique_key — 1 если ячейки колонки должны быть всегда уникальны
- multiple_key — 1 если ячейки колонки могут быть не уникальны
- numeric — 1 если колонка содержит числовые данные
- blob — 1 если колонка содержит данные типа BLOB (двоичные данные)
- type — тип колонки
- unsigned — 1 если колонка имеет тип данных UNSIGNED
- zerofill — 1 если колонка имеет тип данных ZEROFILL
По умолчанию: name
$offset(число) — указатель, информацию о какой колонке нужно получить:
Если указать -1, то будут получена информация о всех колонках в виде массива. По умолчанию.
Если указать 0 или больше то будет возвращена информация об указанной колонке, где 0 — первая колонка, 1 — вторая и т.д.
По умолчанию: -1
flush — сброс кэша
Можно сбросить последние сохраненные данные в свойствах класса:
$wpdb->flush();
Эта команда очистит следующие свойства (переменные): $wpdb->last_result, $wpdb->last_query и $wpdb->col_info
Свойства (переменные) класса
$show_errorr — показывать ошибки или нет, когда возвращается результат, по умолчанию (true)
$suppress_errors — подавлять ли ошибки в процессе построения запроса
$last_error — последняя ошибка из любого запроса
$num_queries — количество запросов которые выполняются
$num_rows — количество строк возвращенных последним запросом
$rows_affected — сохраняет число задействованных строк из последнего запроса
$insert_id — идентификатор (ID) сгенерированный последним запросом, для SQL параметра AUTO_INCREMENT
$last_query — последний запрос, который был выполнен классом
$last_result — результат последнего запроса
$func_call — текстовое описание последнего вызова query/get_row/get_var
$queries — можно сохранить все запросы которые были сделаны к БД и их время выполнения, для этого нужно определить константу SAVEQUERIES как TRUE (например в config.php). По умолчанию она выключена (false). После того как эта константа включена в эту переменную будут собираться все запросы в виде массива данных
$col_info — информация о колонках последнего запроса
$prefix — префикс таблиц БД определенный для WordPress. Может пригодиться для мульти-сайтов
$base_prefix — префикс базовой таблицы WordPress. В мультисайте для сайтов сети префик отличается. Тут храниться префикс таблиц основного сайта сети
$ready — логический (готов ли класс к выполнению запросов)
$blogid — идентификатор текущего блога
$siteid — ID сайта
$tables — список названий таблиц сайта (без префикса)
$global_tables — глобальные таблицы: ‘users’, ‘usermeta’
$ms_global_tables — глобальные таблицы в режиме MU: ‘blogs’, ‘signups’, ‘site’, ‘sitemeta’, ‘sitecategories’, ‘registration_log’, ‘blog_versions’
$collate — режим сопоставления (сравнивания) данных в колонках базы данных
Функции SQL
Создает или изменяет таблицы базы данных на основе переданного SQL запроса на создание таблицы.
Подготавливает строку к использованию в SQL запросе. Защищает от SQL инъекций.
По переданным параметрам создает JOIN и WHERE части SQL запроса для метаданных, которые можно использовать в основном запросе.
Получает количество запросов которое было сделано к базе данных WordPress до момента вызова этой функции.
Функция вернет WHERE часть SQL запроса, в котором будет учитываться статус записи ‘private’ для авторизованных пользователей.
Проверяет можно ли использовать переданную строку в ORDER BY части SQL запроса.
Пример работы с базой данных в плагине
Для примера создадим гостевую книгу. Начнём с создания таблицы, в которой будут храниться данные нашей гостевой книги. Будем спрашивать у пользователя имя и комментарий.
Поля таблицы:
- id
- date_add
- user_name
- message
Для работы с данными таблицы создадим в разделе меню нашего плагина страницу с названием Гостевая книга. Для этого пункта меню создадим класс includes\controllers\admin\menu\StepByStepGuestBookSubMenuController
namespace includes\controllers\admin\menu;
class StepByStepGuestBookSubMenuController {}
Наследует StepByStepGuestBookSubMenuController
Класс StepByStepGuestBookSubMenuController наследует StepByStepGuestBookSubMenuController
<?php
/**
* Created by PhpStorm.
* User: solomashenko
* Date: 16.02.17
* Time: 15:42
*/
namespace includes\controllers\admin\menu;
class StepByStepGuestBookSubMenuController extends StepByStepBaseAdminMenuController
{
public function action()
{
// TODO: Implement action() method.
}
public function render()
{
// TODO: Implement render() method.
}
public static function newInstance()
{
// TODO: Implement newInstance() method.
} }
Добавление пункта меню
<?php
namespace includes\controllers\admin\menu;
class StepByStepGuestBookSubMenuController extends StepByStepBaseAdminMenuController
{
public function action()
{
// TODO: Implement action() method.
//Добавление пункта меню
$pluginPage = add_submenu_page(
STEPBYSTEP_PlUGIN_TEXTDOMAIN,
_x(
‘Guest book’,
‘admin menu page’ ,
STEPBYSTEP_PlUGIN_TEXTDOMAIN
),
_x(
‘Guest book’,
‘admin menu page’ ,
STEPBYSTEP_PlUGIN_TEXTDOMAIN
),
‘manage_options’,
step_by_step_control_guest_book_menu,
array(&$this, ‘render’)); }
public function render()
{
// TODO: Implement render() method.
}
public static function newInstance()
{
// TODO: Implement newInstance() method.
$instance = new self;
return $instance; } }
Подключение контроллера в StepByStepLoader
Чтобы пункт меню добавился в раздел плагина нам нужно создать экземпляр класса контроллера в методе admin класса StepByStepLoader.
<?php
namespace includes\common;
use includes\controllers\admin\menu\StepByStepGuestBookSubMenuController;
use includes\controllers\admin\menu\StepByStepMainAdminMenuController;
….
class StepByStepLoader
{
……
/**
* Метод будет срабатывать когда вы находитесь в Админ панеле. Загрузка классов для Админ панели
*/
public function admin(){
StepByStepMainAdminMenuController::newInstance();
StepByStepGuestBookSubMenuController::newInstance();
….
}
….
}
}
}
}
View для контроллера
Для контроллера создадим view файлик ответственный за отображения страницы. includes\views\admin\menu\StepByStepGuestBookSubMenu.view.php и подключим его в методе render контроллера.
public function render()
{
// TODO: Implement render() method.
//Данные которые будут передаваться в view
$data = array();
$pathView = STEPBYSTEP_PlUGIN_DIR.»/includes/views/admin/menu/StepByStepGuestBookSubMenu.view.php»;
$this->loadView($pathView, 0, $data);
}
Модель
Для работы с базой данных нам понадобиться модель. Создадим класс модель includes\models\admin\menu\StepByStepGuestBookSubMenuModel
namespace includes\models\admin\menu;
class StepByStepGuestBookSubMenuModel {}
Добавим методы в модель
<?php
/**
* Created by PhpStorm.
* User: solomashenko
* Date: 16.02.17
* Time: 16:08
*/
namespace includes\models\admin\menu;
class StepByStepGuestBookSubMenuModel
{
//Название таблицы
const STEPBYSTEP_TABLE_NAME = «step_by_step_guest_book»;
/**
* Возвращает название таблицы с префиксом WordPress тот что задаеться при установке
* всем таблицам
* @return string
*/
static public function getTableName(){
global $wpdb;
return $wpdb->prefix .static::STEPBYSTEP_TABLE_NAME;
}
/**
* Метод создание таблицы в базе данных
*/
static public function createTable()
{
global $wpdb;
$tableName = self::getTableName();
$sql = «CREATE TABLE » .$tableName. «(
id int(11) NOT NULL AUTO_INCREMENT,
date_add int(11) NOT NULL,
user_name varchar(255) NOT NULL,
message text NOT NULL,
PRIMARY KEY (id)
) CHARACTER SET utf8 COLLATE utf8_general_ci;»;
// Проверяем на наличие таблицы в базе данных и если ее нет то создаем
if($wpdb->get_var(«show tables like ‘$tableName'») != $tableName) {
require_once(ABSPATH . ‘wp-admin/includes/upgrade.php’);
dbDelta($sql); } }
/**
* Получает по ID строку в таблице
* @return mixed
*/
static public function getById($id){
global $wpdb;
$data = $wpdb->get_row(«SELECT * FROM «.self::getTableName().» WHERE id= «. $id, ARRAY_A);
if(count($data) > 0) return $data;
return false; }
/**
* Вставляет данные в таблицу
* @param $data
* @return mixed
*/
static public function insert($data){
global $wpdb;
$id = $wpdb->insert( self::getTableName(), $data);
return $id; }
/**
* Обновляет данные в таблице по ID
* @param $data
* @return mixed
*/
static public function updateById($data, $id){
global $wpdb;
$id = $wpdb->update(self::getTableName(), $data ,array(‘id’ => $id));
return $id; }
/**
* Удаляет данные в таблице по ID
* @param $id
* @return mixed
*/
static public function deleteById($id){
global $wpdb;
$wpdb->query(«DELETE FROM «.self::getTableName().» WHERE id = ‘».$id .»‘»);
}
/**
* Метод удаляет таблицу в базе данных
*/
static public function deleteTable()
{
global $wpdb;
$wpdb->query(«DROP TABLE IF EXISTS «.self::getTableName());
}
/**
* Метод получает все записи в таблице
* @return bool
*/
static public function getAll()
{
// TODO: Implement getAll() method.
if (self::issetTable() == false) return false;
global $wpdb;
$data = $wpdb->get_results( «SELECT * FROM «.self::getTableName().» ORDER BY date_add DESC», ARRAY_A);
if(count($data) > 0) return $data;
return false;
} }
Создание таблицы гостевой книги
При активации плагина создаем таблицу для гостевой книги в базе данных (используем метод createTable класса StepByStepGuestBookSubMenuModel).
Добавим вызов метода createTable в методе activation основного класса плагина
…….
use includes\models\admin\menu\StepByStepGuestBookSubMenuModel;
class StepByStepPlugin
{
…………………….
static public function activation()
{
StepByStepGuestBookSubMenuModel::createTable();
}
StepByStepGuestBookSubMenu.view.php
<!— Ссылка ссылаеться на страницу гостевой книги только у нее добавлен $_GET[‘action’] параметр &action=add_data
По этому параметру мы будем в методе render определять что делать
—>
<a href=»admin.php?page=step_by_step_control_guest_book_menu&action=add_data»>
<?php _e(‘Add’, STEPBYSTEP_PlUGIN_TEXTDOMAIN ); ?>
</a>
<table border=»1″>
<thead>
<tr>
<td>
<?php _e(‘Name’, STEPBYSTEP_PlUGIN_TEXTDOMAIN ); ?>
</td>
<td>
<?php _e(‘Messsage’, STEPBYSTEP_PlUGIN_TEXTDOMAIN ); ?>
</td>
<td>
<?php _e(‘Date’, STEPBYSTEP_PlUGIN_TEXTDOMAIN ); ?>
</td>
<td>
<?php _e(‘Actions’, STEPBYSTEP_PlUGIN_TEXTDOMAIN ); ?>
</td>
</tr>
</thead>
<tbody>
<!— Проверка данных на пустоту чтобы цыкл не вернул ошибку —>
<?php if(count($data) > 0 && $data !== false){ ?>
<?php foreach($data as $value): ?>
<tr class=»row table_box»>
<td>
<?php echo $value[‘user_name’]; ?>
</td>
<td>
<?php echo $value[‘message’]; ?>
</td>
<td>
<?php echo date(‘d-m-Y H:i’, $value[‘date_add’]); ?>
</td>
<td>
<!— Ссылки ссылаються на страницу гостевой книги только у них добавлен $_GET[‘action’] параметр
для редактирования &action=edit_data для удаления &action=delete_data и в этих ссылок еще добавлен
один $_GET[‘id’] параметр это &id=(id записи) записи гостевой книги по котором мы будем выполнять
действия —>
<a href=»admin.php?page=step_by_step_control_guest_book_menu&action=edit_data&id=<?php echo $value[‘id’];?>»>
<?php _e(‘Edit’, STEPBYSTEP_PlUGIN_TEXTDOMAIN ); ?>
</a>
<a href=»admin.php?page=step_by_step_control_guest_book_menu&action=delete_data&id=<?php echo $value[‘id’];?>»>
<?php _e(‘Delete’, STEPBYSTEP_PlUGIN_TEXTDOMAIN ); ?>
</a>
</td>
</tr>
<?php endforeach ?>
<?php }else{ ?>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<?php } ?>
</tbody>
</table>
StepByStepGuestBookSubMenuAdd.view.php
<!— View форма для добавления записи в таблицу. action формы это ссылка на страницу гостевой книги с $_GET[‘action’]
параметр &action=insert_data в методе render контроллера мы будем обрабатывать параметр $_GET[‘action’] —>
<form action=»admin.php?page=step_by_step_control_guest_book_menu&action=insert_data» method=»post»>
<input type=»text» name=»user_name»>
<textarea name=»message»></textarea>
<input type=»submit» name=»<?php _e(‘Add’, STEPBYSTEP_PlUGIN_TEXTDOMAIN ); ?>»>
</form>
StepByStepGuestBookSubMenuEdit.view.php
<!— View форма для редактирования записи в таблицу. action формы это ссылка на страницу гостевой книги с $_GET[‘action’]
параметр &action=update_data в методе render контроллера мы будем обрабатывать параметр $_GET[‘action’] update_data.
Эта форма похожая на форму StepByStepGuestBookSubMenuAdd.view.php только у ее полей ввода есть атрибут value со значением
записи в таблицы которую мы будем редактировать. И еще есть одно скрытое поле id по котором будем обновлять запись в таблице.
—>
<form action=»admin.php?page=step_by_step_control_guest_book_menu&action=update_data» method=»post»>
<input type=»text» name=»user_name» value=»<?php echo $data[‘user_name’]; ?>»>
<textarea name=»message»>
<?php echo $data[‘message’]; ?>
</textarea>
<!— Поле id по котором будем обновлять запись в таблице —>
<input type=»hidden» name=»id» value=»<?php echo $data[‘id’]; ?>»>
<input type=»submit» name=»<?php _e(‘Add’, STEPBYSTEP_PlUGIN_TEXTDOMAIN ); ?>»>
</form>
StepByStepGuestBookSubMenuController
<?php
namespace includes\controllers\admin\menu;
use includes\models\admin\menu\StepByStepGuestBookSubMenuModel;
class StepByStepGuestBookSubMenuController extends StepByStepBaseAdminMenuController
{
public function action()
{
// TODO: Implement action() method.
//Добавление пункта меню
$pluginPage = add_submenu_page(
STEPBYSTEP_PlUGIN_TEXTDOMAIN,
_x(
‘Guest book’,
‘admin menu page’ ,
STEPBYSTEP_PlUGIN_TEXTDOMAIN
),
_x(
‘Guest book’,
‘admin menu page’ ,
STEPBYSTEP_PlUGIN_TEXTDOMAIN
),
‘manage_options’,
‘step_by_step_control_guest_book_menu’,
array(&$this, ‘render’));
}
public function render()
{
// TODO: Implement render() method.
/*
В Гостевой книги может быть несколько view (Отображение данных таблицы,
Добавление данных в таблице, Редактирование данных в таблице,
Удаление данных с таблицы). Что бы определить контролеру какое действие в данный
момент обрабатывать к ссылке будет добляться $_GET[‘action’]. Мы его можем получить
и определить какой view подшружать странице.
*/
$action = isset($_GET[‘action’]) ? $_GET[‘action’] : null ;
//Данные которые будут передаваться в view
$data = array();
$pathView = STEPBYSTEP_PlUGIN_DIR;
/*
* Используем switch чтобы определить какой сейчас $_GET[‘action’]
*/
switch($action) {
// Подгружаем view для добавление данных в таблицу
// admin.php?page=step_by_step_control_guest_book_menu&action=add_data
case «add_data»:
$pathView .= «/includes/views/admin/menu/StepByStepGuestBookSubMenuAdd.view.php»;
$this->loadView($pathView, 0, $data);
break;
// Сохранение данных в таблицу
// admin.php?page=step_by_step_control_guest_book_menu&action=insert_data
case «insert_data»:
/*
* Проверяем наличие данных от формы StepByStepGuestBookSubMenuAdd.view.php
*/
if (isset($_POST)){
/*
* Передаем массив данных в метод insert модели.
* Массив ассоциативный ключ это название поля в таблице в которую мы будем вставлять,
* значение это значение которое будет вставлено определеному полю
*
*/
$id = StepByStepGuestBookSubMenuModel::insert(array(
‘user_name’ => $_POST[‘user_name’],
‘date_add’ => time(), // time() стандартная php функция получения времени
‘message’ => $_POST[‘message’]
));
/*
* После вставки возвращаемся на основную страницу гостевой книги
* admin.php?page=step_by_step_control_guest_book_menu
*/
$this->redirect(«admin.php?page=step_by_step_control_guest_book_menu»);
}
break;
// Подгружаем view для редактирование данных в таблицу
// admin.php?page=step_by_step_control_guest_book_menu&action=edit_data&id=ID записи
case «edit_data»:
/*
* Чтобы получить из таблицы запись которую редактировать мы используем $_GET[‘id’] параметр
* Проверяем его наличие и на пустоту
*/
if(isset($_GET[‘id’]) && !empty($_GET[‘id’])){
// Получаем данные записи в таблице по id затем эти данные передадим в view StepByStepGuestBookSubMenuEdit.view
$data = StepByStepGuestBookSubMenuModel::getById((int)$_GET[‘id’]);
$pathView .= «/includes/views/admin/menu/StepByStepGuestBookSubMenuEdit.view.php»;
$this->loadView($pathView, 0, $data);
}
break;
// Обновление редактированых данных в таблице
// admin.php?page=step_by_step_control_guest_book_menu&action=update_data
case «update_data»:
// Проверяем наличие $_POST данных от формы редактирования StepByStepGuestBookSubMenuEdit.view.php
//var_dump($_POST);
if (isset($_POST)){
// Если данные есть то обновляем их в базе данных по ID
StepByStepGuestBookSubMenuModel::updateById(
array(
‘user_name’ => $_POST[‘user_name’],
‘date_add’ => time(),
‘message’ => $_POST[‘message’]
), $_POST[‘id’]
);
$this->redirect(«admin.php?page=step_by_step_control_guest_book_menu»);
}
break;
// Удаление данных
// admin.php?page=step_by_step_control_guest_book_menu&action=delete_data&id=ID записи
case «delete_data»:
// Чтобы удалить определеную запись в таблице мы используем $_GET[‘id’] параметр
// Проверяем его наличие и на пустоту
if(isset($_GET[‘id’]) && !empty($_GET[‘id’])){
StepByStepGuestBookSubMenuModel::deleteById((int)$_GET[‘id’]);
}
$this->redirect(«admin.php?page=step_by_step_control_guest_book_menu»);
break;
// Основная страница Гостевой книги
// admin.php?page=step_by_step_control_guest_book_menu
default:
//Получение всех записей в таблице чтобы отобразить их view
$data = StepByStepGuestBookSubMenuModel::getAll();
$pathView .= «/includes/views/admin/menu/StepByStepGuestBookSubMenu.view.php»;
$this->loadView($pathView, 0, $data);
} }
/**
* Метод перенаправления на нужную страницу
* @param string $page
*/
public function redirect($page = »){
echo ‘<script type=»text/javascript»>
document.location.href=»‘.$page.'»;
</script>’;
}
public static function newInstance()
{
// TODO: Implement newInstance() method.
$instance = new self;
return $instance;
}
}



admin
— добавил таблицу в базу данных
— подключил виджет к базе данных
— подключил пример кода с созданием, редактированием и удалением записей в таблице базы данных sql через контроллер в админ меню Интеркасса -> Home Work Guest Book