Как настроить класс wpdb и добавить новые методы

Опубликовано: 2018-07-10

Уровень абстракции базы данных WordPress, более известный как wpdb, представляет собой класс, основанный на ezSQL, отвечающий за взаимодействие с базой данных. Класс wpdb также является вставкой — частью основного кода WP, которую можно легко заменить другой частью кода с аналогичной функциональностью (актуальный список вставок доступен в Справочнике по коду WP).

Изменить класс #wpdb по умолчанию несложно. Вы можете легко добавить, удалить или изменить только несколько методов. Нет необходимости заменять весь класс. #Вордпресс

НАЖМИТЕ, ЧТОБЫ НАПИСАТЬ

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

Зачем изменять класс wpdb?

Наверняка в wpdb есть все, что вам нужно!? Весь WP построен поверх него. Технически это правильно. Используя метод $wpdb->query() , вы можете выполнить любую команду SQL. Но с применением такой логики у нас никогда не было бы и не было необходимости в таких методах, как $wpdb->insert() или $wpdb->get_var() . Но мы это делаем, потому что они экономят время, уменьшают количество ошибок и устраняют плохие запросы. Итак, каких функций не хватает? Это зависит от проекта, над которым вы работаете. Нам нужна была поддержка для этих двух запросов:

INSERT IGNORE INTO tbl_name ...
INSERT INTO tbl_name ... ON DUPLICATE KEY UPDATE ...

Шаг № 1 — Создайте дроп-ин

Процесс создания дроп-ина БД прост, а конечный результат органично вписывается в WP.
Создайте файл с именем db.php и поместите его в папку /wp-content/ . Дайте файлу стандартный заголовок плагина и создайте класс, расширяющий wpdb. Что-то вроде этого:

<?php
/*
  Plugin Name: Extended wpdb
  Description: A few extra functions for wpdb
  Version: 1.0
  Author: WebFactory Ltd
*/

class wpdb_extended extends wpdb {

  public function __construct(){
    parent::__construct( DB_USER, DB_PASSWORD, DB_NAME, DB_HOST );
  }

  public function test() {
    echo 'Extended wpdb is running.';
  }
}


global $wpdb;
$wpdb = new wpdb_extended();

Заголовок довольно понятен. Метод построения гарантирует, что мы создадим новое соединение с БД после создания объекта, и для этого он использует исходный конструктор wpdb. Эти константы БД определены в wp-config.php . Как мы сказали в начале — мы просто добавляем некоторые функции и повторно используем все остальное. Второй метод test() предназначен исключительно для того, чтобы проверить, все ли работает правильно.

Последние две строки имеют решающее значение. Поскольку это пользовательский класс, WP не будет автоматически создавать для нас объект $wpdb . Мы должны сделать это сами. Не забудьте использовать ключевое слово global , иначе вы создадите локальную переменную.

Шаг № 2. Протестируйте, прежде чем копать глубже

Откройте панель управления WP и перейдите в раздел «Плагины». Помимо обычных вкладок All, Active и Inactive (плагины), вы увидите вкладку Drop-ins и в ней каким-то волшебным образом наш пользовательский класс базы данных.

Поскольку администратор работает нормально, мы знаем, что проделали хорошую работу. Наш новый, пользовательский, расширенный класс готов, и ничего не изменилось. Большой! Но на всякий случай поместите эти три строки кода в файл functions.php темы (или где-нибудь внутри плагина, где он сразу же запустится):

global $wpdb;
$wpdb->test();
die;

Запустите любую страницу администратора или внешнего интерфейса, и что вы увидите? « Расширенный wpdb запущен. " Идеальный. Теперь о наших реальных функциях.

Шаг №3 – Создайте, измените или замените функции

Запрос INSERT IGNORE кажется довольно простым. У нас уже есть $wpdb->insert(), поэтому нам не хватает только одного слова. К сожалению, из-за отсутствия фильтров в нужных местах, двух строчек кода не получится.

Если вы откроете wp-db.php и перейдете к методу insert() в строке 2100, вы увидите, что он использует метод _insert_replace_helper() из строки 2151. И эта функция не имеет ни одного фильтра или действия. Мы также не можем обернуть функцию, потому что она немедленно возвращает результат запроса, а не сам запрос, который мы могли бы изменить. Облом. Нам придется переопределить методы insert() и _insert_replace_helper() . Мы добавим дополнительный параметр — $ignore . Логическое значение со значением по умолчанию false .

public function insert( $table, $data, $format = null, $ignore = false ) {
  return $this->_insert_replace_helper( $table, $data, $format, 'INSERT', $ignore = false );
}

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

function _insert_replace_helper( $table, $data, $format = null, $type = 'INSERT', $ignore = false ) {
  $this->insert_id = 0;

  if ( ! in_array( strtoupper( $type ), array( 'REPLACE', 'INSERT' ) ) ) {
    return false;
  }

  $data = $this->process_fields( $table, $data, $format );
  if ( false === $data ) {
    return false;
  }

  $formats = $values = array();
  foreach ( $data as $value ) {
    if ( is_null( $value['value'] ) ) {
      $formats[] = 'NULL';
      continue;
    }

    $formats[] = $value['format'];
    $values[]  = $value['value'];
  }

  $fields  = '`' . implode( '`, `', array_keys( $data ) ) . '`';
  $formats = implode( ', ', $formats );
  
  // modification for IGNORE keyword
  if (true == $ignore && 'INSERT' == $type) {
    $type = 'INSERT IGNORE';
  }

  $sql = "$type INTO `$table` ($fields) VALUES ($formats)";

  $this->check_current_query = false;
  return $this->query( $this->prepare( $sql, $values ) );
}

Почему разработчики не делают этого чаще?

Если вам нужен пользовательский запрос всего несколько раз, вы можете легко использовать $wpdb->query() . Нет необходимости заменять класс по умолчанию. Вы также можете написать собственный класс, который расширяет класс по умолчанию, но не переопределяет объект wpdb. В этом случае вы бы использовали $mycustomclass->method() , но это не конец света.

Помимо очевидного фактора крутости, расширение класса wpdb по умолчанию — это то, что должно быть сделано в WP и не является хакерским, так что не стесняйтесь играть с этим. Имейте в виду две вещи:

  • когда вы отправляете свой проект кому-то, не забудьте включить файл db.php ; он не будет находиться ни в одной папке темы или плагина
  • следите за изменениями в wp-db.php , так как они могут повлиять на ваш пользовательский класс (хотя это маловероятно)