Skip to content

WordPress 数据库操作

WordPress 数据库概述

数据库表结构

WordPress 默认表:
┌────────────────────────────────────────────────────────────┐
│ wp_posts          - 所有文章、页面、附件内容              │
│ wp_postmeta       - 文章/页面的元数据(自定义字段)        │
│ wp_comments       - 评论数据                              │
│ wp_commentmeta    - 评论的元数据                          │
│ wp_terms          - 分类和标签                            │
│ wp_term_taxonomy  - 分类法(分类目录、标签等)            │
│ wp_term_relationships - 文章与分类/标签的关联             │
│ wp_termmeta       - 分类/标签的元数据                    │
│ wp_users          - 用户数据                              │
│ wp_usermeta       - 用户的元数据                          │
│ wp_options        - 站点设置和选项                        │
└────────────────────────────────────────────────────────────┘

表关系图

posts ─────────────┬─────────────── postmeta
  │               │                    │
  │               │                    │
  ▼               ▼                    │
posts ────────────▼─── comments ──────── commentmeta



term_relationships ──── term_taxonomy ──── terms ──── termeta
                                                       
users ──────────────── usermeta

全局对象

$wpdb 对象

php
<?php
global $wpdb;

// 直接执行 SQL
$results = $wpdb->get_results("SELECT * FROM {$wpdb->posts} WHERE post_type = 'post'");

// 获取一行
$row = $wpdb->get_row("SELECT * FROM {$wpdb->posts} WHERE ID = 1");

// 获取一个值
$count = $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->posts}");

// 获取一列
$titles = $wpdb->get_col("SELECT post_title FROM {$wpdb->posts}");
?>

表前缀

php
<?php
// 安全地引用表
$wpdb->posts      // wp_posts
$wpdb->postmeta   // wp_postmeta
$wpdb->comments   // wp_comments
$wpdb->commentmeta
$wpdb->terms
$wpdb->term_taxonomy
$wpdb->term_relationships
$wpdb->termmeta
$wpdb->users
$wpdb->usermeta
$wpdb->options

// 自定义表(需要 $wpdb->prefix)
$table_name = $wpdb->prefix . 'my_custom_table';
?>

基础查询

SELECT 查询

php
<?php
// get_results - 获取多行
$posts = $wpdb->get_results(
    "SELECT ID, post_title, post_content 
     FROM {$wpdb->posts} 
     WHERE post_type = 'post' 
     AND post_status = 'publish' 
     ORDER BY post_date DESC 
     LIMIT 10"
);

foreach ($posts as $post) {
    echo $post->post_title;
}

// 使用占位符(防注入)
$post_type = 'post';
$posts = $wpdb->get_results(
    $wpdb->prepare(
        "SELECT * FROM {$wpdb->posts} WHERE post_type = %s AND post_status = %s",
        $post_type,
        'publish'
    )
);

// 数字占位符 %d, 字符串 %s, 浮点数 %f
$wpdb->prepare(
    "SELECT * FROM {$wpdb->posts} WHERE ID = %d AND post_type = %s",
    $id,           // %d 整数
    $post_type     // %s 字符串
);
?>

插入数据

php
<?php
// insert() 方法
$wpdb->insert(
    $wpdb->prefix . 'my_table',
    array(
        'name' => '张三',
        'email' => '[email protected]',
        'created' => current_time('mysql'),
    ),
    array(
        '%s',  // name - 字符串
        '%s',  // email - 字符串
        '%s',  // created - 字符串
    )
);

// 获取插入的 ID
$insert_id = $wpdb->insert_id;

// 完整示例:记录访问日志
function log_visit($post_id, $visitor_ip) {
    global $wpdb;
    
    $table = $wpdb->prefix . 'visit_logs';
    
    $result = $wpdb->insert(
        $table,
        array(
            'post_id'    => $post_id,
            'visitor_ip' => $visitor_ip,
            'visit_date' => current_time('mysql'),
        ),
        array('%d', '%s', '%s')
    );
    
    return $result !== false;
}
?>

更新数据

php
<?php
// update() 方法
$wpdb->update(
    $wpdb->prefix . 'my_table',
    array(
        'name' => '李四',
        'email' => '[email protected]',
    ),
    array('id' => 1),
    array('%s', '%s'),  // 新值格式
    array('%d')          // WHERE 条件格式
);

// 示例:更新文章阅读数
function increment_views($post_id) {
    global $wpdb;
    
    // 使用 %d 占位符
    $table = $wpdb->prefix . 'post_stats';
    
    return $wpdb->query(
        $wpdb->prepare(
            "UPDATE {$table} SET views = views + 1 WHERE post_id = %d",
            $post_id
        )
    );
}
?>

删除数据

php
<?php
// delete() 方法
$wpdb->delete(
    $wpdb->prefix . 'my_table',
    array('id' => 5),
    array('%d')
);

// 示例:清理过期数据
function cleanup_expired_data() {
    global $wpdb;
    
    return $wpdb->query(
        $wpdb->prepare(
            "DELETE FROM {$wpdb->prefix}transient_logs 
             WHERE expires < %s",
            current_time('mysql')
        )
    );
}
?>

自定义数据库表

创建表

php
<?php
/**
 * 创建自定义表
 */
function create_custom_table() {
    global $wpdb;
    $charset_collate = $wpdb->get_charset_collate();
    
    $table_name = $wpdb->prefix . 'portfolio_clients';
    
    $sql = "CREATE TABLE IF NOT EXISTS {$table_name} (
        id bigint(20) NOT NULL AUTO_INCREMENT,
        name varchar(255) NOT NULL,
        email varchar(255) NOT NULL,
        company varchar(255),
        phone varchar(50),
        notes text,
        status varchar(20) DEFAULT 'active',
        created_at datetime DEFAULT CURRENT_TIMESTAMP,
        updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
        PRIMARY KEY  (id),
        KEY status (status),
        KEY email (email)
    ) $charset_collate;";
    
    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    dbDelta($sql);
}

// 激活插件时创建
register_activation_hook(__FILE__, 'create_custom_table');
?>

完整 CRUD 示例

php
<?php
/**
 * 客户管理类
 */
class Portfolio_Client_Manager {
    
    private $table_name;
    
    public function __construct() {
        global $wpdb;
        $this->table_name = $wpdb->prefix . 'portfolio_clients';
    }
    
    /**
     * 创建客户
     */
    public function create($data) {
        global $wpdb;
        
        $result = $wpdb->insert(
            $this->table_name,
            array(
                'name'    => sanitize_text_field($data['name']),
                'email'   => sanitize_email($data['email']),
                'company' => sanitize_text_field($data['company'] ?? ''),
                'phone'   => sanitize_text_field($data['phone'] ?? ''),
                'notes'   => wp_kses_post($data['notes'] ?? ''),
                'status'  => sanitize_key($data['status'] ?? 'active'),
            ),
            array('%s', '%s', '%s', '%s', '%s', '%s')
        );
        
        if ($result === false) {
            return new WP_Error('db_error', '创建客户失败');
        }
        
        return $wpdb->insert_id;
    }
    
    /**
     * 获取客户
     */
    public function get($id) {
        global $wpdb;
        
        return $wpdb->get_row(
            $wpdb->prepare(
                "SELECT * FROM {$this->table_name} WHERE id = %d",
                $id
            )
        );
    }
    
    /**
     * 获取所有客户
     */
    public function get_all($args = array()) {
        global $wpdb;
        
        $defaults = array(
            'status'   => '',
            'orderby' => 'id',
            'order'   => 'DESC',
            'limit'   => 20,
            'offset'  => 0,
        );
        
        $args = wp_parse_args($args, $defaults);
        
        $sql = "SELECT * FROM {$this->table_name}";
        $where = array();
        $values = array();
        
        if (!empty($args['status'])) {
            $where[] = 'status = %s';
            $values[] = $args['status'];
        }
        
        if (!empty($where)) {
            $sql .= ' WHERE ' . implode(' AND ', $where);
        }
        
        $sql .= " ORDER BY {$args['orderby']} {$args['order']}";
        $sql .= " LIMIT {$args['limit']} OFFSET {$args['offset']}";
        
        if (!empty($values)) {
            $sql = $wpdb->prepare($sql, $values);
        }
        
        return $wpdb->get_results($sql);
    }
    
    /**
     * 更新客户
     */
    public function update($id, $data) {
        global $wpdb;
        
        $update_data = array();
        $format = array();
        
        foreach ($data as $key => $value) {
            if (in_array($key, array('name', 'email', 'company', 'phone', 'notes', 'status'))) {
                $update_data[$key] = sanitize_text_field($value);
                $format[] = '%s';
            }
        }
        
        if (empty($update_data)) {
            return false;
        }
        
        return $wpdb->update(
            $this->table_name,
            $update_data,
            array('id' => $id),
            $format,
            array('%d')
        );
    }
    
    /**
     * 删除客户
     */
    public function delete($id) {
        global $wpdb;
        
        return $wpdb->delete(
            $this->table_name,
            array('id' => $id),
            array('%d')
        );
    }
    
    /**
     * 搜索客户
     */
    public function search($keyword) {
        global $wpdb;
        
        return $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM {$this->table_name} 
                 WHERE name LIKE %s 
                 OR email LIKE %s 
                 OR company LIKE %s
                 ORDER BY name ASC",
                '%' . $wpdb->esc_like($keyword) . '%',
                '%' . $wpdb->esc_like($keyword) . '%',
                '%' . $wpdb->esc_like($keyword) . '%'
            )
        );
    }
    
    /**
     * 统计客户数
     */
    public function count($status = '') {
        global $wpdb;
        
        if (empty($status)) {
            return (int) $wpdb->get_var(
                "SELECT COUNT(*) FROM {$this->table_name}"
            );
        }
        
        return (int) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$this->table_name} WHERE status = %s",
                $status
            )
        );
    }
}
?>

WordPress Meta API

Post Meta

php
<?php
// 添加 meta
add_post_meta($post_id, 'key', $value, $unique = false);

// 获取 meta
$value = get_post_meta($post_id, 'key', $single = false);
// $single = true 返回字符串/false
// $single = false 返回数组

// 更新 meta
update_post_meta($post_id, 'key', $new_value, $old_value = '');

// 删除 meta
delete_post_meta($post_id, $key, $value = '');

// 示例
$views = get_post_meta($post_id, 'views', true);  // 获取阅读数
$views = (int) $views + 1;
update_post_meta($post_id, 'views', $views);     // 更新阅读数
?>

User Meta

php
<?php
// 添加用户 meta
add_user_meta($user_id, 'twitter', '@username');

// 获取用户 meta
$twitter = get_user_meta($user_id, 'twitter', true);

// 更新用户 meta
update_user_meta($user_id, 'twitter', '@new_username');

// 删除用户 meta
delete_user_meta($user_id, 'twitter');

// 示例:用户配置
$preferences = get_user_meta($user_id, 'preferences', true);
if (!$preferences) {
    $preferences = array(
        'theme' => 'light',
        'email_notifications' => true,
    );
}
update_user_meta($user_id, 'preferences', $preferences);
?>

Term Meta

php
<?php
// 添加术语 meta
add_term_meta($term_id, 'color', '#21759b');

// 获取术语 meta
$color = get_term_meta($term_id, 'color', true);

// 更新术语 meta
update_term_meta($term_id, 'color', '#f1851a');

// 删除术语 meta
delete_term_meta($term_id, 'color');
?>

数据库安全

防 SQL 注入

php
<?php
// ✅ 使用 prepare() 方法
$sql = $wpdb->prepare(
    "SELECT * FROM {$wpdb->posts} WHERE ID = %d AND post_type = %s",
    $post_id,     // 整数
    $post_type    // 字符串
);
$results = $wpdb->get_results($sql);

// ✅ 使用 wpdb->esc_like() 转义搜索
$search = $wpdb->esc_like($_GET['s']);
$sql = $wpdb->prepare(
    "SELECT * FROM {$wpdb->posts} WHERE post_title LIKE %s",
    '%' . $search . '%'
);

// ❌ 不安全:直接拼接
$sql = "SELECT * FROM {$wpdb->posts} WHERE ID = " . $_GET['id'];  // 危险!

// ❌ 不安全:虽然简单,但不要用
$sql = "SELECT * FROM {$wpdb->posts} WHERE ID = " . intval($_GET['id']);  // 不推荐
?>

数据验证和清理

php
<?php
// 验证整数
$id = absint($_GET['id']);              // 正整数
$id = (int) $_GET['id'];               // 有符号整数
$id = intval($_GET['id']);              // 同上

// 验证浮点数
$price = (float) $_POST['price'];

// 清理 URL
$url = esc_url_raw($_GET['url']);      // 清理用于数据库
$url = esc_url($_GET['url']);          // 清理用于显示

// 清理 HTML
$html = wp_kses_post($_POST['content']);  // 允许基本 HTML
$html = wp_kses($_POST['content'], $allowed_tags);  // 自定义允许标签

// 清理邮箱
$email = sanitize_email($_POST['email']);

// 清理文本
$text = sanitize_text_field($_POST['name']);
$text = sanitize_textarea_field($_POST['message']);
$text = sanitize_title($_POST['title']);   // 用于 slug

// 清理 Key
$key = sanitize_key($_GET['key']);

// 清理文件路径
$file = sanitize_file($_GET['file']);

// 清理选择
$choice = sanitize_html_class($_GET['class']);

// 转义输出
echo esc_html($text);
echo esc_attr($class);
echo esc_url($url);
echo esc_js($string);
echo wp_kses_post($html);
?>

数据库性能优化

索引使用

php
<?php
// 创建索引以优化查询
$sql = "CREATE INDEX idx_post_status_date 
        ON {$wpdb->posts}(post_status, post_date)";

// 复合索引示例
$sql = "CREATE INDEX idx_user_status 
        ON {$wpdb->usermeta}(user_id, meta_key)";
?>

查询优化

php
<?php
// ✅ 使用 SELECT 只需要的字段
$wpdb->get_row(
    "SELECT ID, post_title FROM {$wpdb->posts} WHERE ID = %d",
    $id
);

// ✅ 使用缓存
$cache_key = 'post_' . $post_id;
$cached = wp_cache_get($cache_key);

if ($cached === false) {
    $cached = $wpdb->get_row(
        $wpdb->prepare(
            "SELECT * FROM {$wpdb->posts} WHERE ID = %d",
            $post_id
        )
    );
    wp_cache_set($cache_key, $cached, 'posts', HOUR_IN_SECONDS);
}

// ✅ 使用 transients 存储临时数据
set_transient('my_temp_data', $data, HOUR_IN_SECONDS);
$data = get_transient('my_temp_data');
delete_transient('my_temp_data');

// ✅ 批量操作
$wpdb->query("BEGIN");
foreach ($ids as $id) {
    $wpdb->update(...);
}
$wpdb->query("COMMIT");
?>

数据库迁移

升级表结构

php
<?php
/**
 * 插件升级时更新数据库
 */
function my_plugin_update_db_check() {
    $saved_version = get_option('my_plugin_version');
    
    if ($saved_version !== MY_PLUGIN_VERSION) {
        // 执行升级
        update_database_structure();
        
        // 更新版本记录
        update_option('my_plugin_version', MY_PLUGIN_VERSION);
    }
}
add_action('plugins_loaded', 'my_plugin_update_db_check');

function update_database_structure() {
    global $wpdb;
    $charset_collate = $wpdb->get_charset_collate();
    
    $table_name = $wpdb->prefix . 'my_plugin_table';
    
    // 添加新列
    $column_exists = $wpdb->get_var(
        $wpdb->prepare(
            "SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS 
             WHERE TABLE_SCHEMA = %s AND TABLE_NAME = %s AND COLUMN_NAME = 'new_column'",
            DB_NAME,
            $table_name
        )
    );
    
    if (!$column_exists) {
        $wpdb->query(
            "ALTER TABLE {$table_name} ADD COLUMN new_column VARCHAR(255)"
        );
    }
}
?>

调试数据库查询

php
<?php
// 保存所有查询
add_filter('query', 'log_queries');

function log_queries($query) {
    global $wpdb;
    $wpdb->queries[] = $query;
    return $query;
}

// 输出查询日志
function debug_queries() {
    global $wpdb;
    
    if (current_user_can('manage_options') && isset($_GET['debug_queries'])) {
        echo '<pre>';
        foreach ($wpdb->queries as $query) {
            echo esc_html($query) . "\n\n";
        }
        echo '</pre>';
    }
}
add_action('wp_footer', 'debug_queries');

// 使用 Query Monitor 插件(推荐)
// 提供图形界面和详细分析
?>

基于 WordPress官方文档 构建