Plugins often need to store their own data. Creating custom database tables helps keep plugin data organized and separate from WordPress core data.
Plugin database tables in Wordpress
<?php
function myplugin_create_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'myplugin_table';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
created datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
PRIMARY KEY (id)
) $charset_collate;";
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
dbDelta( $sql );
}
add_action( 'plugins_loaded', 'myplugin_create_table' );Use $wpdb->prefix to get the correct table prefix for the site.
Use dbDelta() to safely create or update tables without losing data.
<?php // Create a simple table for storing messages function create_messages_table() { global $wpdb; $table_name = $wpdb->prefix . 'messages'; $charset_collate = $wpdb->get_charset_collate(); $sql = "CREATE TABLE $table_name ( message_id bigint(20) NOT NULL AUTO_INCREMENT, message_text text NOT NULL, user_id bigint(20) NOT NULL, sent_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, PRIMARY KEY (message_id) ) $charset_collate;"; require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); dbDelta( $sql ); } add_action( 'plugins_loaded', 'create_messages_table' );
<?php
// Add a new column to an existing plugin table
function update_myplugin_table() {
global $wpdb;
$table_name = $wpdb->prefix . 'myplugin_table';
$status_column = $wpdb->get_results( $wpdb->prepare("SHOW COLUMNS FROM $table_name LIKE %s", 'status') );
if ( empty( $status_column ) ) {
$sql = "ALTER TABLE $table_name ADD COLUMN status varchar(20) DEFAULT 'active' NOT NULL;";
$wpdb->query($sql);
}
}
add_action( 'plugins_loaded', 'update_myplugin_table' );This plugin creates a custom table, inserts a sample row, and displays the stored data in the WordPress admin area.
<?php /** * Plugin Name: Simple Plugin Table Example */ function spt_create_table() { global $wpdb; $table_name = $wpdb->prefix . 'spt_data'; $charset_collate = $wpdb->get_charset_collate(); $sql = "CREATE TABLE $table_name ( id mediumint(9) NOT NULL AUTO_INCREMENT, data varchar(100) NOT NULL, created_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL, PRIMARY KEY (id) ) $charset_collate;"; require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); dbDelta( $sql ); } add_action( 'plugins_loaded', 'spt_create_table' ); function spt_insert_sample_data() { global $wpdb; $table_name = $wpdb->prefix . 'spt_data'; $row_count = $wpdb->get_var( "SELECT COUNT(*) FROM $table_name" ); if ( $row_count == 0 ) { $wpdb->insert( $table_name, [ 'data' => 'Hello World' ] ); } } add_action( 'plugins_loaded', 'spt_insert_sample_data' ); function spt_show_data() { global $wpdb; $table_name = $wpdb->prefix . 'spt_data'; $results = $wpdb->get_results( "SELECT * FROM $table_name" ); foreach ( $results as $row ) { echo "ID: {$row->id}, Data: {$row->data}, Created At: {$row->created_at}<br>"; } } add_action( 'admin_notices', 'spt_show_data' );
Always use dbDelta() for creating or updating tables to avoid data loss.
Use the $wpdb object for safe database access and to respect WordPress table prefixes.
Remember to sanitize and validate any data before inserting it into your tables.
Plugins use custom database tables to store their own data separately from WordPress core.
Use $wpdb->prefix and dbDelta() to create and update tables safely.
Custom tables help organize data, improve performance, and keep plugin data isolated.
Practice
Solution
Step 1: Understand plugin data management
Plugins create their own tables to store data separately from WordPress core data.Step 2: Benefits of separate tables
This separation helps organize data and improves performance by avoiding clutter in core tables.Final Answer:
To keep plugin data separate and organized for better performance -> Option CQuick Check:
Separate tables improve organization and performance [OK]
- Thinking WordPress forbids using core tables
- Believing plugins avoid databases entirely
- Assuming slower load is intentional
myplugin_data?Solution
Step 1: Understand $wpdb prefix usage
$wpdb->prefix contains the WordPress table prefix, usually 'wp_'.Step 2: Correct concatenation for table name
Concatenate $wpdb->prefix with the table name string to get the full table name.Final Answer:
$wpdb->prefix . 'myplugin_data' -> Option AQuick Check:
Prefix plus table name string = correct table name [OK]
- Using $wpdb->myplugin_data directly
- Not adding prefix to table name
- Calling $wpdb->prefix as a function
$table_name = $wpdb->prefix . 'myplugin_data'; $sql = "CREATE TABLE $table_name ( id mediumint(9) NOT NULL AUTO_INCREMENT, name varchar(100) NOT NULL, PRIMARY KEY (id) );"; dbDelta($sql);
What will happen when this code runs?
Solution
Step 1: Understand dbDelta function
dbDelta safely creates or updates database tables based on the SQL CREATE statement.Step 2: Analyze the SQL statement
The SQL creates a table with id and name columns and a primary key on id.Final Answer:
It creates the table with columns id and name if it doesn't exist -> Option BQuick Check:
dbDelta creates or updates tables safely [OK]
- Thinking dbDelta deletes tables
- Assuming dbDelta causes syntax errors
- Confusing dbDelta with data update functions
$table_name = $wpdb->prefix . 'myplugin_data'; $sql = "CREATE TABLE $table_name ( id int NOT NULL AUTO_INCREMENT, name varchar(100) NOT NULL, PRIMARY KEY (id) )"; dbDelta($sql);
But the table is not created after activation. What is the likely problem?
Solution
Step 1: Check SQL syntax for dbDelta
dbDelta requires the SQL CREATE statement to end with a semicolon to parse correctly.Step 2: Identify missing semicolon
The SQL string lacks a semicolon after the closing parenthesis, causing dbDelta to fail creating the table.Final Answer:
dbDelta requires the SQL string to end with a semicolon -> Option AQuick Check:
SQL must end with semicolon for dbDelta [OK]
- Ignoring semicolon requirement
- Thinking int vs mediumint causes failure
- Calling $wpdb->query() unnecessarily
email varchar(255) NOT NULL to your plugin's custom table myplugin_data during an update. Which approach correctly updates the table without losing data?Solution
Step 1: Understand dbDelta update behavior
dbDelta compares the current table structure with the SQL and adds missing columns safely.Step 2: Update CREATE TABLE SQL with new column
Modify the SQL to include the new email column and run dbDelta() to update the table without data loss.Final Answer:
Modify the original CREATE TABLE SQL to include the new column and run dbDelta() again -> Option DQuick Check:
dbDelta updates tables by comparing SQL definitions [OK]
- Dropping table loses all data
- Running ALTER TABLE manually then old dbDelta
- Avoiding database updates by using files
Ready to prove it?
Pass the test and this pattern moves unknown
