Secure CRUD Operations: Mastering $wpdb for WordPress Development
Learn to perform secure CRUD operations in WordPress using $wpdb. Prevent SQL injection with prepared statements in your custom plugin database interactions.
Previously in this course, we covered the database basics with wpdb, where you learned how to access the $wpdb object and perform simple SELECT queries. In this lesson, we move beyond reading data to writing it safely.
To maintain the integrity of our Knowledge Base plugin, we must ensure every "Create, Read, Update, and Delete" (CRUD) operation is immune to SQL injection. By leveraging built-in WordPress helper methods, we can abstract away the complexity of manual query construction and minimize human error.
The CRUD Mindset: Why Helper Methods Matter
When you write raw SQL queries, you are responsible for escaping every variable. If you forget even one, an attacker can manipulate your query to drop tables or leak sensitive user information. While preventing SQL injection in modern frameworks is standard practice, WordPress provides specific methods that handle this automatically.
We will focus on $wpdb->insert, $wpdb->update, and $wpdb->delete. These methods take arrays of data and handle the formatting and quoting for you, provided you use them correctly.
Performing Secure CRUD Operations
1. Creating Data with $wpdb->insert
To add a new entry to a custom table, we pass the table name, an associative array of data, and an optional array of formats.
PHPglobal $wpdb; $table_name = $wpdb->prefix . 'kb_articles'; $data = [ 'title' => 'How to use hooks', 'content' => 'Hooks allow you to modify WordPress...', 'status' => 'published' ]; $wpdb->insert($table_name, $data, ['%s', '%s', '%s']);
The third argument specifies the format: %s for strings, %d for integers, and %f for floats. Always define these to ensure the database engine treats your data as the correct type.
2. Updating Data with $wpdb->update
Updating follows a similar pattern, but requires a WHERE clause to ensure you don't accidentally update the entire table.
PHP$wpdb->update( $table_name, ['status' => 'archived'], #6A9955">// Data to update ['id' => 5], #6A9955">// WHERE clause ['%s'], #6A9955">// Format of data ['%d'] #6A9955">// Format of WHERE );
3. Secure Fetching with $wpdb->prepare
While insert and update handle their own security, SELECT queries (the "Read" in CRUD) require explicit protection. You must use $wpdb->prepare() to sanitize your input before it reaches the database.
PHP$article_id = 5; #6A9955">// Suppose this came from $_GET['id'] $query = $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}kb_articles WHERE id = %d", $article_id ); $article = $wpdb->get_row($query);
By using %d as a placeholder, prepare() ensures that $article_id is treated strictly as an integer, rendering SQL injection attempts harmless.
4. Deleting Data
Deletion is the most dangerous operation. Always ensure you have a specific WHERE clause to avoid catastrophic data loss.
PHP$wpdb->delete( $table_name, ['id' => 5], ['%d'] );
Hands-on Exercise: Implementing a Delete Action
In your Knowledge Base plugin, create a method within your KnowledgeBaseModel class that deletes an article by its ID.
- Ensure the method accepts
$idas an argument. - Use
$wpdb->deleteto remove the row from your custom table. - Validate that the ID is cast to an integer before passing it to the method.
- Return the result of the operation (the number of rows affected).
Common Pitfalls to Avoid
- Ignoring Formats: Never omit the format array. If you pass a string into a field expected to be an integer, you invite unexpected behavior.
- Mixing Raw SQL with variables: Never concatenate variables directly into a query string (e.g.,
"SELECT * FROM table WHERE id = $id"). This is the primary vector for SQL injection. - Forgetting
wpdb::prepare: Every time you use$wpdb->get_results,get_row, orget_varwith variables, you must useprepare().
Recap
CRUD operations are the lifeblood of your plugin's data management. By standardizing your database interactions through $wpdb->insert, $wpdb->update, and $wpdb->prepare, you protect your plugin against common security vulnerabilities. Always treat user-supplied data as untrusted until it has been properly formatted and prepared for the database engine.
Up next: We will transition from raw SQL to the powerful WP_Query class, which simplifies complex data retrieval in WordPress.
Work with me

Custom WordPress Plugin Development
Custom WordPress & WooCommerce plugins built to standard โ by the developer behind a plugin with 5,000+ active installs and a SaaS with 10,000+ users.

FilamentPHP Admin Panel & Dashboard Development
A powerful admin panel for your Laravel app โ built with FilamentPHP so you can manage everything without touching the database.