如何自定義 wpdb 類並添加新方法

已發表: 2018-07-10

WordPress的數據庫抽象層,俗稱wpdb,是一個基於ezSQL的類,負責與數據庫交互。 wpdb 類也是一個插件——一段核心 WP 代碼,可以很容易地被另一段具有類似功能的代碼替換(WP 代碼參考中提供了最新的插件列表)。

修改默認的#wpdb 類並不復雜。 您可以輕鬆地添加、刪除或修改幾個方法。 無需更換整個班級。 #wordpress

點擊推文

這是一個很大的誤解發揮作用的地方。 人們將“替換”視為“編寫我自己的、完整的數據庫類”。 幸運的是,您不必編寫整個數據庫類。 您可以使用現有的類並僅添加、刪除或修改您需要的功能。 這就是我們要做的。

為什麼要修改 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 構造函數。 這些 DB 常量在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 並前往 #2100 行的insert()方法,您會看到它使用了 #2151 行的_insert_replace_helper()方法。 而且該功能沒有單個過濾器或操作。 我們也不能包裝該函數,因為它會立即返回查詢結果,而不是我們可以修改的查詢本身。 真可惜。 我們必須重寫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 中完成的事情,而且不是 hackish,所以請隨意使用它。 請記住兩件事:

  • 當您將項目發送給某人時,不要忘記包含db.php文件; 它不會出現在任何主題或插件文件夾中
  • 密切關注wp-db.php中的變化,因為它們可能會影響您的自定義類(儘管這極不可能)