WordPress $wpdb Class

$wpdb is the global WordPress object for the database. Use it when the normal functions (WP_Query, get_option() and others) are not enough, for example to work with your own table. It already knows the connection and the table prefix.

Table names

global $wpdb;
echo $wpdb->prefix . "\n";
echo $wpdb->posts . "\n";
echo $wpdb->users . "\n";
echo $wpdb->options;
Output

wp_
wp_posts
wp_users
wp_options

Never write wp_posts by hand. The prefix can be different on another site, so use $wpdb->posts or $wpdb->prefix . 'my_table'.

Read data

MethodReturns
get_results( $sql )Many rows, as an array of objects
get_row( $sql )One row
get_var( $sql )One single value
get_col( $sql )One column, as an array
global $wpdb;

$count = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_type = 'page'" );
echo "Pages: $count\n";

$rows = $wpdb->get_results( "SELECT ID, post_title FROM {$wpdb->posts} WHERE post_type = 'page' ORDER BY ID" );
foreach ( $rows as $row ) {
	echo $row->ID . ' - ' . $row->post_title . "\n";
}
Output

Pages: 2
2 – Sample Page
3 – Privacy Policy

Always use prepare()

When a value comes from outside, never put it directly in the SQL. This opens your site to SQL injection. Use $wpdb->prepare() with the placeholders %s (string), %d (integer) and %f (float):

global $wpdb;
$title = "Sample Page' OR '1'='1";   // a bad input
$sql   = $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_title = %s", $title );
echo $sql . "\n";
var_dump( $wpdb->get_var( $sql ) );
Output

SELECT ID FROM wp_posts WHERE post_title = 'Sample Page\' OR \'1\'=\'1'
NULL

The quote in the bad input was escaped, so it is just a text and not a part of the SQL command. Without prepare() the same input would return every row.

Your own table with dbDelta

global $wpdb;
require_once ABSPATH . 'wp-admin/includes/upgrade.php';

$table   = $wpdb->prefix . 'tc_notes';
$charset = $wpdb->get_charset_collate();

$sql = "CREATE TABLE $table (
	id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
	note varchar(190) NOT NULL,
	created datetime NOT NULL,
	PRIMARY KEY  (id)
) $charset;";
dbDelta( $sql );

echo $wpdb->get_var( "SHOW TABLES LIKE '$table'" );
Output

wp_tc_notes

dbDelta() creates the table, or changes it when the table already exists. It is picky about the format: two spaces after PRIMARY KEY, and each field on its own line. Run it in the plugin activation hook.

Insert, update and delete

These helper methods write the safe SQL for you, so you do not need prepare() with them:

global $wpdb;
$table = $wpdb->prefix . 'tc_notes';
$wpdb->query( "CREATE TABLE IF NOT EXISTS $table ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT, note varchar(190) NOT NULL, created datetime NOT NULL, PRIMARY KEY  (id) )" );

$wpdb->insert( $table, array( 'note' => 'Buy milk', 'created' => '2026-03-01 09:00:00' ), array( '%s', '%s' ) );
echo 'Inserted ID: ' . $wpdb->insert_id . "\n";

$wpdb->update( $table, array( 'note' => 'Buy milk and bread' ), array( 'id' => 1 ), array( '%s' ), array( '%d' ) );
echo 'Note now: ' . $wpdb->get_var( "SELECT note FROM $table WHERE id = 1" ) . "\n";

$deleted = $wpdb->delete( $table, array( 'id' => 1 ), array( '%d' ) );
echo 'Rows deleted: ' . $deleted;
Output

Inserted ID: 2
Note now:
Rows deleted: 0

Useful properties

  • $wpdb->insert_id: the ID of the last inserted row.
  • $wpdb->last_error: the last database error text.
  • $wpdb->last_query: the last SQL query (good for debugging).
  • $wpdb->num_rows: the number of rows in the last result.
Note: Prefer the WordPress functions when they exist: WP_Query, get_posts(), get_option() and update_post_meta() use the cache and fire the hooks. Use $wpdb mainly for your own tables. Next: the REST API section, starting with WordPress REST API Introduction.

Congratulations! Chapter Finished. Learn more about the similar topics:
Exercises & Assignments
No Content Found.
Interview Questions & Answers
No Content Found.