How To Run Safe Database Queries In WordPress With $Wpdb
The global $wpdb object lets you query the WordPress database directly. Use it when the standard functions are not enough, and always use $wpdb->prepare() to protect against SQL injection.
Get several rows
global $wpdb;
$lotgrafix_rows = $wpdb->get_results(
$wpdb->prepare(
"SELECT ID, post_title FROM {$wpdb->posts} WHERE post_type = %s AND post_status = %s LIMIT %d",
'post',
'publish',
5
)
);
foreach ( $lotgrafix_rows as $lotgrafix_row ) {
echo esc_html( $lotgrafix_row->post_title );
}
Get a single value
$lotgrafix_count = $wpdb->get_var(
$wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_author = %d", $author_id )
);
Placeholders
%s: a string.%d: an integer.%f: a float.
Search with LIKE
$lotgrafix_term = '%' . $wpdb->esc_like( $search ) . '%';
$lotgrafix_rows = $wpdb->get_results(
$wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_title LIKE %s", $lotgrafix_term )
);
Insert, update and delete
These helper methods build the query for you and escape the values.
$lotgrafix_table = $wpdb->prefix . 'lotgrafix_log';
$wpdb->insert(
$lotgrafix_table,
array(
'message' => 'Task finished',
'created_at' => current_time( 'mysql' ),
),
array( '%s', '%s' )
);
$wpdb->update(
$lotgrafix_table,
array( 'message' => 'Updated' ),
array( 'id' => 1 ),
array( '%s' ),
array( '%d' )
);
$wpdb->delete( $lotgrafix_table, array( 'id' => 1 ), array( '%d' ) );
Create a custom table on plugin activation
function lotgrafix_create_table() {
global $wpdb;
$table = $wpdb->prefix . 'lotgrafix_log';
$charset = $wpdb->get_charset_collate();
$sql = "CREATE TABLE $table (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
message text NOT NULL,
created_at datetime NOT NULL,
PRIMARY KEY (id)
) $charset;";
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta( $sql );
}
register_activation_hook( __FILE__, 'lotgrafix_create_table' );
dbDelta() is strict about formatting. Keep two spaces after PRIMARY KEY and put each field on its own line.
Rules to remember
- Use
{$wpdb->posts}and$wpdb->prefixinstead of typing table names. - Never put user input directly inside a query string.
- Prefer
WP_Query,get_posts()and the options functions when they can do the job.


