数据库
Custom tables 与调优。
数据库与查询实战
这一课你将能做到
- 画出 WP 核心表的关系图,说清 posts / postmeta / options / users / terms 五大块各存什么
- 用 $wpdb 写出带 prepare 的安全查询,并用 dbDelta 规范建自定义表
- 用 WP_Query 的 meta_query / tax_query 组合出复杂课程列表,并知道性能坑在哪
为什么要学
WP 把你的所有内容——文章、页面、课程、设置——全部装进十来张 MySQL 表。做数据相关的开发(自定义字段筛选、批量导入、性能调优),绕不开表结构和 $wpdb。这也是 WP 面试区分「会用」和「会做」的分水岭。
人话:wp_posts 像 Java 里的通用实体表,post_type 字段区分文章/页面/课程;wp_postmeta 是典型的 EAV(键值对)扩展表——灵活但天生难索引,meta_query 写狠了就是慢查询之源。
先建立图像
wp_posts (ID, post_title, post_content, post_type, post_status)
│ 1:N │ N:M
▼ ▼
wp_postmeta wp_term_relationships
(post_id, meta_key, (object_id, term_taxonomy_id)
meta_value) │
▼
wp_options (option_name, wp_term_taxonomy → wp_terms
option_value, autoload) (分类法:category/tag/自定义)
wp_users (ID, user_login) ─1:N→ wp_usermeta
记忆法:四棵树——内容树(posts+meta)、配置树(options)、用户树(users+meta)、词汇树(terms 家族)。
跟着做
步骤 1:先看看库里有什么
wp db tables # 列出全部表
wp db query "SELECT post_type, COUNT(*) AS n FROM wp_posts GROUP BY post_type"
wp db size --tables # 哪张表最大
打开 phpMyAdmin 逐行看 wp_posts:一篇「课程」就是一行 post_type='course' 的记录,post_content 里存的可能是带区块注释的文本。
步骤 2:$wpdb 三剑客
global $wpdb;
// get_var: 取单个值
$count = $wpdb->get_var(
$wpdb->prepare(
"SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_type = %s AND post_status = %s",
'course', 'publish'
)
);
// get_row: 取一行(对象)
$course = $wpdb->get_row(
$wpdb->prepare( "SELECT * FROM {$wpdb->posts} WHERE ID = %d", 42 )
);
echo esc_html( $course->post_title );
// get_results: 取多行
$rows = $wpdb->get_results(
$wpdb->prepare(
"SELECT p.ID, p.post_title
FROM {$wpdb->posts} p
WHERE p.post_type = %s AND p.post_status = %s
ORDER BY p.post_date DESC
LIMIT %d",
'course', 'publish', 10
)
);
注意 {$wpdb->posts}:用属性而非硬编码 wp_posts,尊重自定义表前缀。%s/%d 占位符是 prepare 的防注入核心。
步骤 3:建一张自定义表
数据量大、查询复杂的场景(如课程学习记录)建独立表,在插件激活钩子里:
register_activation_hook( __FILE__, function () {
global $wpdb;
$table = $wpdb->prefix . 'qrocmq_enrollments';
$charset = $wpdb->get_charset_collate();
$sql = "CREATE TABLE $table (
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
user_id BIGINT(20) UNSIGNED NOT NULL,
course_id BIGINT(20) UNSIGNED NOT NULL,
progress TINYINT(3) UNSIGNED NOT NULL DEFAULT 0,
created_at DATETIME NOT NULL,
PRIMARY KEY (id),
KEY user_course (user_id, course_id),
KEY course_idx (course_id)
) $charset;";
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta( $sql );
} );