Querying the database
As with most frameworks, WordPress provides a built-in interface for interacting with the database. Most of the database operations will be handled by the wpdb
class located inside the wp-includes
directory. The wpdb
class will be available inside your plugins and themes as a global variable and provides access to all the tables inside the WordPress database including custom tables.
Note
Using the wpdb
class for CRUD operations is straightforward with its built-in methods. The complete guide for using the wpdb
class can be found at http://codex.wordpress.org/Class_Reference/wpdb.
Querying the existing tables
WordPress provides well-optimized built-in methods for accessing the existing database tables. Therefore, accessing these tables becomes straightforward. Let's see how basic CRUD (Create, Read, Update, and Delete) operations are executed on existing tables.
Inserting records
All the existing tables contain a prebuilt insert method for creating new records. The following list illustrates a few of the built-in insert functions:
wp_insert_post
: This function creates a new post or page in thewp_posts
tableadd_option
: This function creates a new option on thewp_options
table, if it doesn't already existwp_insert_comment
: This function creates a new comment in thewp_comments
table
Updating records
All the existing tables contain a prebuilt update method for updating existing records. The following list illustrates a few of the built-in update functions:
update_post_meta
: This function creates or updates additional details about posts in thewp_postmeta
tablewp_update_term
: This function updates the existing terms in thewp_terms
tableupdate_user_meta
: This function updates the user's meta details in thewp_usermeta
table based on the user ID
Deleting records
Similar methods are available for deleting records in each of the existing tables.
Selecting records
As usual, there is a set of built-in functions for selecting records from the existing tables. The following list contains few of the data selecting functions:
get_posts
: This function retrieves the posts as an array from thewp_posts
table based on the passed arguments. Also, we can use theWP_Query
class with the necessary arguments to get the post list from the OOP method.get_option
: This function retrieves the option value of the given key from thewp_options
table.get_users
: This function retrieves the list of users as an array from thewp_user
table.
Most of the database operations on existing tables can be executed using these built-in functions. So, use of the $wpdb
class is not necessary in most occasions unless queries become complex and hard to handle using direct functions.
Querying the custom tables
Basically, there are no built-in methods for accessing custom tables using direct functions. So, it's a must to use the wpdb
class for handling custom tables. Let's take a look at some of the functions provided by the wpdb
class:
$wpdb->get_results( "select query" )
: This function can be used to select a set of records from any database table.$wpdb->query('query')
: This function can be used to execute any custom query. This is typically used for update and delete statements instead of select statements as it only provides the affected rows' count as the result.$wpdb->get_row('query')
: This function can be used to retrieve a single row from the database as an object, an associative array, or as a numerically indexed array.
The complete list of the wpdb
class functions can be accessed at http://codex.wordpress.org/Class_Reference/wpdb. When executing these functions, we have to make sure that we include the necessary filtering and validations as these are not built to directly work with the existing tables. For example, consider the following query for proper usage of these functions with the necessary filtering:
$wpdb->query( $wpdb->prepare("SELECT FROM $wpdb->postmetaWHERE post_id = %d AND meta_key = %s",1, 'book_title' ) );
Here, we are filtering the user input values through the prepare
function for illegal operations and illegal characters. Similarly, you have to use functions such as escape
and escape_by_ref
for securing direct SQL queries.
Data validation is an important aspect of keeping the consistency of the database. WordPress offers the prepare
function for formatting the SQL queries from possible threats. Usually, developers use the prepare
function with direct queries including variables instead of using placeholders and value parameters. It's a must to use placeholders and value parameters to get the intended outcome of the prepare
function. Therefore, WordPress Version 3.5 and onwards enforce a minimum of two arguments to prevent developers from misusing the prepare
function.
Working with posts
WordPress posts act as the main module in web application development as well as content management systems. Therefore, WordPress comes with a separate class named WP_Query
for interacting with the posts and pages. You can look into more details about the use of WP_Query
at http://codex.wordpress.org/Class_Reference/WP_Query.
Up until now, we had a look at procedural database access functions using global objects. Web application developers are much more familiar with object-oriented coding. The WP_Query
class is a good choice for such developers in querying the database. Let's find out the default usage of WP_Query
using the following code:
$args = array( 'post_type' => 'projects', 'meta_query' => array( array( 'language' => '', 'value' => 'PHP' ) ) ); $query = new WP_Query($args);
First, we need to add all the filtering conditions to an array. The WP_Query
class allows us to include conditions on multiple tables, such as categories, tags, and postmeta. This technique allows us to create highly complex queries without worrying about the SQL code. The advantage of WP_Query
comes with its ability to create sub classes to cater to project-specific requirements. In the next section, we are going learn how to extend the WP_Query
class to create custom database access interfaces.
Extending WP_Query for applications
The default WP_Query
class works similarly for all types of custom post types. In web applications, we can have different custom post types with different meanings. For example, developers can create services inside our portfolio application. Each service will have a price and process associated with it. There is no point retrieving these services without those additional details. Now, let's look at the default way of retrieving services with WP_Query
using the following code:
$args = array( 'post_type' => 'services', 'meta_query' => array( array( 'key' => 'price' ), array( 'key' => 'process' ) ) ); $query = new WP_Query( $args );
This query works perfectly in retrieving services from the database. However, each time we have to pass the price and process keys in order to join them while retrieving services. Since this is a services-specific requirement, we can create a custom class to extend WP_Query
and avoid repetitive argument passing as it's common to all the services-related queries. Let's implement the extended WP_Query
class as follows:
class WPWA_Services_Query extends WP_Query { function __construct( $args = array() ) { $args = wp_parse_args( $args, array( 'post_type' => 'services', 'meta_query' => array( array( 'key' => 'price' ), array( 'key' => 'process' ) ) ) ); parent::__construct( $args ); } }
Now, all the common conditions are abstracted inside the WPWA_Services_Query
class. So, we don't have to pass the conditions every time we want services. The preceding example illustrates the basic form of object inheritance. Additionally, we can use post filters to combine custom tables with services. Now, we can access services using the following code without passing any arguments:
$query = new WPWA_Services_Query();
The WP_Query
class is going to play a vital part in our portfolio application development. In the upcoming chapters, we are going to explore how it can be extended in several ways using advanced post filters provided by WordPress. Until then, you can check out the available post filters at http://codex.wordpress.org/Plugin_API/Filter_Reference#WP_Query_Filters.