Wpdb last error

An instantiated wpdb class can talk to any number of tables, but only to one database at a time. In the rare case you need to connect to another database, instantiate your own object from the wpdb class with your own database connection information.

Contents

  • More Information
    • An Important Note Regarding Escaping
  • Using the $wpdb global object
  • Protect Queries Against SQL Injection Attacks
    • Placeholders
    • Examples
  • Common Tasks
    • SELECT a Variable
      • Examples
    • SELECT a Row
      • Examples
    • SELECT a Column
      • Examples
    • SELECT Generic Results
      • Examples
    • INSERT row
      • Examples
    • REPLACE row
      • Examples
    • UPDATE rows
      • Examples
    • DELETE Rows
      • Examples
    • Running General Queries
      • Examples
    • Show and Hide SQL Errors
    • Getting Column Information
    • Clearing the Cache
    • Tables
    • Properties
      • Multi-Site Variables
      • Tables
      • Multisite Tables
    • Methods
    • Source
    • User Contributed Notes

An instantiated wpdb class can talk to any number of tables, but only to one database at a time. In the rare case you need to connect to another database, instantiate your own object from the wpdb class with your own database connection information.

Note: Each method contained within the class is listed in the Methods section (below). In addition, each method has its own help page; this is where you’ll find detailed usage information for the method you’re interested in.

Some of the methods in this class take an SQL statement as input. All untrusted values in an SQL statement must be escaped to prevent SQL injection attacks. Some methods will escape SQL for you; others will not. Check the documentation to be sure before you use any method in this class. For more on SQL escaping in WordPress, see the section entitled Protect Queries Against SQL Injection Attacks below.


WordPress provides a global object, $wpdb, which is an instantiation of the wpdb class. By default, $wpdb is instantiated to talk to the WordPress database.

The recommended way to access $wpdb in your WordPress PHP code is to declare $wpdb as a global variable using the global keyword, like this:

<?php
// 1st Method - Declaring $wpdb as global and using it to execute an SQL query statement that returns a PHP object
global $wpdb;
$results = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}options WHERE option_id = 1", OBJECT );

Alternatively, if the above doesn’t suit your needs for whatever reason, use the superglobal $GLOBALS in the following manner:

<?php
// 2nd Method - Utilizing the $GLOBALS superglobal. Does not require global keyword ( but may not be best practice )
$results = $GLOBALS['wpdb']->get_results( "SELECT * FROM {$wpdb->prefix}options WHERE option_id = 1", OBJECT );

The $wpdb object can be used to read data from any table in the WordPress database, not just those created by WordPress itself.


For a more complete overview of SQL escaping in WordPress, see database Data Validation. It is a must-read for all WordPress code contributors and plugin authors.

All data in SQL queries must be SQL-escaped before the SQL query is executed to prevent against SQL injection attacks. The prepare method performs this functionality for WordPress, which supports both a sprintf()-like and vsprintf()-like syntax.

Using it looks like this:

<?php
$sql = $wpdb->prepare( 'query' , value_parameter[, value_parameter ... ] );
query
(string) The SQL query you wish to execute, with placeholders (see below).
value_parameter
(int|string|array) The value to substitute into the placeholder. Many values may be passed by simply passing more arguments in a sprintf()-like fashion. Alternatively the second argument can be an array containing the values as in PHP’s vsprintf() function. Care must be taken not to allow direct user input to this parameter, which would enable array manipulation of any query with multiple placeholders.Note: Values cannot be SQL-escaped.

The query parameter for prepare accepts sprintf()-like placeholders:

  • %s (string)
  • %d (integer)
  • %f (float)

Notes on placeholders

  1. Any other % characters may cause parsing errors unless they are escaped.
  2. All % characters inside SQL string literals, including LIKE wildcards, must be double-% escaped as %%.
  3. Leave %d, %f, and %s unquoted in the query string.

Add Meta key => value pair “Funny Phrases” => “WordPress’ database interface is like Sunday Morning: Easy.” to Post 10.

<?php
$metakey   = 'Funny Phrases';
$metavalue = "WordPress' database interface is like Sunday Morning: Easy.";

$wpdb->query(
   $wpdb->prepare(
      "INSERT INTO $wpdb->postmeta
      ( post_id, meta_key, meta_value )
      VALUES ( %d, %s, %s )",
      10,
      $metakey,
      $metavalue
   )
);

The same query using vsprintf()-like syntax. Note that in this example we pack the values together in an array. This can be useful when we don’t know the number of arguments we need to pass until runtime.

<?php
$metakey   = 'Funny Phrases';
$metavalue = "WordPress' database interface is like Sunday Morning: Easy.";

$wpdb->query(
   $wpdb->prepare(
   "INSERT INTO $wpdb->postmeta
   ( post_id, meta_key, meta_value )
   VALUES ( %d, %s, %s )",
   array(
         10,
         $metakey,
         $metavalue,
      )
   )
);

In both cases, we do not need to escape the strings because we are passing them using placeholders. You can pass as many values as you like, provided each one has a corresponding placeholder in the prepare() method call.


Each of the class’s properties and methods are listed below, and most have their own help page that you should consult for detailed usage information. This section, however, gives an overview of some of the more common tasks this class can be used to perform.

The get_var function returns a single variable from the database. Though only one variable is returned, the entire result of the query is cached for later use. Returns NULL if no result is found.

 <?php $wpdb->get_var( 'query', column_offset, row_offset ); ?>
query
(string) The query you wish to run. Setting this parameter to null will return the specified variable from the cached results of the previous query.
column_offset
(integer) The desired column (0 being the first). Defaults to 0.
row_offset
(integer) The desired row (0 being the first). Defaults to 0.

Retrieve and display the number of users.

<?php
$user_count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->users" );
echo "<p>User count is {$user_count}</p>";
?>

Retrieve and display the sum of a Custom Field value.

<?php
// set the meta_key to the appropriate custom field meta key
$meta_key = 'miles';
$allmiles = $wpdb->get_var(
	$wpdb->prepare(
		"
			SELECT sum(meta_value)
			FROM $wpdb->postmeta
			WHERE meta_key = %s
		",
		$meta_key
	)
);
echo "<p>Total miles is {$allmiles}</p>";
?>

To retrieve an entire row from a query, use get_row. The function can return the row as an object, an associative array, or as a numerically indexed array. If more than one row is returned by the query, only the specified row is returned by the function, but all rows are cached for later use. Returns null if no result is found, consider this when using the returned value in arguments, see example below.

<?php $wpdb->get_row('query', output_type, row_offset); ?>
query
(string) The query you wish to run.
output_type
One of three pre-defined constants. Defaults to OBJECT.
  • OBJECT – result will be output as an object.
  • ARRAY_A – result will be output as an associative array.
  • ARRAY_N – result will be output as a numerically indexed array.
row_offset
(integer) The desired row (0 being the first). Defaults to 0.

Get all the information about Link 10.

$mylink = $wpdb->get_row( "SELECT * FROM $wpdb->links WHERE link_id = 10" );

The properties of the <code>$mylink</code> object are the column names of the result from the SQL query (in this example all the columns from the <code>$wpdb->links</code> table, but you could also query for specific columns only).

echo $mylink->link_id; // prints "10"

In contrast, using

$mylink = $wpdb->get_row( "SELECT * FROM $wpdb->links WHERE link_id = 10", ARRAY_A );

would result in an associative array:

echo $mylink['link_id']; // prints "10"

and

$mylink = $wpdb->get_row( "SELECT * FROM $wpdb->links WHERE link_id = 10", ARRAY_N );

would result in a numerically indexed array:

echo $mylink[1]; // prints "10"

If there is no record with ID 10 in the links table, null will be returned. The following would then be false:

if ( null !== $mylink ) {
  // do something with the link
  return true;
} else {
  // no link found
  return false;
}

To SELECT a column, use get_col. This method outputs a one dimensional array. If more than one column is returned by the query, only the specified column will be returned, but the entire result is cached for later use. Returns an empty array if no result is found.

get_col( 'query', column_offset ); ?>
query
(string) the query you wish to execute. Setting this parameter to null will return the specified column from the cached results of the previous query.
column_offset
(integer) The desired column (0 being the first). Defaults to 0.

For this example, assume the blog is devoted to information about automobiles. Each post describes a particular car (e.g. 1969 Ford Mustang), and three Custom Fields, manufacturer, model, and year, are assigned to each post. This example will display the post titles, filtered by a particular manufacturer (Ford), and sorted by model and year.

The get_col method is used to return an array of all the post ids meeting the criteria and sorted in the correct order. Then a foreach construct is used to iterate through that array of post ids, displaying the title of each post. Note that the SQL for this example was created by Andomar.

<?php
$meta_key1       = 'model';
$meta_key2       = 'year';
$meta_key3       = 'manufacturer';
$meta_key3_value = 'Ford';

$postids = $wpdb->get_col( $wpdb->prepare(
	"
		SELECT      key3.post_id
		FROM        $wpdb->postmeta key3
		INNER JOIN  $wpdb->postmeta key1
	            ON key1.post_id = key3.post_id
	            AND key1.meta_key = %s
		INNER JOIN  $wpdb->postmeta key2
	            ON key2.post_id = key3.post_id
	            AND key2.meta_key = %s
		WHERE       key3.meta_key = %s
	            AND key3.meta_value = %s
		ORDER BY    key1.meta_value, key2.meta_value
	",
	$meta_key1,
	$meta_key2,
	$meta_key3,
	$meta_key3_value
) ); 

if ( $postids ) {
	echo "List of {$meta_key3_value}(s), sorted by {$meta_key1}, {$meta_key2}";
	foreach ( $postids as $id ) {
		$post = get_post( intval( $id ) );
		setup_postdata( $post );
		?>
		<p>
			<a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>">
				<?php the_title(); ?>
			</a>
		</p>
		<?php
	}
}
?>

This example lists all posts that contain a particular custom field, but sorted by the value of a second custom field.

<?php
// List all posts with custom field Color, sorted by the value of custom field Display_Order
// does not exclude any 'post_type'
// assumes each post has just one custom field for Color, and one for Display_Order
$meta_key1 = 'Color';
$meta_key2 = 'Display_Order';

$postids = $wpdb->get_col( $wpdb->prepare(
	"
		SELECT      key1.post_id
		FROM        $wpdb->postmeta key1
		INNER JOIN  $wpdb->postmeta key2
	            ON key2.post_id = key1.post_id
	            AND key2.meta_key = %s
		WHERE       key1.meta_key = %s
		ORDER BY    key2.meta_value+(0) ASC
	",
        $meta_key2,
	$meta_key1
) ); 

if ( $postids ) {
	echo "List of {$meta_key1} posts, sorted by {$meta_key2}";
	foreach ( $postids as $id ) {
		$post = get_post( intval( $id ) );
		setup_postdata( $post );
		?>
		<p>
			<a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>">
				<?php the_title(); ?>
			</a>
		</p>
		<?php
	}
}
?>

Generic, multiple row results can be pulled from the database with get_results. The method returns the entire query result as an array. Each element of this array corresponds to one row of the query result and, like get_row, can be an object, an associative array, or a numbered array. If no matching rows are found, or if there is a database error, the return value will be an empty array. If your $query string is empty, or you pass an invalid $output_type, NULL will be returned.

get_results( 'query', output_type );
query
(string) The query you wish to run.
output_type
One of four pre-defined constants. Defaults to OBJECT. See SELECT a Row and its examples for more information.

  • OBJECT – result will be output as a numerically indexed array of row objects.
  • OBJECT_K – result will be output as an associative array of row objects, using first column’s values as keys (duplicates will be discarded).
  • ARRAY_A – result will be output as a numerically indexed array of associative arrays, using column names as keys.
  • ARRAY_N – result will be output as a numerically indexed array of numerically indexed arrays.

Since this method uses the $wpdb->query() method, all the class variables are properly set. The results count for a ‘SELECT’ query will be stored in $wpdb->num_rows.

Get the IDs and Titles of all the Drafts by User 5 and echo the Titles.

$fivesdrafts = $wpdb->get_results(
	"
		SELECT ID, post_title
		FROM $wpdb->posts
		WHERE post_status = 'draft'
		AND post_author = 5
	"
);

foreach ( $fivesdrafts as $fivesdraft ) {
	echo $fivesdraft->post_title;
}

Get all information on the Drafts by User 5.

<?php
$fivesdrafts = $wpdb->get_results(
	"
		SELECT *
		FROM $wpdb->posts
		WHERE post_status = 'draft'
		AND post_author = 5
	"
);

if ( $fivesdrafts ) {
	foreach ( $fivesdrafts as $post ) {
		setup_postdata( $post );
		?>
		<h2>
			<a href="<?php the_permalink(); ?>" rel="bookmark" title="Permalink: <?php the_title(); ?>">
				<?php the_title(); ?>
			</a>
		</h2>
		<?php
	}
} else {
	?>
	<h2>Not Found</h2>
	<?php
}
?>

The insert method is used to insert a row into a table.

insert( $table, $data, $format );
$table
(string) The name of the table to insert data into.
$data
(array) Data to insert (in column => value pairs). Both $data columns and $data values should be “raw” (neither should be SQL escaped).
$format
(array|string) (optional) An array of formats to be mapped to each of the values in $data. If string, that format will be used for all of the values in $data. If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.

Possible format values: %s as string; %d as integer (whole number); and %f as float. (See below for more information.)

Note: After insert, the ID generated for the AUTO_INCREMENT column can be accessed with:

$wpdb->insert_id

This method returns false if the row could not be inserted. Otherwise, it returns the number of affected rows (which will always be 1).

Please note: The value portion of the data parameter’s column=>value pairs must be scalar. If you pass an array (or object) as a value to be inserted you will generate a warning.

Insert two columns in a row, the first value being a string and the second a number:

$wpdb->insert(
	'table',
	array(
		'column1' => 'value1',
		'column2' => 123,
	),
	array(
		'%s',
		'%d',
	)
);

The replace method replaces a row in a table if it exists or inserts a new row in a table if the row did not already exist.

replace( $table, $data, $format );
$table
(string) The name of the table to replace data in.
$data
(array) Data to replace (in column => value pairs). Both $data columns and $data values should be “raw” (neither should be SQL escaped).
$format
(array|string) (optional) An array of formats to be mapped to each of the value in $data. If string, that format will be used for all of the values in $data. If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types. Possible format values: %s as string; %d as integer (whole number); and %f as float. (See below for more information.)

If the length of a string element in the $data array parameter is longer that the defined length in the MySql database table, the insert will fail, this method will return false, but $wpdb->last_error will not be set to a descriptive message. You must ensure the data you wish to insert will fit in the database – do not assume the MySql will truncate the data.

After replace, the ID generated for the AUTO_INCREMENT column can be accessed with:

$wpdb->insert_id

This method returns a count to indicate the number of rows affected. This is the sum of the rows deleted and inserted. If the count is 1 for a single-row REPLACE, a row was inserted and no rows were deleted. If the count is greater than 1, one or more old rows were deleted before the new row was inserted. It is possible for a single row to replace more than one old row if the table contains multiple unique indexes and the new row duplicates values for different old rows in different unique indexes.

This method returns false if an existing row could not be replaced and a new row could not be inserted.

Replace a row, the first value being the row id, the second a string and the third a number:

$wpdb->replace(
	'table',
	array(
                'indexed_id' => 1,
		'column1' => 'value1',
		'column2' => 123,
	),
	array(
                '%d',
		'%s',
		'%d',
	)
);

Update a row in the table. Returns false if errors, or the number of rows affected if successful. (wpdb::update)

update( $table, $data, $where, $format = null, $where_format = null );
$table
(string) The name of the table to update.
$data
(array) Data to update (in column => value pairs). Both $data columns and $data values should be “raw” (neither should be SQL escaped). This means that if you are using GET or POST data you may need to use stripslashes() to avoid slashes ending up in the database.
$where
(array) A named array of WHERE clauses (in column => value pairs). Multiple clauses will be joined with ANDs. Both $where columns and $where values should be “raw”.
$format
(array|string) (optional) An array of formats to be mapped to each of the values in $data. If string, that format will be used for all of the values in $data.
$where_format
(array|string) (optional) An array of formats to be mapped to each of the values in $where. If string, that format will be used for all of the items in $where. Possible format values: %s as string; %d as integer (whole number) and %f as float. (See below for more information.) If omitted, all values in $where will be treated as strings.

This method returns the number of rows updated, or false if there is an error. Keep in mind that if the $data matches what is already in the database, no rows will be updated, so 0 will be returned. Because of this, you should probably check the return with false === $result

Update a row, where the ID is 1, the value in the first column is a string and the value in the second column is a number:

$wpdb->update(
	'table',
	array(
		'column1' => 'value1',	// string
		'column2' => 'value2'	// integer (number)
	),
	array( 'ID' => 1 ),
	array(
		'%s',	// value1
		'%d'	// value2
	),
	array( '%d' )
);

Attention: %d can’t deal with comma values – if you’re not using full numbers, use string/%s.

The delete method is used to delete rows from a table. The usage is very similar to update and insert. It returns the number of rows updated, or false on error.

delete( $table, $where, $where_format = null );
$table
(string) (required) Table name.Default: None
$where
(array) (required) A named array of WHERE clauses (in column -> value pairs). Multiple clauses will be joined with ANDs. Both $where columns and $where values should be ‘raw’. Default: None
$where_format
(string/array) (optional) An array of formats to be mapped to each of the values in $where. If a string, that format will be used for all of the items in $where. A format is one of '%d', '%f', '%s' (integer, float, string; see below for more information). If omitted, all values in $where will be treated as strings unless otherwise specified in wpdb::$field_types. Default: null
// Default usage.
$wpdb->delete( 'table', array( 'ID' => 1 ) );

// Using where formatting.
$wpdb->delete( 'table', array( 'ID' => 1 ), array( '%d' ) );

The query method allows you to execute any SQL query on the WordPress database. It is best used when there is a need for specific, custom, or otherwise complex SQL queries. For more basic queries, such as selecting information from a table, see the other wpdb methods above such as get_results, get_var, get_row or get_col.

query('query');
query
(string) The SQL query you wish to execute.

This method returns an integer value indicating the number of rows affected/selected for SELECT, INSERT, DELETE, UPDATE, etc. For CREATE, ALTER, TRUNCATE and DROP SQL statements, (which affect whole tables instead of specific rows) this method returns TRUE on success. If a MySQL error is encountered, the method will return FALSE. Note that since both 0 and FALSE may be returned for row queries, you should be careful when checking the return value. Use the identity operator (===) to check for errors (e.g., false === $result), and whether any rows were affected (e.g., 0 === $result).

Delete the ‘gargle’ meta key and value from Post 13. (We’ll add the ‘prepare’ method to make sure we’re not dealing with an illegal operation or any illegal characters):

$wpdb->query(
	$wpdb->prepare(
		"
                	DELETE FROM $wpdb->postmeta
			WHERE post_id = %d
			AND meta_key = %s
		",
	        13, 'gargle'
        )
);

Set the parent of Page 15 to Page 7.

$wpdb->query( $wpdb->prepare(
	"
		UPDATE $wpdb->posts
		SET post_parent = %d
		WHERE ID = %d
		AND post_status = %s
	",
        7, 15, 'static'
) );

You can turn error echoing on and off with the show_errors and hide_errors, respectively.

<?php $wpdb->show_errors(); ?>
<?php $wpdb->hide_errors(); ?>

You can also print the error (if any) generated by the most recent query with print_error.

<?php $wpdb->print_error(); ?>

Note: If you are running WordPress Multisite, you must define the DIEONDBERROR constant for database errors to display like so:

<?php define( 'DIEONDBERROR', true ); ?>

You can retrieve information about the columns of the most recent query result with get_col_info. This can be useful when a function has returned an OBJECT whose properties you don’t know. The function will output the desired information from the specified column, or an array with information on all columns from the query result if no column is specified.

<?php $wpdb->get_col_info('type', offset); ?>

type
(string) What information you wish to retrieve. May take on any of the following values (list taken from the ezSQL docs). Defaults to name.

  • name – column name. Default.
  • table – name of the table the column belongs to
  • max_length – maximum length of the column
  • not_null – 1 if the column cannot be NULL
  • primary_key – 1 if the column is a primary key
  • unique_key – 1 if the column is a unique key
  • multiple_key – 1 if the column is a non-unique key
  • numeric – 1 if the column is numeric
  • blob – 1 if the column is a BLOB
  • type – the type of the column
  • unsigned – 1 if the column is unsigned
  • zerofill – 1 if the column is zero-filled

offset
(integer) Specify the column from which to retrieve information (with 0 being the first column). Defaults to -1.

  • -1 – Retrieve information from all columns. Output as array. Default.
  • Non-negative integer – Retrieve information from specified column (0 being the first).

You can clear the SQL result cache with flush.

<?php $wpdb->flush(); ?>

This clears $wpdb->last_result, $wpdb->last_query, and $wpdb->col_info.


The tables that WordPress creates by default can be found here.


  • $base_prefix — The original prefix as defined in wp-config.php. For multi-site: Use if you want to get the prefix without the blog number appended.
  • $col_info — The column information for the most recent query results. See Getting Column Information.
  • $insert_id — ID generated for an AUTO_INCREMENT column by the most recent INSERT query.
  • $last_error — The most recent error text generated by MySQL.
  • $last_query — The most recent query to have been executed.
  • $last_result — The most recent query results.
  • $num_queries — The number of queries that have been executed.
  • $num_rows — The number of rows returned by the last query.
  • $prefix — The assigned WordPress table prefix for the site.
  • $queries — You may save all of the queries run on the database and their stop times by setting the SAVEQUERIES constant to TRUE (this constant defaults to FALSE). If SAVEQUERIES is TRUE, your queries will be stored in this variable as an array.
  • $show_errors — Whether or not Error echoing is turned on. Defaults to TRUE.

If you are using Multi-Site, you also have access to the following:

  • $blogid — The id of the current site (blog).
  • $siteid — The id of the current network (formerly “site”). WordPress currently only supports one network per multi-site install, but that could change in future. See the following for more information: WordPress: difference between site_id and blog_id?
    http://stackoverflow.com/a/4189358/1924128 – Another good answer to the same question.

The WordPress database tables are easily referenced in the wpdb class.

  • $comments — The Comments table.
  • $commentmeta — The table contains additional comment information.
  • $links — The table of Links.
  • $options — The Options table.
  • $posts — The table of Posts.
  • $postmeta — The Meta Content (a.k.a. Custom Fields) table.
  • $term_taxonomy — The term_taxonomy table describes the various taxonomies (classes of terms). Categories, Link Categories, and Tags are taxonomies.
  • $term_relationships — The term relationships table contains link between the term and the object that uses that term, meaning this file point to each Category used for each Post.
  • $termmeta — The termmeta table contains the term meta values.
  • $terms — The terms table contains the ‘description’ of Categories, Link Categories, Tags.
  • $users — The table of Users.
  • $usermeta — The usermeta table contains additional user information, such as nicknames, descriptions and permissions.

These tables are used only in multisite installations.

  • $blogs — The Blogs table contains a list of the separate blogs (sites) that have been set up within the network(s).
  • $blog_versions — The Blog Versions table.
  • $blogmeta — The Blogmeta table is used to store data associated with a particulate blog in multisite context. See more info in this blog post.
  • $registration_log — The Registration Log table.
  • $signups — The Signups table.
  • $site — The Site table contains a list of the networks (previously known as “sites” in WPMU) that are set up in the installation (usually there is only one site listed in this table).
  • $sitecategories — The Site Categories table.
  • $sitemeta — The Network Options (Site Meta) table contains any options that are applicable to the entire multisite installation.

For more information about the tables WordPress creates and uses, look here.


  • __construct
    — Connects to the database server and selects a database.
  • __get
    — Makes private properties readable for backward compatibility.
  • __isset
    — Makes private properties check-able for backward compatibility.
  • __set
    — Makes private properties settable for backward compatibility.
  • __unset
    — Makes private properties un-settable for backward compatibility.
  • _do_query
    — Internal function to perform the mysql_query() call.
  • _escape
    — Escapes data. Works on arrays.
  • _insert_replace_helper
    — Helper function for insert and replace.
  • _real_escape
    — Real escape, using mysqli_real_escape_string() or mysql_real_escape_string().
  • _weak_escape
    — Do not use, deprecated. — deprecated
  • add_placeholder_escape
    — Adds a placeholder escape string, to escape anything that resembles a printf() placeholder.
  • bail
    — Wraps errors in a nice header and footer and dies.
  • check_ascii
    — Checks if a string is ASCII.
  • check_connection
    — Checks that the connection to the database is still up. If not, try to reconnect.
  • check_database_version
    — Determines whether MySQL database is at least the required minimum version.
  • check_safe_collation
    — Checks if the query is accessing a collation considered safe on the current version of MySQL.
  • close
    — Closes the current database connection.
  • db_connect
    — Connects to and selects database.
  • db_server_info
    — Retrieves full database server information.
  • db_version
    — Retrieves the database server version.
  • delete
    — Deletes a row in the table.
  • determine_charset
    — Determines the best charset and collation to use given a charset and collation.
  • esc_like
    — First half of escaping for `LIKE` special characters `%` and `_` before preparing for SQL.
  • escape
    — Do not use, deprecated. — deprecated
  • escape_by_ref
    — Escapes content by reference for insertion into the database, for security.
  • flush
    — Kills cached query results.
  • get_blog_prefix
    — Gets blog prefix.
  • get_caller
    — Retrieves a comma-separated list of the names of the functions that called wpdb.
  • get_charset_collate
    — Retrieves the database character collate.
  • get_col
    — Retrieves one column from the database.
  • get_col_charset
    — Retrieves the character set for the given column.
  • get_col_info
    — Retrieves column metadata from the last query.
  • get_col_length
    — Retrieves the maximum string length allowed in a given column.
  • get_results
    — Retrieves an entire SQL result set from the database (i.e., many rows).
  • get_row
    — Retrieves one row from the database.
  • get_table_charset
    — Retrieves the character set for the given table.
  • get_table_from_query
    — Finds the first table name referenced in a query.
  • get_var
    — Retrieves one variable from the database.
  • has_cap
    — Determines whether the database or WPDB supports a particular feature.
  • hide_errors
    — Disables showing of database errors.
  • init_charset
    — Sets $this->charset and $this->collate.
  • insert
    — Inserts a row into the table.
  • load_col_info
    — Loads the column metadata from the last query.
  • log_query
    — Logs query data.
  • parse_db_host
    — Parses the DB_HOST setting to interpret it for mysqli_real_connect().
  • placeholder_escape
    — Generates and returns a placeholder escape string for use in queries returned by ::prepare().
  • prepare
    — Prepares a SQL query for safe execution.
  • print_error
    — Prints SQL/DB error.
  • process_field_charsets
    — Adds field charsets to field/value/format arrays generated by wpdb::process_field_formats().
  • process_field_formats
    — Prepares arrays of value/format pairs as passed to wpdb CRUD methods.
  • process_field_lengths
    — For string fields, records the maximum string length that field can safely save.
  • process_fields
    — Processes arrays of field/value pairs and field formats.
  • query
    — Performs a database query, using current database connection.
  • remove_placeholder_escape
    — Removes the placeholder escape strings from a query.
  • replace
    — Replaces a row in the table.
  • select
    — Selects a database using the current or provided database connection.
  • set_blog_id
    — Sets blog ID.
  • set_charset
    — Sets the connection’s character set.
  • set_prefix
    — Sets the table prefix for the WordPress tables.
  • set_sql_mode
    — Changes the current SQL mode, and ensures its WordPress compatibility.
  • show_errors
    — Enables showing of database errors.
  • strip_invalid_text
    — Strips any invalid characters based on value/charset pairs.
  • strip_invalid_text_for_column
    — Strips any invalid characters from the string for a given table and column.
  • strip_invalid_text_from_query
    — Strips any invalid characters from the query.
  • supports_collation
    — Determines whether the database supports collation. — deprecated
  • suppress_errors
    — Enables or disables suppressing of database errors.
  • tables
    — Returns an array of WordPress tables.
  • timer_start
    — Starts the timer, for debugging purposes.
  • timer_stop
    — Stops the debugging timer.
  • update
    — Updates a row in the table.

File: wp-includes/class-wpdb.php.
View all references

class wpdb {

	/**
	 * Whether to show SQL/DB errors.
	 *
	 * Default is to show errors if both WP_DEBUG and WP_DEBUG_DISPLAY evaluate to true.
	 *
	 * @since 0.71
	 *
	 * @var bool
	 */
	public $show_errors = false;

	/**
	 * Whether to suppress errors during the DB bootstrapping. Default false.
	 *
	 * @since 2.5.0
	 *
	 * @var bool
	 */
	public $suppress_errors = false;

	/**
	 * The error encountered during the last query.
	 *
	 * @since 2.5.0
	 *
	 * @var string
	 */
	public $last_error = '';

	/**
	 * The number of queries made.
	 *
	 * @since 1.2.0
	 *
	 * @var int
	 */
	public $num_queries = 0;

	/**
	 * Count of rows returned by the last query.
	 *
	 * @since 0.71
	 *
	 * @var int
	 */
	public $num_rows = 0;

	/**
	 * Count of rows affected by the last query.
	 *
	 * @since 0.71
	 *
	 * @var int
	 */
	public $rows_affected = 0;

	/**
	 * The ID generated for an AUTO_INCREMENT column by the last query (usually INSERT).
	 *
	 * @since 0.71
	 *
	 * @var int
	 */
	public $insert_id = 0;

	/**
	 * The last query made.
	 *
	 * @since 0.71
	 *
	 * @var string
	 */
	public $last_query;

	/**
	 * Results of the last query.
	 *
	 * @since 0.71
	 *
	 * @var stdClass[]|null
	 */
	public $last_result;

	/**
	 * Database query result.
	 *
	 * Possible values:
	 *
	 * - For successful SELECT, SHOW, DESCRIBE, or EXPLAIN queries:
	 *   - `mysqli_result` instance when the `mysqli` driver is in use
	 *   - `resource` when the older `mysql` driver is in use
	 * - `true` for other query types that were successful
	 * - `null` if a query is yet to be made or if the result has since been flushed
	 * - `false` if the query returned an error
	 *
	 * @since 0.71
	 *
	 * @var mysqli_result|resource|bool|null
	 */
	protected $result;

	/**
	 * Cached column info, for sanity checking data before inserting.
	 *
	 * @since 4.2.0
	 *
	 * @var array
	 */
	protected $col_meta = array();

	/**
	 * Calculated character sets keyed by table name.
	 *
	 * @since 4.2.0
	 *
	 * @var string[]
	 */
	protected $table_charset = array();

	/**
	 * Whether text fields in the current query need to be sanity checked.
	 *
	 * @since 4.2.0
	 *
	 * @var bool
	 */
	protected $check_current_query = true;

	/**
	 * Flag to ensure we don't run into recursion problems when checking the collation.
	 *
	 * @since 4.2.0
	 *
	 * @see wpdb::check_safe_collation()
	 * @var bool
	 */
	private $checking_collation = false;

	/**
	 * Saved info on the table column.
	 *
	 * @since 0.71
	 *
	 * @var array
	 */
	protected $col_info;

	/**
	 * Log of queries that were executed, for debugging purposes.
	 *
	 * @since 1.5.0
	 * @since 2.5.0 The third element in each query log was added to record the calling functions.
	 * @since 5.1.0 The fourth element in each query log was added to record the start time.
	 * @since 5.3.0 The fifth element in each query log was added to record custom data.
	 *
	 * @var array[] {
	 *     Array of arrays containing information about queries that were executed.
	 *
	 *     @type array ...$0 {
	 *         Data for each query.
	 *
	 *         @type string $0 The query's SQL.
	 *         @type float  $1 Total time spent on the query, in seconds.
	 *         @type string $2 Comma-separated list of the calling functions.
	 *         @type float  $3 Unix timestamp of the time at the start of the query.
	 *         @type array  $4 Custom query data.
	 *     }
	 * }
	 */
	public $queries;

	/**
	 * The number of times to retry reconnecting before dying. Default 5.
	 *
	 * @since 3.9.0
	 *
	 * @see wpdb::check_connection()
	 * @var int
	 */
	protected $reconnect_retries = 5;

	/**
	 * WordPress table prefix.
	 *
	 * You can set this to have multiple WordPress installations in a single database.
	 * The second reason is for possible security precautions.
	 *
	 * @since 2.5.0
	 *
	 * @var string
	 */
	public $prefix = '';

	/**
	 * WordPress base table prefix.
	 *
	 * @since 3.0.0
	 *
	 * @var string
	 */
	public $base_prefix;

	/**
	 * Whether the database queries are ready to start executing.
	 *
	 * @since 2.3.2
	 *
	 * @var bool
	 */
	public $ready = false;

	/**
	 * Blog ID.
	 *
	 * @since 3.0.0
	 *
	 * @var int
	 */
	public $blogid = 0;

	/**
	 * Site ID.
	 *
	 * @since 3.0.0
	 *
	 * @var int
	 */
	public $siteid = 0;

	/**
	 * List of WordPress per-site tables.
	 *
	 * @since 2.5.0
	 *
	 * @see wpdb::tables()
	 * @var string[]
	 */
	public $tables = array(
		'posts',
		'comments',
		'links',
		'options',
		'postmeta',
		'terms',
		'term_taxonomy',
		'term_relationships',
		'termmeta',
		'commentmeta',
	);

	/**
	 * List of deprecated WordPress tables.
	 *
	 * 'categories', 'post2cat', and 'link2cat' were deprecated in 2.3.0, db version 5539.
	 *
	 * @since 2.9.0
	 *
	 * @see wpdb::tables()
	 * @var string[]
	 */
	public $old_tables = array( 'categories', 'post2cat', 'link2cat' );

	/**
	 * List of WordPress global tables.
	 *
	 * @since 3.0.0
	 *
	 * @see wpdb::tables()
	 * @var string[]
	 */
	public $global_tables = array( 'users', 'usermeta' );

	/**
	 * List of Multisite global tables.
	 *
	 * @since 3.0.0
	 *
	 * @see wpdb::tables()
	 * @var string[]
	 */
	public $ms_global_tables = array(
		'blogs',
		'blogmeta',
		'signups',
		'site',
		'sitemeta',
		'registration_log',
	);

	/**
	 * List of deprecated WordPress Multisite global tables.
	 *
	 * @since 6.1.0
	 *
	 * @see wpdb::tables()
	 * @var string[]
	 */
	public $old_ms_global_tables = array( 'sitecategories' );

	/**
	 * WordPress Comments table.
	 *
	 * @since 1.5.0
	 *
	 * @var string
	 */
	public $comments;

	/**
	 * WordPress Comment Metadata table.
	 *
	 * @since 2.9.0
	 *
	 * @var string
	 */
	public $commentmeta;

	/**
	 * WordPress Links table.
	 *
	 * @since 1.5.0
	 *
	 * @var string
	 */
	public $links;

	/**
	 * WordPress Options table.
	 *
	 * @since 1.5.0
	 *
	 * @var string
	 */
	public $options;

	/**
	 * WordPress Post Metadata table.
	 *
	 * @since 1.5.0
	 *
	 * @var string
	 */
	public $postmeta;

	/**
	 * WordPress Posts table.
	 *
	 * @since 1.5.0
	 *
	 * @var string
	 */
	public $posts;

	/**
	 * WordPress Terms table.
	 *
	 * @since 2.3.0
	 *
	 * @var string
	 */
	public $terms;

	/**
	 * WordPress Term Relationships table.
	 *
	 * @since 2.3.0
	 *
	 * @var string
	 */
	public $term_relationships;

	/**
	 * WordPress Term Taxonomy table.
	 *
	 * @since 2.3.0
	 *
	 * @var string
	 */
	public $term_taxonomy;

	/**
	 * WordPress Term Meta table.
	 *
	 * @since 4.4.0
	 *
	 * @var string
	 */
	public $termmeta;

	//
	// Global and Multisite tables
	//

	/**
	 * WordPress User Metadata table.
	 *
	 * @since 2.3.0
	 *
	 * @var string
	 */
	public $usermeta;

	/**
	 * WordPress Users table.
	 *
	 * @since 1.5.0
	 *
	 * @var string
	 */
	public $users;

	/**
	 * Multisite Blogs table.
	 *
	 * @since 3.0.0
	 *
	 * @var string
	 */
	public $blogs;

	/**
	 * Multisite Blog Metadata table.
	 *
	 * @since 5.1.0
	 *
	 * @var string
	 */
	public $blogmeta;

	/**
	 * Multisite Registration Log table.
	 *
	 * @since 3.0.0
	 *
	 * @var string
	 */
	public $registration_log;

	/**
	 * Multisite Signups table.
	 *
	 * @since 3.0.0
	 *
	 * @var string
	 */
	public $signups;

	/**
	 * Multisite Sites table.
	 *
	 * @since 3.0.0
	 *
	 * @var string
	 */
	public $site;

	/**
	 * Multisite Sitewide Terms table.
	 *
	 * @since 3.0.0
	 *
	 * @var string
	 */
	public $sitecategories;

	/**
	 * Multisite Site Metadata table.
	 *
	 * @since 3.0.0
	 *
	 * @var string
	 */
	public $sitemeta;

	/**
	 * Format specifiers for DB columns.
	 *
	 * Columns not listed here default to %s. Initialized during WP load.
	 * Keys are column names, values are format types: 'ID' => '%d'.
	 *
	 * @since 2.8.0
	 *
	 * @see wpdb::prepare()
	 * @see wpdb::insert()
	 * @see wpdb::update()
	 * @see wpdb::delete()
	 * @see wp_set_wpdb_vars()
	 * @var array
	 */
	public $field_types = array();

	/**
	 * Database table columns charset.
	 *
	 * @since 2.2.0
	 *
	 * @var string
	 */
	public $charset;

	/**
	 * Database table columns collate.
	 *
	 * @since 2.2.0
	 *
	 * @var string
	 */
	public $collate;

	/**
	 * Database Username.
	 *
	 * @since 2.9.0
	 *
	 * @var string
	 */
	protected $dbuser;

	/**
	 * Database Password.
	 *
	 * @since 3.1.0
	 *
	 * @var string
	 */
	protected $dbpassword;

	/**
	 * Database Name.
	 *
	 * @since 3.1.0
	 *
	 * @var string
	 */
	protected $dbname;

	/**
	 * Database Host.
	 *
	 * @since 3.1.0
	 *
	 * @var string
	 */
	protected $dbhost;

	/**
	 * Database handle.
	 *
	 * Possible values:
	 *
	 * - `mysqli` instance when the `mysqli` driver is in use
	 * - `resource` when the older `mysql` driver is in use
	 * - `null` if the connection is yet to be made or has been closed
	 * - `false` if the connection has failed
	 *
	 * @since 0.71
	 *
	 * @var mysqli|resource|false|null
	 */
	protected $dbh;

	/**
	 * A textual description of the last query/get_row/get_var call.
	 *
	 * @since 3.0.0
	 *
	 * @var string
	 */
	public $func_call;

	/**
	 * Whether MySQL is used as the database engine.
	 *
	 * Set in wpdb::db_connect() to true, by default. This is used when checking
	 * against the required MySQL version for WordPress. Normally, a replacement
	 * database drop-in (db.php) will skip these checks, but setting this to true
	 * will force the checks to occur.
	 *
	 * @since 3.3.0
	 *
	 * @var bool
	 */
	public $is_mysql = null;

	/**
	 * A list of incompatible SQL modes.
	 *
	 * @since 3.9.0
	 *
	 * @var string[]
	 */
	protected $incompatible_modes = array(
		'NO_ZERO_DATE',
		'ONLY_FULL_GROUP_BY',
		'STRICT_TRANS_TABLES',
		'STRICT_ALL_TABLES',
		'TRADITIONAL',
		'ANSI',
	);

	/**
	 * Whether to use mysqli over mysql. Default false.
	 *
	 * @since 3.9.0
	 *
	 * @var bool
	 */
	private $use_mysqli = false;

	/**
	 * Whether we've managed to successfully connect at some point.
	 *
	 * @since 3.9.0
	 *
	 * @var bool
	 */
	private $has_connected = false;

	/**
	 * Time when the last query was performed.
	 *
	 * Only set when `SAVEQUERIES` is defined and truthy.
	 *
	 * @since 1.5.0
	 *
	 * @var float
	 */
	public $time_start = null;

	/**
	 * The last SQL error that was encountered.
	 *
	 * @since 2.5.0
	 *
	 * @var WP_Error|string
	 */
	public $error = null;

	/**
	 * Connects to the database server and selects a database.
	 *
	 * Does the actual setting up
	 * of the class properties and connection to the database.
	 *
	 * @since 2.0.8
	 *
	 * @link https://core.trac.wordpress.org/ticket/3354
	 *
	 * @param string $dbuser     Database user.
	 * @param string $dbpassword Database password.
	 * @param string $dbname     Database name.
	 * @param string $dbhost     Database host.
	 */
	public function __construct( $dbuser, $dbpassword, $dbname, $dbhost ) {
		if ( WP_DEBUG && WP_DEBUG_DISPLAY ) {
			$this->show_errors();
		}

		// Use the `mysqli` extension if it exists unless `WP_USE_EXT_MYSQL` is defined as true.
		if ( function_exists( 'mysqli_connect' ) ) {
			$this->use_mysqli = true;

			if ( defined( 'WP_USE_EXT_MYSQL' ) ) {
				$this->use_mysqli = ! WP_USE_EXT_MYSQL;
			}
		}

		$this->dbuser     = $dbuser;
		$this->dbpassword = $dbpassword;
		$this->dbname     = $dbname;
		$this->dbhost     = $dbhost;

		// wp-config.php creation will manually connect when ready.
		if ( defined( 'WP_SETUP_CONFIG' ) ) {
			return;
		}

		$this->db_connect();
	}

	/**
	 * Makes private properties readable for backward compatibility.
	 *
	 * @since 3.5.0
	 *
	 * @param string $name The private member to get, and optionally process.
	 * @return mixed The private member.
	 */
	public function __get( $name ) {
		if ( 'col_info' === $name ) {
			$this->load_col_info();
		}

		return $this->$name;
	}

	/**
	 * Makes private properties settable for backward compatibility.
	 *
	 * @since 3.5.0
	 *
	 * @param string $name  The private member to set.
	 * @param mixed  $value The value to set.
	 */
	public function __set( $name, $value ) {
		$protected_members = array(
			'col_meta',
			'table_charset',
			'check_current_query',
		);
		if ( in_array( $name, $protected_members, true ) ) {
			return;
		}
		$this->$name = $value;
	}

	/**
	 * Makes private properties check-able for backward compatibility.
	 *
	 * @since 3.5.0
	 *
	 * @param string $name The private member to check.
	 * @return bool If the member is set or not.
	 */
	public function __isset( $name ) {
		return isset( $this->$name );
	}

	/**
	 * Makes private properties un-settable for backward compatibility.
	 *
	 * @since 3.5.0
	 *
	 * @param string $name  The private member to unset
	 */
	public function __unset( $name ) {
		unset( $this->$name );
	}

	/**
	 * Sets $this->charset and $this->collate.
	 *
	 * @since 3.1.0
	 */
	public function init_charset() {
		$charset = '';
		$collate = '';

		if ( function_exists( 'is_multisite' ) && is_multisite() ) {
			$charset = 'utf8';
			if ( defined( 'DB_COLLATE' ) && DB_COLLATE ) {
				$collate = DB_COLLATE;
			} else {
				$collate = 'utf8_general_ci';
			}
		} elseif ( defined( 'DB_COLLATE' ) ) {
			$collate = DB_COLLATE;
		}

		if ( defined( 'DB_CHARSET' ) ) {
			$charset = DB_CHARSET;
		}

		$charset_collate = $this->determine_charset( $charset, $collate );

		$this->charset = $charset_collate['charset'];
		$this->collate = $charset_collate['collate'];
	}

	/**
	 * Determines the best charset and collation to use given a charset and collation.
	 *
	 * For example, when able, utf8mb4 should be used instead of utf8.
	 *
	 * @since 4.6.0
	 *
	 * @param string $charset The character set to check.
	 * @param string $collate The collation to check.
	 * @return array {
	 *     The most appropriate character set and collation to use.
	 *
	 *     @type string $charset Character set.
	 *     @type string $collate Collation.
	 * }
	 */
	public function determine_charset( $charset, $collate ) {
		if ( ( $this->use_mysqli && ! ( $this->dbh instanceof mysqli ) ) || empty( $this->dbh ) ) {
			return compact( 'charset', 'collate' );
		}

		if ( 'utf8' === $charset && $this->has_cap( 'utf8mb4' ) ) {
			$charset = 'utf8mb4';
		}

		if ( 'utf8mb4' === $charset && ! $this->has_cap( 'utf8mb4' ) ) {
			$charset = 'utf8';
			$collate = str_replace( 'utf8mb4_', 'utf8_', $collate );
		}

		if ( 'utf8mb4' === $charset ) {
			// _general_ is outdated, so we can upgrade it to _unicode_, instead.
			if ( ! $collate || 'utf8_general_ci' === $collate ) {
				$collate = 'utf8mb4_unicode_ci';
			} else {
				$collate = str_replace( 'utf8_', 'utf8mb4_', $collate );
			}
		}

		// _unicode_520_ is a better collation, we should use that when it's available.
		if ( $this->has_cap( 'utf8mb4_520' ) && 'utf8mb4_unicode_ci' === $collate ) {
			$collate = 'utf8mb4_unicode_520_ci';
		}

		return compact( 'charset', 'collate' );
	}

	/**
	 * Sets the connection's character set.
	 *
	 * @since 3.1.0
	 *
	 * @param mysqli|resource $dbh     The connection returned by `mysqli_connect()` or `mysql_connect()`.
	 * @param string          $charset Optional. The character set. Default null.
	 * @param string          $collate Optional. The collation. Default null.
	 */
	public function set_charset( $dbh, $charset = null, $collate = null ) {
		if ( ! isset( $charset ) ) {
			$charset = $this->charset;
		}
		if ( ! isset( $collate ) ) {
			$collate = $this->collate;
		}
		if ( $this->has_cap( 'collation' ) && ! empty( $charset ) ) {
			$set_charset_succeeded = true;

			if ( $this->use_mysqli ) {
				if ( function_exists( 'mysqli_set_charset' ) && $this->has_cap( 'set_charset' ) ) {
					$set_charset_succeeded = mysqli_set_charset( $dbh, $charset );
				}

				if ( $set_charset_succeeded ) {
					$query = $this->prepare( 'SET NAMES %s', $charset );
					if ( ! empty( $collate ) ) {
						$query .= $this->prepare( ' COLLATE %s', $collate );
					}
					mysqli_query( $dbh, $query );
				}
			} else {
				if ( function_exists( 'mysql_set_charset' ) && $this->has_cap( 'set_charset' ) ) {
					$set_charset_succeeded = mysql_set_charset( $charset, $dbh );
				}
				if ( $set_charset_succeeded ) {
					$query = $this->prepare( 'SET NAMES %s', $charset );
					if ( ! empty( $collate ) ) {
						$query .= $this->prepare( ' COLLATE %s', $collate );
					}
					mysql_query( $query, $dbh );
				}
			}
		}
	}

	/**
	 * Changes the current SQL mode, and ensures its WordPress compatibility.
	 *
	 * If no modes are passed, it will ensure the current MySQL server modes are compatible.
	 *
	 * @since 3.9.0
	 *
	 * @param array $modes Optional. A list of SQL modes to set. Default empty array.
	 */
	public function set_sql_mode( $modes = array() ) {
		if ( empty( $modes ) ) {
			if ( $this->use_mysqli ) {
				$res = mysqli_query( $this->dbh, 'SELECT @@SESSION.sql_mode' );
			} else {
				$res = mysql_query( 'SELECT @@SESSION.sql_mode', $this->dbh );
			}

			if ( empty( $res ) ) {
				return;
			}

			if ( $this->use_mysqli ) {
				$modes_array = mysqli_fetch_array( $res );
				if ( empty( $modes_array[0] ) ) {
					return;
				}
				$modes_str = $modes_array[0];
			} else {
				$modes_str = mysql_result( $res, 0 );
			}

			if ( empty( $modes_str ) ) {
				return;
			}

			$modes = explode( ',', $modes_str );
		}

		$modes = array_change_key_case( $modes, CASE_UPPER );

		/**
		 * Filters the list of incompatible SQL modes to exclude.
		 *
		 * @since 3.9.0
		 *
		 * @param array $incompatible_modes An array of incompatible modes.
		 */
		$incompatible_modes = (array) apply_filters( 'incompatible_sql_modes', $this->incompatible_modes );

		foreach ( $modes as $i => $mode ) {
			if ( in_array( $mode, $incompatible_modes, true ) ) {
				unset( $modes[ $i ] );
			}
		}

		$modes_str = implode( ',', $modes );

		if ( $this->use_mysqli ) {
			mysqli_query( $this->dbh, "SET SESSION sql_mode='$modes_str'" );
		} else {
			mysql_query( "SET SESSION sql_mode='$modes_str'", $this->dbh );
		}
	}

	/**
	 * Sets the table prefix for the WordPress tables.
	 *
	 * @since 2.5.0
	 *
	 * @param string $prefix          Alphanumeric name for the new prefix.
	 * @param bool   $set_table_names Optional. Whether the table names, e.g. wpdb::$posts,
	 *                                should be updated or not. Default true.
	 * @return string|WP_Error Old prefix or WP_Error on error.
	 */
	public function set_prefix( $prefix, $set_table_names = true ) {

		if ( preg_match( '|[^a-z0-9_]|i', $prefix ) ) {
			return new WP_Error( 'invalid_db_prefix', 'Invalid database prefix' );
		}

		$old_prefix = is_multisite() ? '' : $prefix;

		if ( isset( $this->base_prefix ) ) {
			$old_prefix = $this->base_prefix;
		}

		$this->base_prefix = $prefix;

		if ( $set_table_names ) {
			foreach ( $this->tables( 'global' ) as $table => $prefixed_table ) {
				$this->$table = $prefixed_table;
			}

			if ( is_multisite() && empty( $this->blogid ) ) {
				return $old_prefix;
			}

			$this->prefix = $this->get_blog_prefix();

			foreach ( $this->tables( 'blog' ) as $table => $prefixed_table ) {
				$this->$table = $prefixed_table;
			}

			foreach ( $this->tables( 'old' ) as $table => $prefixed_table ) {
				$this->$table = $prefixed_table;
			}
		}
		return $old_prefix;
	}

	/**
	 * Sets blog ID.
	 *
	 * @since 3.0.0
	 *
	 * @param int $blog_id
	 * @param int $network_id Optional.
	 * @return int Previous blog ID.
	 */
	public function set_blog_id( $blog_id, $network_id = 0 ) {
		if ( ! empty( $network_id ) ) {
			$this->siteid = $network_id;
		}

		$old_blog_id  = $this->blogid;
		$this->blogid = $blog_id;

		$this->prefix = $this->get_blog_prefix();

		foreach ( $this->tables( 'blog' ) as $table => $prefixed_table ) {
			$this->$table = $prefixed_table;
		}

		foreach ( $this->tables( 'old' ) as $table => $prefixed_table ) {
			$this->$table = $prefixed_table;
		}

		return $old_blog_id;
	}

	/**
	 * Gets blog prefix.
	 *
	 * @since 3.0.0
	 *
	 * @param int $blog_id Optional.
	 * @return string Blog prefix.
	 */
	public function get_blog_prefix( $blog_id = null ) {
		if ( is_multisite() ) {
			if ( null === $blog_id ) {
				$blog_id = $this->blogid;
			}

			$blog_id = (int) $blog_id;

			if ( defined( 'MULTISITE' ) && ( 0 === $blog_id || 1 === $blog_id ) ) {
				return $this->base_prefix;
			} else {
				return $this->base_prefix . $blog_id . '_';
			}
		} else {
			return $this->base_prefix;
		}
	}

	/**
	 * Returns an array of WordPress tables.
	 *
	 * Also allows for the `CUSTOM_USER_TABLE` and `CUSTOM_USER_META_TABLE` to override the WordPress users
	 * and usermeta tables that would otherwise be determined by the prefix.
	 *
	 * The `$scope` argument can take one of the following:
	 *
	 * - 'all' - returns 'all' and 'global' tables. No old tables are returned.
	 * - 'blog' - returns the blog-level tables for the queried blog.
	 * - 'global' - returns the global tables for the installation, returning multisite tables only on multisite.
	 * - 'ms_global' - returns the multisite global tables, regardless if current installation is multisite.
	 * - 'old' - returns tables which are deprecated.
	 *
	 * @since 3.0.0
	 * @since 6.1.0 `old` now includes deprecated multisite global tables only on multisite.
	 *
	 * @uses wpdb::$tables
	 * @uses wpdb::$old_tables
	 * @uses wpdb::$global_tables
	 * @uses wpdb::$ms_global_tables
	 * @uses wpdb::$old_ms_global_tables
	 *
	 * @param string $scope   Optional. Possible values include 'all', 'global', 'ms_global', 'blog',
	 *                        or 'old' tables. Default 'all'.
	 * @param bool   $prefix  Optional. Whether to include table prefixes. If blog prefix is requested,
	 *                        then the custom users and usermeta tables will be mapped. Default true.
	 * @param int    $blog_id Optional. The blog_id to prefix. Used only when prefix is requested.
	 *                        Defaults to `wpdb::$blogid`.
	 * @return string[] Table names. When a prefix is requested, the key is the unprefixed table name.
	 */
	public function tables( $scope = 'all', $prefix = true, $blog_id = 0 ) {
		switch ( $scope ) {
			case 'all':
				$tables = array_merge( $this->global_tables, $this->tables );
				if ( is_multisite() ) {
					$tables = array_merge( $tables, $this->ms_global_tables );
				}
				break;
			case 'blog':
				$tables = $this->tables;
				break;
			case 'global':
				$tables = $this->global_tables;
				if ( is_multisite() ) {
					$tables = array_merge( $tables, $this->ms_global_tables );
				}
				break;
			case 'ms_global':
				$tables = $this->ms_global_tables;
				break;
			case 'old':
				$tables = $this->old_tables;
				if ( is_multisite() ) {
					$tables = array_merge( $tables, $this->old_ms_global_tables );
				}
				break;
			default:
				return array();
		}

		if ( $prefix ) {
			if ( ! $blog_id ) {
				$blog_id = $this->blogid;
			}
			$blog_prefix   = $this->get_blog_prefix( $blog_id );
			$base_prefix   = $this->base_prefix;
			$global_tables = array_merge( $this->global_tables, $this->ms_global_tables );
			foreach ( $tables as $k => $table ) {
				if ( in_array( $table, $global_tables, true ) ) {
					$tables[ $table ] = $base_prefix . $table;
				} else {
					$tables[ $table ] = $blog_prefix . $table;
				}
				unset( $tables[ $k ] );
			}

			if ( isset( $tables['users'] ) && defined( 'CUSTOM_USER_TABLE' ) ) {
				$tables['users'] = CUSTOM_USER_TABLE;
			}

			if ( isset( $tables['usermeta'] ) && defined( 'CUSTOM_USER_META_TABLE' ) ) {
				$tables['usermeta'] = CUSTOM_USER_META_TABLE;
			}
		}

		return $tables;
	}

	/**
	 * Selects a database using the current or provided database connection.
	 *
	 * The database name will be changed based on the current database connection.
	 * On failure, the execution will bail and display a DB error.
	 *
	 * @since 0.71
	 *
	 * @param string          $db  Database name.
	 * @param mysqli|resource $dbh Optional database connection.
	 */
	public function select( $db, $dbh = null ) {
		if ( is_null( $dbh ) ) {
			$dbh = $this->dbh;
		}

		if ( $this->use_mysqli ) {
			$success = mysqli_select_db( $dbh, $db );
		} else {
			$success = mysql_select_db( $db, $dbh );
		}
		if ( ! $success ) {
			$this->ready = false;
			if ( ! did_action( 'template_redirect' ) ) {
				wp_load_translations_early();

				$message = '<h1>' . __( 'Cannot select database' ) . "</h1>n";

				$message .= '<p>' . sprintf(
					/* translators: %s: Database name. */
					__( 'The database server could be connected to (which means your username and password is okay) but the %s database could not be selected.' ),
					'<code>' . htmlspecialchars( $db, ENT_QUOTES ) . '</code>'
				) . "</p>n";

				$message .= "<ul>n";
				$message .= '<li>' . __( 'Are you sure it exists?' ) . "</li>n";

				$message .= '<li>' . sprintf(
					/* translators: 1: Database user, 2: Database name. */
					__( 'Does the user %1$s have permission to use the %2$s database?' ),
					'<code>' . htmlspecialchars( $this->dbuser, ENT_QUOTES ) . '</code>',
					'<code>' . htmlspecialchars( $db, ENT_QUOTES ) . '</code>'
				) . "</li>n";

				$message .= '<li>' . sprintf(
					/* translators: %s: Database name. */
					__( 'On some systems the name of your database is prefixed with your username, so it would be like <code>username_%1$s</code>. Could that be the problem?' ),
					htmlspecialchars( $db, ENT_QUOTES )
				) . "</li>n";

				$message .= "</ul>n";

				$message .= '<p>' . sprintf(
					/* translators: %s: Support forums URL. */
					__( 'If you do not know how to set up a database you should <strong>contact your host</strong>. If all else fails you may find help at the <a href="%s">WordPress Support Forums</a>.' ),
					__( 'https://wordpress.org/support/forums/' )
				) . "</p>n";

				$this->bail( $message, 'db_select_fail' );
			}
		}
	}

	/**
	 * Do not use, deprecated.
	 *
	 * Use esc_sql() or wpdb::prepare() instead.
	 *
	 * @since 2.8.0
	 * @deprecated 3.6.0 Use wpdb::prepare()
	 * @see wpdb::prepare()
	 * @see esc_sql()
	 *
	 * @param string $string
	 * @return string
	 */
	public function _weak_escape( $string ) {
		if ( func_num_args() === 1 && function_exists( '_deprecated_function' ) ) {
			_deprecated_function( __METHOD__, '3.6.0', 'wpdb::prepare() or esc_sql()' );
		}
		return addslashes( $string );
	}

	/**
	 * Real escape, using mysqli_real_escape_string() or mysql_real_escape_string().
	 *
	 * @since 2.8.0
	 *
	 * @see mysqli_real_escape_string()
	 * @see mysql_real_escape_string()
	 *
	 * @param string $string String to escape.
	 * @return string Escaped string.
	 */
	public function _real_escape( $string ) {
		if ( ! is_scalar( $string ) ) {
			return '';
		}

		if ( $this->dbh ) {
			if ( $this->use_mysqli ) {
				$escaped = mysqli_real_escape_string( $this->dbh, $string );
			} else {
				$escaped = mysql_real_escape_string( $string, $this->dbh );
			}
		} else {
			$class = get_class( $this );

			wp_load_translations_early();
			/* translators: %s: Database access abstraction class, usually wpdb or a class extending wpdb. */
			_doing_it_wrong( $class, sprintf( __( '%s must set a database connection for use with escaping.' ), $class ), '3.6.0' );

			$escaped = addslashes( $string );
		}

		return $this->add_placeholder_escape( $escaped );
	}

	/**
	 * Escapes data. Works on arrays.
	 *
	 * @since 2.8.0
	 *
	 * @uses wpdb::_real_escape()
	 *
	 * @param string|array $data Data to escape.
	 * @return string|array Escaped data, in the same type as supplied.
	 */
	public function _escape( $data ) {
		if ( is_array( $data ) ) {
			foreach ( $data as $k => $v ) {
				if ( is_array( $v ) ) {
					$data[ $k ] = $this->_escape( $v );
				} else {
					$data[ $k ] = $this->_real_escape( $v );
				}
			}
		} else {
			$data = $this->_real_escape( $data );
		}

		return $data;
	}

	/**
	 * Do not use, deprecated.
	 *
	 * Use esc_sql() or wpdb::prepare() instead.
	 *
	 * @since 0.71
	 * @deprecated 3.6.0 Use wpdb::prepare()
	 * @see wpdb::prepare()
	 * @see esc_sql()
	 *
	 * @param string|array $data Data to escape.
	 * @return string|array Escaped data, in the same type as supplied.
	 */
	public function escape( $data ) {
		if ( func_num_args() === 1 && function_exists( '_deprecated_function' ) ) {
			_deprecated_function( __METHOD__, '3.6.0', 'wpdb::prepare() or esc_sql()' );
		}
		if ( is_array( $data ) ) {
			foreach ( $data as $k => $v ) {
				if ( is_array( $v ) ) {
					$data[ $k ] = $this->escape( $v, 'recursive' );
				} else {
					$data[ $k ] = $this->_weak_escape( $v, 'internal' );
				}
			}
		} else {
			$data = $this->_weak_escape( $data, 'internal' );
		}

		return $data;
	}

	/**
	 * Escapes content by reference for insertion into the database, for security.
	 *
	 * @uses wpdb::_real_escape()
	 *
	 * @since 2.3.0
	 *
	 * @param string $string String to escape.
	 */
	public function escape_by_ref( &$string ) {
		if ( ! is_float( $string ) ) {
			$string = $this->_real_escape( $string );
		}
	}

	/**
	 * Prepares a SQL query for safe execution.
	 *
	 * Uses sprintf()-like syntax. The following placeholders can be used in the query string:
	 *
	 * - %d (integer)
	 * - %f (float)
	 * - %s (string)
	 *
	 * All placeholders MUST be left unquoted in the query string. A corresponding argument
	 * MUST be passed for each placeholder.
	 *
	 * Note: There is one exception to the above: for compatibility with old behavior,
	 * numbered or formatted string placeholders (eg, `%1$s`, `%5s`) will not have quotes
	 * added by this function, so should be passed with appropriate quotes around them.
	 *
	 * Literal percentage signs (`%`) in the query string must be written as `%%`. Percentage wildcards
	 * (for example, to use in LIKE syntax) must be passed via a substitution argument containing
	 * the complete LIKE string, these cannot be inserted directly in the query string.
	 * Also see wpdb::esc_like().
	 *
	 * Arguments may be passed as individual arguments to the method, or as a single array
	 * containing all arguments. A combination of the two is not supported.
	 *
	 * Examples:
	 *
	 *     $wpdb->prepare(
	 *         "SELECT * FROM `table` WHERE `column` = %s AND `field` = %d OR `other_field` LIKE %s",
	 *         array( 'foo', 1337, '%bar' )
	 *     );
	 *
	 *     $wpdb->prepare(
	 *         "SELECT DATE_FORMAT(`field`, '%%c') FROM `table` WHERE `column` = %s",
	 *         'foo'
	 *     );
	 *
	 * @since 2.3.0
	 * @since 5.3.0 Formalized the existing and already documented `...$args` parameter
	 *              by updating the function signature. The second parameter was changed
	 *              from `$args` to `...$args`.
	 *
	 * @link https://www.php.net/sprintf Description of syntax.
	 *
	 * @param string      $query   Query statement with sprintf()-like placeholders.
	 * @param array|mixed $args    The array of variables to substitute into the query's placeholders
	 *                             if being called with an array of arguments, or the first variable
	 *                             to substitute into the query's placeholders if being called with
	 *                             individual arguments.
	 * @param mixed       ...$args Further variables to substitute into the query's placeholders
	 *                             if being called with individual arguments.
	 * @return string|void Sanitized query string, if there is a query to prepare.
	 */
	public function prepare( $query, ...$args ) {
		if ( is_null( $query ) ) {
			return;
		}

		// This is not meant to be foolproof -- but it will catch obviously incorrect usage.
		if ( strpos( $query, '%' ) === false ) {
			wp_load_translations_early();
			_doing_it_wrong(
				'wpdb::prepare',
				sprintf(
					/* translators: %s: wpdb::prepare() */
					__( 'The query argument of %s must have a placeholder.' ),
					'wpdb::prepare()'
				),
				'3.9.0'
			);
		}

		// If args were passed as an array (as in vsprintf), move them up.
		$passed_as_array = false;
		if ( isset( $args[0] ) && is_array( $args[0] ) && 1 === count( $args ) ) {
			$passed_as_array = true;
			$args            = $args[0];
		}

		foreach ( $args as $arg ) {
			if ( ! is_scalar( $arg ) && ! is_null( $arg ) ) {
				wp_load_translations_early();
				_doing_it_wrong(
					'wpdb::prepare',
					sprintf(
						/* translators: %s: Value type. */
						__( 'Unsupported value type (%s).' ),
						gettype( $arg )
					),
					'4.8.2'
				);
			}
		}

		/*
		 * Specify the formatting allowed in a placeholder. The following are allowed:
		 *
		 * - Sign specifier, e.g. $+d
		 * - Numbered placeholders, e.g. %1$s
		 * - Padding specifier, including custom padding characters, e.g. %05s, %'#5s
		 * - Alignment specifier, e.g. %05-s
		 * - Precision specifier, e.g. %.2f
		 */
		$allowed_format = '(?:[1-9][0-9]*[$])?[-+0-9]*(?: |0|'.)?[-+0-9]*(?:.[0-9]+)?';

		/*
		 * If a %s placeholder already has quotes around it, removing the existing quotes
		 * and re-inserting them ensures the quotes are consistent.
		 *
		 * For backward compatibility, this is only applied to %s, and not to placeholders like %1$s,
		 * which are frequently used in the middle of longer strings, or as table name placeholders.
		 */
		$query = str_replace( "'%s'", '%s', $query ); // Strip any existing single quotes.
		$query = str_replace( '"%s"', '%s', $query ); // Strip any existing double quotes.
		$query = preg_replace( '/(?<!%)%s/', "'%s'", $query ); // Quote the strings, avoiding escaped strings like %%s.

		$query = preg_replace( "/(?<!%)(%($allowed_format)?f)/", '%\2F', $query ); // Force floats to be locale-unaware.

		$query = preg_replace( "/%(?:%|$|(?!($allowed_format)?[sdF]))/", '%%\1', $query ); // Escape any unescaped percents.

		// Count the number of valid placeholders in the query.
		$placeholders = preg_match_all( "/(^|[^%]|(%%)+)%($allowed_format)?[sdF]/", $query, $matches );

		$args_count = count( $args );

		if ( $args_count !== $placeholders ) {
			if ( 1 === $placeholders && $passed_as_array ) {
				// If the passed query only expected one argument, but the wrong number of arguments were sent as an array, bail.
				wp_load_translations_early();
				_doing_it_wrong(
					'wpdb::prepare',
					__( 'The query only expected one placeholder, but an array of multiple placeholders was sent.' ),
					'4.9.0'
				);

				return;
			} else {
				/*
				 * If we don't have the right number of placeholders,
				 * but they were passed as individual arguments,
				 * or we were expecting multiple arguments in an array, throw a warning.
				 */
				wp_load_translations_early();
				_doing_it_wrong(
					'wpdb::prepare',
					sprintf(
						/* translators: 1: Number of placeholders, 2: Number of arguments passed. */
						__( 'The query does not contain the correct number of placeholders (%1$d) for the number of arguments passed (%2$d).' ),
						$placeholders,
						$args_count
					),
					'4.8.3'
				);

				/*
				 * If we don't have enough arguments to match the placeholders,
				 * return an empty string to avoid a fatal error on PHP 8.
				 */
				if ( $args_count < $placeholders ) {
					$max_numbered_placeholder = ! empty( $matches[3] ) ? max( array_map( 'intval', $matches[3] ) ) : 0;

					if ( ! $max_numbered_placeholder || $args_count < $max_numbered_placeholder ) {
						return '';
					}
				}
			}
		}

		array_walk( $args, array( $this, 'escape_by_ref' ) );
		$query = vsprintf( $query, $args );

		return $this->add_placeholder_escape( $query );
	}

	/**
	 * First half of escaping for `LIKE` special characters `%` and `_` before preparing for SQL.
	 *
	 * Use this only before wpdb::prepare() or esc_sql(). Reversing the order is very bad for security.
	 *
	 * Example Prepared Statement:
	 *
	 *     $wild = '%';
	 *     $find = 'only 43% of planets';
	 *     $like = $wild . $wpdb->esc_like( $find ) . $wild;
	 *     $sql  = $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_content LIKE %s", $like );
	 *
	 * Example Escape Chain:
	 *
	 *     $sql  = esc_sql( $wpdb->esc_like( $input ) );
	 *
	 * @since 4.0.0
	 *
	 * @param string $text The raw text to be escaped. The input typed by the user
	 *                     should have no extra or deleted slashes.
	 * @return string Text in the form of a LIKE phrase. The output is not SQL safe.
	 *                Call wpdb::prepare() or wpdb::_real_escape() next.
	 */
	public function esc_like( $text ) {
		return addcslashes( $text, '_%\' );
	}

	/**
	 * Prints SQL/DB error.
	 *
	 * @since 0.71
	 *
	 * @global array $EZSQL_ERROR Stores error information of query and error string.
	 *
	 * @param string $str The error to display.
	 * @return void|false Void if the showing of errors is enabled, false if disabled.
	 */
	public function print_error( $str = '' ) {
		global $EZSQL_ERROR;

		if ( ! $str ) {
			if ( $this->use_mysqli ) {
				$str = mysqli_error( $this->dbh );
			} else {
				$str = mysql_error( $this->dbh );
			}
		}
		$EZSQL_ERROR[] = array(
			'query'     => $this->last_query,
			'error_str' => $str,
		);

		if ( $this->suppress_errors ) {
			return false;
		}

		$caller = $this->get_caller();
		if ( $caller ) {
			// Not translated, as this will only appear in the error log.
			$error_str = sprintf( 'WordPress database error %1$s for query %2$s made by %3$s', $str, $this->last_query, $caller );
		} else {
			$error_str = sprintf( 'WordPress database error %1$s for query %2$s', $str, $this->last_query );
		}

		error_log( $error_str );

		// Are we showing errors?
		if ( ! $this->show_errors ) {
			return false;
		}

		wp_load_translations_early();

		// If there is an error then take note of it.
		if ( is_multisite() ) {
			$msg = sprintf(
				"%s [%s]n%sn",
				__( 'WordPress database error:' ),
				$str,
				$this->last_query
			);

			if ( defined( 'ERRORLOGFILE' ) ) {
				error_log( $msg, 3, ERRORLOGFILE );
			}
			if ( defined( 'DIEONDBERROR' ) ) {
				wp_die( $msg );
			}
		} else {
			$str   = htmlspecialchars( $str, ENT_QUOTES );
			$query = htmlspecialchars( $this->last_query, ENT_QUOTES );

			printf(
				'<div id="error"><p class="wpdberror"><strong>%s</strong> [%s]<br /><code>%s</code></p></div>',
				__( 'WordPress database error:' ),
				$str,
				$query
			);
		}
	}

	/**
	 * Enables showing of database errors.
	 *
	 * This function should be used only to enable showing of errors.
	 * wpdb::hide_errors() should be used instead for hiding errors.
	 *
	 * @since 0.71
	 *
	 * @see wpdb::hide_errors()
	 *
	 * @param bool $show Optional. Whether to show errors. Default true.
	 * @return bool Whether showing of errors was previously active.
	 */
	public function show_errors( $show = true ) {
		$errors            = $this->show_errors;
		$this->show_errors = $show;
		return $errors;
	}

	/**
	 * Disables showing of database errors.
	 *
	 * By default database errors are not shown.
	 *
	 * @since 0.71
	 *
	 * @see wpdb::show_errors()
	 *
	 * @return bool Whether showing of errors was previously active.
	 */
	public function hide_errors() {
		$show              = $this->show_errors;
		$this->show_errors = false;
		return $show;
	}

	/**
	 * Enables or disables suppressing of database errors.
	 *
	 * By default database errors are suppressed.
	 *
	 * @since 2.5.0
	 *
	 * @see wpdb::hide_errors()
	 *
	 * @param bool $suppress Optional. Whether to suppress errors. Default true.
	 * @return bool Whether suppressing of errors was previously active.
	 */
	public function suppress_errors( $suppress = true ) {
		$errors                = $this->suppress_errors;
		$this->suppress_errors = (bool) $suppress;
		return $errors;
	}

	/**
	 * Kills cached query results.
	 *
	 * @since 0.71
	 */
	public function flush() {
		$this->last_result   = array();
		$this->col_info      = null;
		$this->last_query    = null;
		$this->rows_affected = 0;
		$this->num_rows      = 0;
		$this->last_error    = '';

		if ( $this->use_mysqli && $this->result instanceof mysqli_result ) {
			mysqli_free_result( $this->result );
			$this->result = null;

			// Sanity check before using the handle.
			if ( empty( $this->dbh ) || ! ( $this->dbh instanceof mysqli ) ) {
				return;
			}

			// Clear out any results from a multi-query.
			while ( mysqli_more_results( $this->dbh ) ) {
				mysqli_next_result( $this->dbh );
			}
		} elseif ( is_resource( $this->result ) ) {
			mysql_free_result( $this->result );
		}
	}

	/**
	 * Connects to and selects database.
	 *
	 * If `$allow_bail` is false, the lack of database connection will need to be handled manually.
	 *
	 * @since 3.0.0
	 * @since 3.9.0 $allow_bail parameter added.
	 *
	 * @param bool $allow_bail Optional. Allows the function to bail. Default true.
	 * @return bool True with a successful connection, false on failure.
	 */
	public function db_connect( $allow_bail = true ) {
		$this->is_mysql = true;

		/*
		 * Deprecated in 3.9+ when using MySQLi. No equivalent
		 * $new_link parameter exists for mysqli_* functions.
		 */
		$new_link     = defined( 'MYSQL_NEW_LINK' ) ? MYSQL_NEW_LINK : true;
		$client_flags = defined( 'MYSQL_CLIENT_FLAGS' ) ? MYSQL_CLIENT_FLAGS : 0;

		if ( $this->use_mysqli ) {
			/*
			 * Set the MySQLi error reporting off because WordPress handles its own.
			 * This is due to the default value change from `MYSQLI_REPORT_OFF`
			 * to `MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT` in PHP 8.1.
			 */
			mysqli_report( MYSQLI_REPORT_OFF );

			$this->dbh = mysqli_init();

			$host    = $this->dbhost;
			$port    = null;
			$socket  = null;
			$is_ipv6 = false;

			$host_data = $this->parse_db_host( $this->dbhost );
			if ( $host_data ) {
				list( $host, $port, $socket, $is_ipv6 ) = $host_data;
			}

			/*
			 * If using the `mysqlnd` library, the IPv6 address needs to be enclosed
			 * in square brackets, whereas it doesn't while using the `libmysqlclient` library.
			 * @see https://bugs.php.net/bug.php?id=67563
			 */
			if ( $is_ipv6 && extension_loaded( 'mysqlnd' ) ) {
				$host = "[$host]";
			}

			if ( WP_DEBUG ) {
				mysqli_real_connect( $this->dbh, $host, $this->dbuser, $this->dbpassword, null, $port, $socket, $client_flags );
			} else {
				// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
				@mysqli_real_connect( $this->dbh, $host, $this->dbuser, $this->dbpassword, null, $port, $socket, $client_flags );
			}

			if ( $this->dbh->connect_errno ) {
				$this->dbh = null;

				/*
				 * It's possible ext/mysqli is misconfigured. Fall back to ext/mysql if:
				 *  - We haven't previously connected, and
				 *  - WP_USE_EXT_MYSQL isn't set to false, and
				 *  - ext/mysql is loaded.
				 */
				$attempt_fallback = true;

				if ( $this->has_connected ) {
					$attempt_fallback = false;
				} elseif ( defined( 'WP_USE_EXT_MYSQL' ) && ! WP_USE_EXT_MYSQL ) {
					$attempt_fallback = false;
				} elseif ( ! function_exists( 'mysql_connect' ) ) {
					$attempt_fallback = false;
				}

				if ( $attempt_fallback ) {
					$this->use_mysqli = false;
					return $this->db_connect( $allow_bail );
				}
			}
		} else {
			if ( WP_DEBUG ) {
				$this->dbh = mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, $new_link, $client_flags );
			} else {
				// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
				$this->dbh = @mysql_connect( $this->dbhost, $this->dbuser, $this->dbpassword, $new_link, $client_flags );
			}
		}

		if ( ! $this->dbh && $allow_bail ) {
			wp_load_translations_early();

			// Load custom DB error template, if present.
			if ( file_exists( WP_CONTENT_DIR . '/db-error.php' ) ) {
				require_once WP_CONTENT_DIR . '/db-error.php';
				die();
			}

			$message = '<h1>' . __( 'Error establishing a database connection' ) . "</h1>n";

			$message .= '<p>' . sprintf(
				/* translators: 1: wp-config.php, 2: Database host. */
				__( 'This either means that the username and password information in your %1$s file is incorrect or that contact with the database server at %2$s could not be established. This could mean your host’s database server is down.' ),
				'<code>wp-config.php</code>',
				'<code>' . htmlspecialchars( $this->dbhost, ENT_QUOTES ) . '</code>'
			) . "</p>n";

			$message .= "<ul>n";
			$message .= '<li>' . __( 'Are you sure you have the correct username and password?' ) . "</li>n";
			$message .= '<li>' . __( 'Are you sure you have typed the correct hostname?' ) . "</li>n";
			$message .= '<li>' . __( 'Are you sure the database server is running?' ) . "</li>n";
			$message .= "</ul>n";

			$message .= '<p>' . sprintf(
				/* translators: %s: Support forums URL. */
				__( 'If you are unsure what these terms mean you should probably contact your host. If you still need help you can always visit the <a href="%s">WordPress Support Forums</a>.' ),
				__( 'https://wordpress.org/support/forums/' )
			) . "</p>n";

			$this->bail( $message, 'db_connect_fail' );

			return false;
		} elseif ( $this->dbh ) {
			if ( ! $this->has_connected ) {
				$this->init_charset();
			}

			$this->has_connected = true;

			$this->set_charset( $this->dbh );

			$this->ready = true;
			$this->set_sql_mode();
			$this->select( $this->dbname, $this->dbh );

			return true;
		}

		return false;
	}

	/**
	 * Parses the DB_HOST setting to interpret it for mysqli_real_connect().
	 *
	 * mysqli_real_connect() doesn't support the host param including a port or socket
	 * like mysql_connect() does. This duplicates how mysql_connect() detects a port
	 * and/or socket file.
	 *
	 * @since 4.9.0
	 *
	 * @param string $host The DB_HOST setting to parse.
	 * @return array|false {
	 *     Array containing the host, the port, the socket and
	 *     whether it is an IPv6 address, in that order.
	 *     False if the host couldn't be parsed.
	 *
	 *     @type string      $0 Host name.
	 *     @type string|null $1 Port.
	 *     @type string|null $2 Socket.
	 *     @type bool        $3 Whether it is an IPv6 address.
	 * }
	 */
	public function parse_db_host( $host ) {
		$socket  = null;
		$is_ipv6 = false;

		// First peel off the socket parameter from the right, if it exists.
		$socket_pos = strpos( $host, ':/' );
		if ( false !== $socket_pos ) {
			$socket = substr( $host, $socket_pos + 1 );
			$host   = substr( $host, 0, $socket_pos );
		}

		// We need to check for an IPv6 address first.
		// An IPv6 address will always contain at least two colons.
		if ( substr_count( $host, ':' ) > 1 ) {
			$pattern = '#^(?:[)?(?P<host>[0-9a-fA-F:]+)(?:]:(?P<port>[d]+))?#';
			$is_ipv6 = true;
		} else {
			// We seem to be dealing with an IPv4 address.
			$pattern = '#^(?P<host>[^:/]*)(?::(?P<port>[d]+))?#';
		}

		$matches = array();
		$result  = preg_match( $pattern, $host, $matches );

		if ( 1 !== $result ) {
			// Couldn't parse the address, bail.
			return false;
		}

		$host = ! empty( $matches['host'] ) ? $matches['host'] : '';
		// MySQLi port cannot be a string; must be null or an integer.
		$port = ! empty( $matches['port'] ) ? absint( $matches['port'] ) : null;

		return array( $host, $port, $socket, $is_ipv6 );
	}

	/**
	 * Checks that the connection to the database is still up. If not, try to reconnect.
	 *
	 * If this function is unable to reconnect, it will forcibly die, or if called
	 * after the {@see 'template_redirect'} hook has been fired, return false instead.
	 *
	 * If `$allow_bail` is false, the lack of database connection will need to be handled manually.
	 *
	 * @since 3.9.0
	 *
	 * @param bool $allow_bail Optional. Allows the function to bail. Default true.
	 * @return bool|void True if the connection is up.
	 */
	public function check_connection( $allow_bail = true ) {
		if ( $this->use_mysqli ) {
			if ( ! empty( $this->dbh ) && mysqli_ping( $this->dbh ) ) {
				return true;
			}
		} else {
			if ( ! empty( $this->dbh ) && mysql_ping( $this->dbh ) ) {
				return true;
			}
		}

		$error_reporting = false;

		// Disable warnings, as we don't want to see a multitude of "unable to connect" messages.
		if ( WP_DEBUG ) {
			$error_reporting = error_reporting();
			error_reporting( $error_reporting & ~E_WARNING );
		}

		for ( $tries = 1; $tries <= $this->reconnect_retries; $tries++ ) {
			// On the last try, re-enable warnings. We want to see a single instance
			// of the "unable to connect" message on the bail() screen, if it appears.
			if ( $this->reconnect_retries === $tries && WP_DEBUG ) {
				error_reporting( $error_reporting );
			}

			if ( $this->db_connect( false ) ) {
				if ( $error_reporting ) {
					error_reporting( $error_reporting );
				}

				return true;
			}

			sleep( 1 );
		}

		// If template_redirect has already happened, it's too late for wp_die()/dead_db().
		// Let's just return and hope for the best.
		if ( did_action( 'template_redirect' ) ) {
			return false;
		}

		if ( ! $allow_bail ) {
			return false;
		}

		wp_load_translations_early();

		$message = '<h1>' . __( 'Error reconnecting to the database' ) . "</h1>n";

		$message .= '<p>' . sprintf(
			/* translators: %s: Database host. */
			__( 'This means that the contact with the database server at %s was lost. This could mean your host’s database server is down.' ),
			'<code>' . htmlspecialchars( $this->dbhost, ENT_QUOTES ) . '</code>'
		) . "</p>n";

		$message .= "<ul>n";
		$message .= '<li>' . __( 'Are you sure the database server is running?' ) . "</li>n";
		$message .= '<li>' . __( 'Are you sure the database server is not under particularly heavy load?' ) . "</li>n";
		$message .= "</ul>n";

		$message .= '<p>' . sprintf(
			/* translators: %s: Support forums URL. */
			__( 'If you are unsure what these terms mean you should probably contact your host. If you still need help you can always visit the <a href="%s">WordPress Support Forums</a>.' ),
			__( 'https://wordpress.org/support/forums/' )
		) . "</p>n";

		// We weren't able to reconnect, so we better bail.
		$this->bail( $message, 'db_connect_fail' );

		// Call dead_db() if bail didn't die, because this database is no more.
		// It has ceased to be (at least temporarily).
		dead_db();
	}

	/**
	 * Performs a database query, using current database connection.
	 *
	 * More information can be found on the documentation page.
	 *
	 * @since 0.71
	 *
	 * @link https://developer.wordpress.org/reference/classes/wpdb/
	 *
	 * @param string $query Database query.
	 * @return int|bool Boolean true for CREATE, ALTER, TRUNCATE and DROP queries. Number of rows
	 *                  affected/selected for all other queries. Boolean false on error.
	 */
	public function query( $query ) {
		if ( ! $this->ready ) {
			$this->check_current_query = true;
			return false;
		}

		/**
		 * Filters the database query.
		 *
		 * Some queries are made before the plugins have been loaded,
		 * and thus cannot be filtered with this method.
		 *
		 * @since 2.1.0
		 *
		 * @param string $query Database query.
		 */
		$query = apply_filters( 'query', $query );

		if ( ! $query ) {
			$this->insert_id = 0;
			return false;
		}

		$this->flush();

		// Log how the function was called.
		$this->func_call = "$db->query("$query")";

		// If we're writing to the database, make sure the query will write safely.
		if ( $this->check_current_query && ! $this->check_ascii( $query ) ) {
			$stripped_query = $this->strip_invalid_text_from_query( $query );
			// strip_invalid_text_from_query() can perform queries, so we need
			// to flush again, just to make sure everything is clear.
			$this->flush();
			if ( $stripped_query !== $query ) {
				$this->insert_id  = 0;
				$this->last_query = $query;

				wp_load_translations_early();

				$this->last_error = __( 'WordPress database error: Could not perform query because it contains invalid data.' );

				return false;
			}
		}

		$this->check_current_query = true;

		// Keep track of the last query for debug.
		$this->last_query = $query;

		$this->_do_query( $query );

		// Database server has gone away, try to reconnect.
		$mysql_errno = 0;
		if ( ! empty( $this->dbh ) ) {
			if ( $this->use_mysqli ) {
				if ( $this->dbh instanceof mysqli ) {
					$mysql_errno = mysqli_errno( $this->dbh );
				} else {
					// $dbh is defined, but isn't a real connection.
					// Something has gone horribly wrong, let's try a reconnect.
					$mysql_errno = 2006;
				}
			} else {
				if ( is_resource( $this->dbh ) ) {
					$mysql_errno = mysql_errno( $this->dbh );
				} else {
					$mysql_errno = 2006;
				}
			}
		}

		if ( empty( $this->dbh ) || 2006 === $mysql_errno ) {
			if ( $this->check_connection() ) {
				$this->_do_query( $query );
			} else {
				$this->insert_id = 0;
				return false;
			}
		}

		// If there is an error then take note of it.
		if ( $this->use_mysqli ) {
			if ( $this->dbh instanceof mysqli ) {
				$this->last_error = mysqli_error( $this->dbh );
			} else {
				$this->last_error = __( 'Unable to retrieve the error message from MySQL' );
			}
		} else {
			if ( is_resource( $this->dbh ) ) {
				$this->last_error = mysql_error( $this->dbh );
			} else {
				$this->last_error = __( 'Unable to retrieve the error message from MySQL' );
			}
		}

		if ( $this->last_error ) {
			// Clear insert_id on a subsequent failed insert.
			if ( $this->insert_id && preg_match( '/^s*(insert|replace)s/i', $query ) ) {
				$this->insert_id = 0;
			}

			$this->print_error();
			return false;
		}

		if ( preg_match( '/^s*(create|alter|truncate|drop)s/i', $query ) ) {
			$return_val = $this->result;
		} elseif ( preg_match( '/^s*(insert|delete|update|replace)s/i', $query ) ) {
			if ( $this->use_mysqli ) {
				$this->rows_affected = mysqli_affected_rows( $this->dbh );
			} else {
				$this->rows_affected = mysql_affected_rows( $this->dbh );
			}
			// Take note of the insert_id.
			if ( preg_match( '/^s*(insert|replace)s/i', $query ) ) {
				if ( $this->use_mysqli ) {
					$this->insert_id = mysqli_insert_id( $this->dbh );
				} else {
					$this->insert_id = mysql_insert_id( $this->dbh );
				}
			}
			// Return number of rows affected.
			$return_val = $this->rows_affected;
		} else {
			$num_rows = 0;
			if ( $this->use_mysqli && $this->result instanceof mysqli_result ) {
				while ( $row = mysqli_fetch_object( $this->result ) ) {
					$this->last_result[ $num_rows ] = $row;
					$num_rows++;
				}
			} elseif ( is_resource( $this->result ) ) {
				while ( $row = mysql_fetch_object( $this->result ) ) {
					$this->last_result[ $num_rows ] = $row;
					$num_rows++;
				}
			}

			// Log and return the number of rows selected.
			$this->num_rows = $num_rows;
			$return_val     = $num_rows;
		}

		return $return_val;
	}

	/**
	 * Internal function to perform the mysql_query() call.
	 *
	 * @since 3.9.0
	 *
	 * @see wpdb::query()
	 *
	 * @param string $query The query to run.
	 */
	private function _do_query( $query ) {
		if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) {
			$this->timer_start();
		}

		if ( ! empty( $this->dbh ) && $this->use_mysqli ) {
			$this->result = mysqli_query( $this->dbh, $query );
		} elseif ( ! empty( $this->dbh ) ) {
			$this->result = mysql_query( $query, $this->dbh );
		}
		$this->num_queries++;

		if ( defined( 'SAVEQUERIES' ) && SAVEQUERIES ) {
			$this->log_query(
				$query,
				$this->timer_stop(),
				$this->get_caller(),
				$this->time_start,
				array()
			);
		}
	}

	/**
	 * Logs query data.
	 *
	 * @since 5.3.0
	 *
	 * @param string $query           The query's SQL.
	 * @param float  $query_time      Total time spent on the query, in seconds.
	 * @param string $query_callstack Comma-separated list of the calling functions.
	 * @param float  $query_start     Unix timestamp of the time at the start of the query.
	 * @param array  $query_data      Custom query data.
	 */
	public function log_query( $query, $query_time, $query_callstack, $query_start, $query_data ) {
		/**
		 * Filters the custom data to log alongside a query.
		 *
		 * Caution should be used when modifying any of this data, it is recommended that any additional
		 * information you need to store about a query be added as a new associative array element.
		 *
		 * @since 5.3.0
		 *
		 * @param array  $query_data      Custom query data.
		 * @param string $query           The query's SQL.
		 * @param float  $query_time      Total time spent on the query, in seconds.
		 * @param string $query_callstack Comma-separated list of the calling functions.
		 * @param float  $query_start     Unix timestamp of the time at the start of the query.
		 */
		$query_data = apply_filters( 'log_query_custom_data', $query_data, $query, $query_time, $query_callstack, $query_start );

		$this->queries[] = array(
			$query,
			$query_time,
			$query_callstack,
			$query_start,
			$query_data,
		);
	}

	/**
	 * Generates and returns a placeholder escape string for use in queries returned by ::prepare().
	 *
	 * @since 4.8.3
	 *
	 * @return string String to escape placeholders.
	 */
	public function placeholder_escape() {
		static $placeholder;

		if ( ! $placeholder ) {
			// If ext/hash is not present, compat.php's hash_hmac() does not support sha256.
			$algo = function_exists( 'hash' ) ? 'sha256' : 'sha1';
			// Old WP installs may not have AUTH_SALT defined.
			$salt = defined( 'AUTH_SALT' ) && AUTH_SALT ? AUTH_SALT : (string) rand();

			$placeholder = '{' . hash_hmac( $algo, uniqid( $salt, true ), $salt ) . '}';
		}

		/*
		 * Add the filter to remove the placeholder escaper. Uses priority 0, so that anything
		 * else attached to this filter will receive the query with the placeholder string removed.
		 */
		if ( false === has_filter( 'query', array( $this, 'remove_placeholder_escape' ) ) ) {
			add_filter( 'query', array( $this, 'remove_placeholder_escape' ), 0 );
		}

		return $placeholder;
	}

	/**
	 * Adds a placeholder escape string, to escape anything that resembles a printf() placeholder.
	 *
	 * @since 4.8.3
	 *
	 * @param string $query The query to escape.
	 * @return string The query with the placeholder escape string inserted where necessary.
	 */
	public function add_placeholder_escape( $query ) {
		/*
		 * To prevent returning anything that even vaguely resembles a placeholder,
		 * we clobber every % we can find.
		 */
		return str_replace( '%', $this->placeholder_escape(), $query );
	}

	/**
	 * Removes the placeholder escape strings from a query.
	 *
	 * @since 4.8.3
	 *
	 * @param string $query The query from which the placeholder will be removed.
	 * @return string The query with the placeholder removed.
	 */
	public function remove_placeholder_escape( $query ) {
		return str_replace( $this->placeholder_escape(), '%', $query );
	}

	/**
	 * Inserts a row into the table.
	 *
	 * Examples:
	 *
	 *     wpdb::insert( 'table', array( 'column' => 'foo', 'field' => 'bar' ) )
	 *     wpdb::insert( 'table', array( 'column' => 'foo', 'field' => 1337 ), array( '%s', '%d' ) )
	 *
	 * @since 2.5.0
	 *
	 * @see wpdb::prepare()
	 * @see wpdb::$field_types
	 * @see wp_set_wpdb_vars()
	 *
	 * @param string       $table  Table name.
	 * @param array        $data   Data to insert (in column => value pairs).
	 *                             Both $data columns and $data values should be "raw" (neither should be SQL escaped).
	 *                             Sending a null value will cause the column to be set to NULL - the corresponding
	 *                             format is ignored in this case.
	 * @param array|string $format Optional. An array of formats to be mapped to each of the value in $data.
	 *                             If string, that format will be used for all of the values in $data.
	 *                             A format is one of '%d', '%f', '%s' (integer, float, string).
	 *                             If omitted, all values in $data will be treated as strings unless otherwise
	 *                             specified in wpdb::$field_types.
	 * @return int|false The number of rows inserted, or false on error.
	 */
	public function insert( $table, $data, $format = null ) {
		return $this->_insert_replace_helper( $table, $data, $format, 'INSERT' );
	}

	/**
	 * Replaces a row in the table.
	 *
	 * Examples:
	 *
	 *     wpdb::replace( 'table', array( 'column' => 'foo', 'field' => 'bar' ) )
	 *     wpdb::replace( 'table', array( 'column' => 'foo', 'field' => 1337 ), array( '%s', '%d' ) )
	 *
	 * @since 3.0.0
	 *
	 * @see wpdb::prepare()
	 * @see wpdb::$field_types
	 * @see wp_set_wpdb_vars()
	 *
	 * @param string       $table  Table name.
	 * @param array        $data   Data to insert (in column => value pairs).
	 *                             Both $data columns and $data values should be "raw" (neither should be SQL escaped).
	 *                             Sending a null value will cause the column to be set to NULL - the corresponding
	 *                             format is ignored in this case.
	 * @param array|string $format Optional. An array of formats to be mapped to each of the value in $data.
	 *                             If string, that format will be used for all of the values in $data.
	 *                             A format is one of '%d', '%f', '%s' (integer, float, string).
	 *                             If omitted, all values in $data will be treated as strings unless otherwise
	 *                             specified in wpdb::$field_types.
	 * @return int|false The number of rows affected, or false on error.
	 */
	public function replace( $table, $data, $format = null ) {
		return $this->_insert_replace_helper( $table, $data, $format, 'REPLACE' );
	}

	/**
	 * Helper function for insert and replace.
	 *
	 * Runs an insert or replace query based on $type argument.
	 *
	 * @since 3.0.0
	 *
	 * @see wpdb::prepare()
	 * @see wpdb::$field_types
	 * @see wp_set_wpdb_vars()
	 *
	 * @param string       $table  Table name.
	 * @param array        $data   Data to insert (in column => value pairs).
	 *                             Both $data columns and $data values should be "raw" (neither should be SQL escaped).
	 *                             Sending a null value will cause the column to be set to NULL - the corresponding
	 *                             format is ignored in this case.
	 * @param array|string $format Optional. An array of formats to be mapped to each of the value in $data.
	 *                             If string, that format will be used for all of the values in $data.
	 *                             A format is one of '%d', '%f', '%s' (integer, float, string).
	 *                             If omitted, all values in $data will be treated as strings unless otherwise
	 *                             specified in wpdb::$field_types.
	 * @param string       $type   Optional. Type of operation. Possible values include 'INSERT' or 'REPLACE'.
	 *                             Default 'INSERT'.
	 * @return int|false The number of rows affected, or false on error.
	 */
	public function _insert_replace_helper( $table, $data, $format = null, $type = 'INSERT' ) {
		$this->insert_id = 0;

		if ( ! in_array( strtoupper( $type ), array( 'REPLACE', 'INSERT' ), true ) ) {
			return false;
		}

		$data = $this->process_fields( $table, $data, $format );
		if ( false === $data ) {
			return false;
		}

		$formats = array();
		$values  = array();
		foreach ( $data as $value ) {
			if ( is_null( $value['value'] ) ) {
				$formats[] = 'NULL';
				continue;
			}

			$formats[] = $value['format'];
			$values[]  = $value['value'];
		}

		$fields  = '`' . implode( '`, `', array_keys( $data ) ) . '`';
		$formats = implode( ', ', $formats );

		$sql = "$type INTO `$table` ($fields) VALUES ($formats)";

		$this->check_current_query = false;
		return $this->query( $this->prepare( $sql, $values ) );
	}

	/**
	 * Updates a row in the table.
	 *
	 * Examples:
	 *
	 *     wpdb::update( 'table', array( 'column' => 'foo', 'field' => 'bar' ), array( 'ID' => 1 ) )
	 *     wpdb::update( 'table', array( 'column' => 'foo', 'field' => 1337 ), array( 'ID' => 1 ), array( '%s', '%d' ), array( '%d' ) )
	 *
	 * @since 2.5.0
	 *
	 * @see wpdb::prepare()
	 * @see wpdb::$field_types
	 * @see wp_set_wpdb_vars()
	 *
	 * @param string       $table        Table name.
	 * @param array        $data         Data to update (in column => value pairs).
	 *                                   Both $data columns and $data values should be "raw" (neither should be SQL escaped).
	 *                                   Sending a null value will cause the column to be set to NULL - the corresponding
	 *                                   format is ignored in this case.
	 * @param array        $where        A named array of WHERE clauses (in column => value pairs).
	 *                                   Multiple clauses will be joined with ANDs.
	 *                                   Both $where columns and $where values should be "raw".
	 *                                   Sending a null value will create an IS NULL comparison - the corresponding
	 *                                   format will be ignored in this case.
	 * @param array|string $format       Optional. An array of formats to be mapped to each of the values in $data.
	 *                                   If string, that format will be used for all of the values in $data.
	 *                                   A format is one of '%d', '%f', '%s' (integer, float, string).
	 *                                   If omitted, all values in $data will be treated as strings unless otherwise
	 *                                   specified in wpdb::$field_types.
	 * @param array|string $where_format Optional. An array of formats to be mapped to each of the values in $where.
	 *                                   If string, that format will be used for all of the items in $where.
	 *                                   A format is one of '%d', '%f', '%s' (integer, float, string).
	 *                                   If omitted, all values in $where will be treated as strings.
	 * @return int|false The number of rows updated, or false on error.
	 */
	public function update( $table, $data, $where, $format = null, $where_format = null ) {
		if ( ! is_array( $data ) || ! is_array( $where ) ) {
			return false;
		}

		$data = $this->process_fields( $table, $data, $format );
		if ( false === $data ) {
			return false;
		}
		$where = $this->process_fields( $table, $where, $where_format );
		if ( false === $where ) {
			return false;
		}

		$fields     = array();
		$conditions = array();
		$values     = array();
		foreach ( $data as $field => $value ) {
			if ( is_null( $value['value'] ) ) {
				$fields[] = "`$field` = NULL";
				continue;
			}

			$fields[] = "`$field` = " . $value['format'];
			$values[] = $value['value'];
		}
		foreach ( $where as $field => $value ) {
			if ( is_null( $value['value'] ) ) {
				$conditions[] = "`$field` IS NULL";
				continue;
			}

			$conditions[] = "`$field` = " . $value['format'];
			$values[]     = $value['value'];
		}

		$fields     = implode( ', ', $fields );
		$conditions = implode( ' AND ', $conditions );

		$sql = "UPDATE `$table` SET $fields WHERE $conditions";

		$this->check_current_query = false;
		return $this->query( $this->prepare( $sql, $values ) );
	}

	/**
	 * Deletes a row in the table.
	 *
	 * Examples:
	 *
	 *     wpdb::delete( 'table', array( 'ID' => 1 ) )
	 *     wpdb::delete( 'table', array( 'ID' => 1 ), array( '%d' ) )
	 *
	 * @since 3.4.0
	 *
	 * @see wpdb::prepare()
	 * @see wpdb::$field_types
	 * @see wp_set_wpdb_vars()
	 *
	 * @param string       $table        Table name.
	 * @param array        $where        A named array of WHERE clauses (in column => value pairs).
	 *                                   Multiple clauses will be joined with ANDs.
	 *                                   Both $where columns and $where values should be "raw".
	 *                                   Sending a null value will create an IS NULL comparison - the corresponding
	 *                                   format will be ignored in this case.
	 * @param array|string $where_format Optional. An array of formats to be mapped to each of the values in $where.
	 *                                   If string, that format will be used for all of the items in $where.
	 *                                   A format is one of '%d', '%f', '%s' (integer, float, string).
	 *                                   If omitted, all values in $data will be treated as strings unless otherwise
	 *                                   specified in wpdb::$field_types.
	 * @return int|false The number of rows deleted, or false on error.
	 */
	public function delete( $table, $where, $where_format = null ) {
		if ( ! is_array( $where ) ) {
			return false;
		}

		$where = $this->process_fields( $table, $where, $where_format );
		if ( false === $where ) {
			return false;
		}

		$conditions = array();
		$values     = array();
		foreach ( $where as $field => $value ) {
			if ( is_null( $value['value'] ) ) {
				$conditions[] = "`$field` IS NULL";
				continue;
			}

			$conditions[] = "`$field` = " . $value['format'];
			$values[]     = $value['value'];
		}

		$conditions = implode( ' AND ', $conditions );

		$sql = "DELETE FROM `$table` WHERE $conditions";

		$this->check_current_query = false;
		return $this->query( $this->prepare( $sql, $values ) );
	}

	/**
	 * Processes arrays of field/value pairs and field formats.
	 *
	 * This is a helper method for wpdb's CRUD methods, which take field/value pairs
	 * for inserts, updates, and where clauses. This method first pairs each value
	 * with a format. Then it determines the charset of that field, using that
	 * to determine if any invalid text would be stripped. If text is stripped,
	 * then field processing is rejected and the query fails.
	 *
	 * @since 4.2.0
	 *
	 * @param string $table  Table name.
	 * @param array  $data   Field/value pair.
	 * @param mixed  $format Format for each field.
	 * @return array|false An array of fields that contain paired value and formats.
	 *                     False for invalid values.
	 */
	protected function process_fields( $table, $data, $format ) {
		$data = $this->process_field_formats( $data, $format );
		if ( false === $data ) {
			return false;
		}

		$data = $this->process_field_charsets( $data, $table );
		if ( false === $data ) {
			return false;
		}

		$data = $this->process_field_lengths( $data, $table );
		if ( false === $data ) {
			return false;
		}

		$converted_data = $this->strip_invalid_text( $data );

		if ( $data !== $converted_data ) {

			$problem_fields = array();
			foreach ( $data as $field => $value ) {
				if ( $value !== $converted_data[ $field ] ) {
					$problem_fields[] = $field;
				}
			}

			wp_load_translations_early();

			if ( 1 === count( $problem_fields ) ) {
				$this->last_error = sprintf(
					/* translators: %s: Database field where the error occurred. */
					__( 'WordPress database error: Processing the value for the following field failed: %s. The supplied value may be too long or contains invalid data.' ),
					reset( $problem_fields )
				);
			} else {
				$this->last_error = sprintf(
					/* translators: %s: Database fields where the error occurred. */
					__( 'WordPress database error: Processing the values for the following fields failed: %s. The supplied values may be too long or contain invalid data.' ),
					implode( ', ', $problem_fields )
				);
			}

			return false;
		}

		return $data;
	}

	/**
	 * Prepares arrays of value/format pairs as passed to wpdb CRUD methods.
	 *
	 * @since 4.2.0
	 *
	 * @param array $data   Array of fields to values.
	 * @param mixed $format Formats to be mapped to the values in $data.
	 * @return array Array, keyed by field names with values being an array
	 *               of 'value' and 'format' keys.
	 */
	protected function process_field_formats( $data, $format ) {
		$formats          = (array) $format;
		$original_formats = $formats;

		foreach ( $data as $field => $value ) {
			$value = array(
				'value'  => $value,
				'format' => '%s',
			);

			if ( ! empty( $format ) ) {
				$value['format'] = array_shift( $formats );
				if ( ! $value['format'] ) {
					$value['format'] = reset( $original_formats );
				}
			} elseif ( isset( $this->field_types[ $field ] ) ) {
				$value['format'] = $this->field_types[ $field ];
			}

			$data[ $field ] = $value;
		}

		return $data;
	}

	/**
	 * Adds field charsets to field/value/format arrays generated by wpdb::process_field_formats().
	 *
	 * @since 4.2.0
	 *
	 * @param array  $data  As it comes from the wpdb::process_field_formats() method.
	 * @param string $table Table name.
	 * @return array|false The same array as $data with additional 'charset' keys.
	 *                     False on failure.
	 */
	protected function process_field_charsets( $data, $table ) {
		foreach ( $data as $field => $value ) {
			if ( '%d' === $value['format'] || '%f' === $value['format'] ) {
				/*
				 * We can skip this field if we know it isn't a string.
				 * This checks %d/%f versus ! %s because its sprintf() could take more.
				 */
				$value['charset'] = false;
			} else {
				$value['charset'] = $this->get_col_charset( $table, $field );
				if ( is_wp_error( $value['charset'] ) ) {
					return false;
				}
			}

			$data[ $field ] = $value;
		}

		return $data;
	}

	/**
	 * For string fields, records the maximum string length that field can safely save.
	 *
	 * @since 4.2.1
	 *
	 * @param array  $data  As it comes from the wpdb::process_field_charsets() method.
	 * @param string $table Table name.
	 * @return array|false The same array as $data with additional 'length' keys, or false if
	 *                     any of the values were too long for their corresponding field.
	 */
	protected function process_field_lengths( $data, $table ) {
		foreach ( $data as $field => $value ) {
			if ( '%d' === $value['format'] || '%f' === $value['format'] ) {
				/*
				 * We can skip this field if we know it isn't a string.
				 * This checks %d/%f versus ! %s because its sprintf() could take more.
				 */
				$value['length'] = false;
			} else {
				$value['length'] = $this->get_col_length( $table, $field );
				if ( is_wp_error( $value['length'] ) ) {
					return false;
				}
			}

			$data[ $field ] = $value;
		}

		return $data;
	}

	/**
	 * Retrieves one variable from the database.
	 *
	 * Executes a SQL query and returns the value from the SQL result.
	 * If the SQL result contains more than one column and/or more than one row,
	 * the value in the column and row specified is returned. If $query is null,
	 * the value in the specified column and row from the previous SQL result is returned.
	 *
	 * @since 0.71
	 *
	 * @param string|null $query Optional. SQL query. Defaults to null, use the result from the previous query.
	 * @param int         $x     Optional. Column of value to return. Indexed from 0.
	 * @param int         $y     Optional. Row of value to return. Indexed from 0.
	 * @return string|null Database query result (as string), or null on failure.
	 */
	public function get_var( $query = null, $x = 0, $y = 0 ) {
		$this->func_call = "$db->get_var("$query", $x, $y)";

		if ( $query ) {
			if ( $this->check_current_query && $this->check_safe_collation( $query ) ) {
				$this->check_current_query = false;
			}

			$this->query( $query );
		}

		// Extract var out of cached results based on x,y vals.
		if ( ! empty( $this->last_result[ $y ] ) ) {
			$values = array_values( get_object_vars( $this->last_result[ $y ] ) );
		}

		// If there is a value return it, else return null.
		return ( isset( $values[ $x ] ) && '' !== $values[ $x ] ) ? $values[ $x ] : null;
	}

	/**
	 * Retrieves one row from the database.
	 *
	 * Executes a SQL query and returns the row from the SQL result.
	 *
	 * @since 0.71
	 *
	 * @param string|null $query  SQL query.
	 * @param string      $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which
	 *                            correspond to an stdClass object, an associative array, or a numeric array,
	 *                            respectively. Default OBJECT.
	 * @param int         $y      Optional. Row to return. Indexed from 0.
	 * @return array|object|null|void Database query result in format specified by $output or null on failure.
	 */
	public function get_row( $query = null, $output = OBJECT, $y = 0 ) {
		$this->func_call = "$db->get_row("$query",$output,$y)";

		if ( $query ) {
			if ( $this->check_current_query && $this->check_safe_collation( $query ) ) {
				$this->check_current_query = false;
			}

			$this->query( $query );
		} else {
			return null;
		}

		if ( ! isset( $this->last_result[ $y ] ) ) {
			return null;
		}

		if ( OBJECT === $output ) {
			return $this->last_result[ $y ] ? $this->last_result[ $y ] : null;
		} elseif ( ARRAY_A === $output ) {
			return $this->last_result[ $y ] ? get_object_vars( $this->last_result[ $y ] ) : null;
		} elseif ( ARRAY_N === $output ) {
			return $this->last_result[ $y ] ? array_values( get_object_vars( $this->last_result[ $y ] ) ) : null;
		} elseif ( OBJECT === strtoupper( $output ) ) {
			// Back compat for OBJECT being previously case-insensitive.
			return $this->last_result[ $y ] ? $this->last_result[ $y ] : null;
		} else {
			$this->print_error( ' $db->get_row(string query, output type, int offset) -- Output type must be one of: OBJECT, ARRAY_A, ARRAY_N' );
		}
	}

	/**
	 * Retrieves one column from the database.
	 *
	 * Executes a SQL query and returns the column from the SQL result.
	 * If the SQL result contains more than one column, the column specified is returned.
	 * If $query is null, the specified column from the previous SQL result is returned.
	 *
	 * @since 0.71
	 *
	 * @param string|null $query Optional. SQL query. Defaults to previous query.
	 * @param int         $x     Optional. Column to return. Indexed from 0.
	 * @return array Database query result. Array indexed from 0 by SQL result row number.
	 */
	public function get_col( $query = null, $x = 0 ) {
		if ( $query ) {
			if ( $this->check_current_query && $this->check_safe_collation( $query ) ) {
				$this->check_current_query = false;
			}

			$this->query( $query );
		}

		$new_array = array();
		// Extract the column values.
		if ( $this->last_result ) {
			for ( $i = 0, $j = count( $this->last_result ); $i < $j; $i++ ) {
				$new_array[ $i ] = $this->get_var( null, $x, $i );
			}
		}
		return $new_array;
	}

	/**
	 * Retrieves an entire SQL result set from the database (i.e., many rows).
	 *
	 * Executes a SQL query and returns the entire SQL result.
	 *
	 * @since 0.71
	 *
	 * @param string $query  SQL query.
	 * @param string $output Optional. Any of ARRAY_A | ARRAY_N | OBJECT | OBJECT_K constants.
	 *                       With one of the first three, return an array of rows indexed
	 *                       from 0 by SQL result row number. Each row is an associative array
	 *                       (column => value, ...), a numerically indexed array (0 => value, ...),
	 *                       or an object ( ->column = value ), respectively. With OBJECT_K,
	 *                       return an associative array of row objects keyed by the value
	 *                       of each row's first column's value. Duplicate keys are discarded.
	 * @return array|object|null Database query results.
	 */
	public function get_results( $query = null, $output = OBJECT ) {
		$this->func_call = "$db->get_results("$query", $output)";

		if ( $query ) {
			if ( $this->check_current_query && $this->check_safe_collation( $query ) ) {
				$this->check_current_query = false;
			}

			$this->query( $query );
		} else {
			return null;
		}

		$new_array = array();
		if ( OBJECT === $output ) {
			// Return an integer-keyed array of row objects.
			return $this->last_result;
		} elseif ( OBJECT_K === $output ) {
			// Return an array of row objects with keys from column 1.
			// (Duplicates are discarded.)
			if ( $this->last_result ) {
				foreach ( $this->last_result as $row ) {
					$var_by_ref = get_object_vars( $row );
					$key        = array_shift( $var_by_ref );
					if ( ! isset( $new_array[ $key ] ) ) {
						$new_array[ $key ] = $row;
					}
				}
			}
			return $new_array;
		} elseif ( ARRAY_A === $output || ARRAY_N === $output ) {
			// Return an integer-keyed array of...
			if ( $this->last_result ) {
				foreach ( (array) $this->last_result as $row ) {
					if ( ARRAY_N === $output ) {
						// ...integer-keyed row arrays.
						$new_array[] = array_values( get_object_vars( $row ) );
					} else {
						// ...column name-keyed row arrays.
						$new_array[] = get_object_vars( $row );
					}
				}
			}
			return $new_array;
		} elseif ( strtoupper( $output ) === OBJECT ) {
			// Back compat for OBJECT being previously case-insensitive.
			return $this->last_result;
		}
		return null;
	}

	/**
	 * Retrieves the character set for the given table.
	 *
	 * @since 4.2.0
	 *
	 * @param string $table Table name.
	 * @return string|WP_Error Table character set, WP_Error object if it couldn't be found.
	 */
	protected function get_table_charset( $table ) {
		$tablekey = strtolower( $table );

		/**
		 * Filters the table charset value before the DB is checked.
		 *
		 * Returning a non-null value from the filter will effectively short-circuit
		 * checking the DB for the charset, returning that value instead.
		 *
		 * @since 4.2.0
		 *
		 * @param string|WP_Error|null $charset The character set to use, WP_Error object
		 *                                      if it couldn't be found. Default null.
		 * @param string               $table   The name of the table being checked.
		 */
		$charset = apply_filters( 'pre_get_table_charset', null, $table );
		if ( null !== $charset ) {
			return $charset;
		}

		if ( isset( $this->table_charset[ $tablekey ] ) ) {
			return $this->table_charset[ $tablekey ];
		}

		$charsets = array();
		$columns  = array();

		$table_parts = explode( '.', $table );
		$table       = '`' . implode( '`.`', $table_parts ) . '`';
		$results     = $this->get_results( "SHOW FULL COLUMNS FROM $table" );
		if ( ! $results ) {
			return new WP_Error( 'wpdb_get_table_charset_failure', __( 'Could not retrieve table charset.' ) );
		}

		foreach ( $results as $column ) {
			$columns[ strtolower( $column->Field ) ] = $column;
		}

		$this->col_meta[ $tablekey ] = $columns;

		foreach ( $columns as $column ) {
			if ( ! empty( $column->Collation ) ) {
				list( $charset ) = explode( '_', $column->Collation );

				// If the current connection can't support utf8mb4 characters, let's only send 3-byte utf8 characters.
				if ( 'utf8mb4' === $charset && ! $this->has_cap( 'utf8mb4' ) ) {
					$charset = 'utf8';
				}

				$charsets[ strtolower( $charset ) ] = true;
			}

			list( $type ) = explode( '(', $column->Type );

			// A binary/blob means the whole query gets treated like this.
			if ( in_array( strtoupper( $type ), array( 'BINARY', 'VARBINARY', 'TINYBLOB', 'MEDIUMBLOB', 'BLOB', 'LONGBLOB' ), true ) ) {
				$this->table_charset[ $tablekey ] = 'binary';
				return 'binary';
			}
		}

		// utf8mb3 is an alias for utf8.
		if ( isset( $charsets['utf8mb3'] ) ) {
			$charsets['utf8'] = true;
			unset( $charsets['utf8mb3'] );
		}

		// Check if we have more than one charset in play.
		$count = count( $charsets );
		if ( 1 === $count ) {
			$charset = key( $charsets );
		} elseif ( 0 === $count ) {
			// No charsets, assume this table can store whatever.
			$charset = false;
		} else {
			// More than one charset. Remove latin1 if present and recalculate.
			unset( $charsets['latin1'] );
			$count = count( $charsets );
			if ( 1 === $count ) {
				// Only one charset (besides latin1).
				$charset = key( $charsets );
			} elseif ( 2 === $count && isset( $charsets['utf8'], $charsets['utf8mb4'] ) ) {
				// Two charsets, but they're utf8 and utf8mb4, use utf8.
				$charset = 'utf8';
			} else {
				// Two mixed character sets. ascii.
				$charset = 'ascii';
			}
		}

		$this->table_charset[ $tablekey ] = $charset;
		return $charset;
	}

	/**
	 * Retrieves the character set for the given column.
	 *
	 * @since 4.2.0
	 *
	 * @param string $table  Table name.
	 * @param string $column Column name.
	 * @return string|false|WP_Error Column character set as a string. False if the column has
	 *                               no character set. WP_Error object if there was an error.
	 */
	public function get_col_charset( $table, $column ) {
		$tablekey  = strtolower( $table );
		$columnkey = strtolower( $column );

		/**
		 * Filters the column charset value before the DB is checked.
		 *
		 * Passing a non-null value to the filter will short-circuit
		 * checking the DB for the charset, returning that value instead.
		 *
		 * @since 4.2.0
		 *
		 * @param string|null $charset The character set to use. Default null.
		 * @param string      $table   The name of the table being checked.
		 * @param string      $column  The name of the column being checked.
		 */
		$charset = apply_filters( 'pre_get_col_charset', null, $table, $column );
		if ( null !== $charset ) {
			return $charset;
		}

		// Skip this entirely if this isn't a MySQL database.
		if ( empty( $this->is_mysql ) ) {
			return false;
		}

		if ( empty( $this->table_charset[ $tablekey ] ) ) {
			// This primes column information for us.
			$table_charset = $this->get_table_charset( $table );
			if ( is_wp_error( $table_charset ) ) {
				return $table_charset;
			}
		}

		// If still no column information, return the table charset.
		if ( empty( $this->col_meta[ $tablekey ] ) ) {
			return $this->table_charset[ $tablekey ];
		}

		// If this column doesn't exist, return the table charset.
		if ( empty( $this->col_meta[ $tablekey ][ $columnkey ] ) ) {
			return $this->table_charset[ $tablekey ];
		}

		// Return false when it's not a string column.
		if ( empty( $this->col_meta[ $tablekey ][ $columnkey ]->Collation ) ) {
			return false;
		}

		list( $charset ) = explode( '_', $this->col_meta[ $tablekey ][ $columnkey ]->Collation );
		return $charset;
	}

	/**
	 * Retrieves the maximum string length allowed in a given column.
	 *
	 * The length may either be specified as a byte length or a character length.
	 *
	 * @since 4.2.1
	 *
	 * @param string $table  Table name.
	 * @param string $column Column name.
	 * @return array|false|WP_Error {
	 *     Array of column length information, false if the column has no length (for
	 *     example, numeric column), WP_Error object if there was an error.
	 *
	 *     @type int    $length The column length.
	 *     @type string $type   One of 'byte' or 'char'.
	 */
	public function get_col_length( $table, $column ) {
		$tablekey  = strtolower( $table );
		$columnkey = strtolower( $column );

		// Skip this entirely if this isn't a MySQL database.
		if ( empty( $this->is_mysql ) ) {
			return false;
		}

		if ( empty( $this->col_meta[ $tablekey ] ) ) {
			// This primes column information for us.
			$table_charset = $this->get_table_charset( $table );
			if ( is_wp_error( $table_charset ) ) {
				return $table_charset;
			}
		}

		if ( empty( $this->col_meta[ $tablekey ][ $columnkey ] ) ) {
			return false;
		}

		$typeinfo = explode( '(', $this->col_meta[ $tablekey ][ $columnkey ]->Type );

		$type = strtolower( $typeinfo[0] );
		if ( ! empty( $typeinfo[1] ) ) {
			$length = trim( $typeinfo[1], ')' );
		} else {
			$length = false;
		}

		switch ( $type ) {
			case 'char':
			case 'varchar':
				return array(
					'type'   => 'char',
					'length' => (int) $length,
				);

			case 'binary':
			case 'varbinary':
				return array(
					'type'   => 'byte',
					'length' => (int) $length,
				);

			case 'tinyblob':
			case 'tinytext':
				return array(
					'type'   => 'byte',
					'length' => 255,        // 2^8 - 1
				);

			case 'blob':
			case 'text':
				return array(
					'type'   => 'byte',
					'length' => 65535,      // 2^16 - 1
				);

			case 'mediumblob':
			case 'mediumtext':
				return array(
					'type'   => 'byte',
					'length' => 16777215,   // 2^24 - 1
				);

			case 'longblob':
			case 'longtext':
				return array(
					'type'   => 'byte',
					'length' => 4294967295, // 2^32 - 1
				);

			default:
				return false;
		}
	}

	/**
	 * Checks if a string is ASCII.
	 *
	 * The negative regex is faster for non-ASCII strings, as it allows
	 * the search to finish as soon as it encounters a non-ASCII character.
	 *
	 * @since 4.2.0
	 *
	 * @param string $string String to check.
	 * @return bool True if ASCII, false if not.
	 */
	protected function check_ascii( $string ) {
		if ( function_exists( 'mb_check_encoding' ) ) {
			if ( mb_check_encoding( $string, 'ASCII' ) ) {
				return true;
			}
		} elseif ( ! preg_match( '/[^x00-x7F]/', $string ) ) {
			return true;
		}

		return false;
	}

	/**
	 * Checks if the query is accessing a collation considered safe on the current version of MySQL.
	 *
	 * @since 4.2.0
	 *
	 * @param string $query The query to check.
	 * @return bool True if the collation is safe, false if it isn't.
	 */
	protected function check_safe_collation( $query ) {
		if ( $this->checking_collation ) {
			return true;
		}

		// We don't need to check the collation for queries that don't read data.
		$query = ltrim( $query, "rnt (" );
		if ( preg_match( '/^(?:SHOW|DESCRIBE|DESC|EXPLAIN|CREATE)s/i', $query ) ) {
			return true;
		}

		// All-ASCII queries don't need extra checking.
		if ( $this->check_ascii( $query ) ) {
			return true;
		}

		$table = $this->get_table_from_query( $query );
		if ( ! $table ) {
			return false;
		}

		$this->checking_collation = true;
		$collation                = $this->get_table_charset( $table );
		$this->checking_collation = false;

		// Tables with no collation, or latin1 only, don't need extra checking.
		if ( false === $collation || 'latin1' === $collation ) {
			return true;
		}

		$table = strtolower( $table );
		if ( empty( $this->col_meta[ $table ] ) ) {
			return false;
		}

		// If any of the columns don't have one of these collations, it needs more sanity checking.
		$safe_collations = array(
			'utf8_bin',
			'utf8_general_ci',
			'utf8mb3_bin',
			'utf8mb3_general_ci',
			'utf8mb4_bin',
			'utf8mb4_general_ci',
		);

		foreach ( $this->col_meta[ $table ] as $col ) {
			if ( empty( $col->Collation ) ) {
				continue;
			}

			if ( ! in_array( $col->Collation, $safe_collations, true ) ) {
				return false;
			}
		}

		return true;
	}

	/**
	 * Strips any invalid characters based on value/charset pairs.
	 *
	 * @since 4.2.0
	 *
	 * @param array $data Array of value arrays. Each value array has the keys 'value' and 'charset'.
	 *                    An optional 'ascii' key can be set to false to avoid redundant ASCII checks.
	 * @return array|WP_Error The $data parameter, with invalid characters removed from each value.
	 *                        This works as a passthrough: any additional keys such as 'field' are
	 *                        retained in each value array. If we cannot remove invalid characters,
	 *                        a WP_Error object is returned.
	 */
	protected function strip_invalid_text( $data ) {
		$db_check_string = false;

		foreach ( $data as &$value ) {
			$charset = $value['charset'];

			if ( is_array( $value['length'] ) ) {
				$length                  = $value['length']['length'];
				$truncate_by_byte_length = 'byte' === $value['length']['type'];
			} else {
				$length = false;
				// Since we have no length, we'll never truncate. Initialize the variable to false.
				// True would take us through an unnecessary (for this case) codepath below.
				$truncate_by_byte_length = false;
			}

			// There's no charset to work with.
			if ( false === $charset ) {
				continue;
			}

			// Column isn't a string.
			if ( ! is_string( $value['value'] ) ) {
				continue;
			}

			$needs_validation = true;
			if (
				// latin1 can store any byte sequence.
				'latin1' === $charset
			||
				// ASCII is always OK.
				( ! isset( $value['ascii'] ) && $this->check_ascii( $value['value'] ) )
			) {
				$truncate_by_byte_length = true;
				$needs_validation        = false;
			}

			if ( $truncate_by_byte_length ) {
				mbstring_binary_safe_encoding();
				if ( false !== $length && strlen( $value['value'] ) > $length ) {
					$value['value'] = substr( $value['value'], 0, $length );
				}
				reset_mbstring_encoding();

				if ( ! $needs_validation ) {
					continue;
				}
			}

			// utf8 can be handled by regex, which is a bunch faster than a DB lookup.
			if ( ( 'utf8' === $charset || 'utf8mb3' === $charset || 'utf8mb4' === $charset ) && function_exists( 'mb_strlen' ) ) {
				$regex = '/
					(
						(?: [x00-x7F]                  # single-byte sequences   0xxxxxxx
						|   [xC2-xDF][x80-xBF]       # double-byte sequences   110xxxxx 10xxxxxx
						|   xE0[xA0-xBF][x80-xBF]   # triple-byte sequences   1110xxxx 10xxxxxx * 2
						|   [xE1-xEC][x80-xBF]{2}
						|   xED[x80-x9F][x80-xBF]
						|   [xEE-xEF][x80-xBF]{2}';

				if ( 'utf8mb4' === $charset ) {
					$regex .= '
						|    xF0[x90-xBF][x80-xBF]{2} # four-byte sequences   11110xxx 10xxxxxx * 3
						|    [xF1-xF3][x80-xBF]{3}
						|    xF4[x80-x8F][x80-xBF]{2}
					';
				}

				$regex         .= '){1,40}                          # ...one or more times
					)
					| .                                  # anything else
					/x';
				$value['value'] = preg_replace( $regex, '$1', $value['value'] );

				if ( false !== $length && mb_strlen( $value['value'], 'UTF-8' ) > $length ) {
					$value['value'] = mb_substr( $value['value'], 0, $length, 'UTF-8' );
				}
				continue;
			}

			// We couldn't use any local conversions, send it to the DB.
			$value['db']     = true;
			$db_check_string = true;
		}
		unset( $value ); // Remove by reference.

		if ( $db_check_string ) {
			$queries = array();
			foreach ( $data as $col => $value ) {
				if ( ! empty( $value['db'] ) ) {
					// We're going to need to truncate by characters or bytes, depending on the length value we have.
					if ( isset( $value['length']['type'] ) && 'byte' === $value['length']['type'] ) {
						// Using binary causes LEFT() to truncate by bytes.
						$charset = 'binary';
					} else {
						$charset = $value['charset'];
					}

					if ( $this->charset ) {
						$connection_charset = $this->charset;
					} else {
						if ( $this->use_mysqli ) {
							$connection_charset = mysqli_character_set_name( $this->dbh );
						} else {
							$connection_charset = mysql_client_encoding();
						}
					}

					if ( is_array( $value['length'] ) ) {
						$length          = sprintf( '%.0f', $value['length']['length'] );
						$queries[ $col ] = $this->prepare( "CONVERT( LEFT( CONVERT( %s USING $charset ), $length ) USING $connection_charset )", $value['value'] );
					} elseif ( 'binary' !== $charset ) {
						// If we don't have a length, there's no need to convert binary - it will always return the same result.
						$queries[ $col ] = $this->prepare( "CONVERT( CONVERT( %s USING $charset ) USING $connection_charset )", $value['value'] );
					}

					unset( $data[ $col ]['db'] );
				}
			}

			$sql = array();
			foreach ( $queries as $column => $query ) {
				if ( ! $query ) {
					continue;
				}

				$sql[] = $query . " AS x_$column";
			}

			$this->check_current_query = false;
			$row                       = $this->get_row( 'SELECT ' . implode( ', ', $sql ), ARRAY_A );
			if ( ! $row ) {
				return new WP_Error( 'wpdb_strip_invalid_text_failure', __( 'Could not strip invalid text.' ) );
			}

			foreach ( array_keys( $data ) as $column ) {
				if ( isset( $row[ "x_$column" ] ) ) {
					$data[ $column ]['value'] = $row[ "x_$column" ];
				}
			}
		}

		return $data;
	}

	/**
	 * Strips any invalid characters from the query.
	 *
	 * @since 4.2.0
	 *
	 * @param string $query Query to convert.
	 * @return string|WP_Error The converted query, or a WP_Error object if the conversion fails.
	 */
	protected function strip_invalid_text_from_query( $query ) {
		// We don't need to check the collation for queries that don't read data.
		$trimmed_query = ltrim( $query, "rnt (" );
		if ( preg_match( '/^(?:SHOW|DESCRIBE|DESC|EXPLAIN|CREATE)s/i', $trimmed_query ) ) {
			return $query;
		}

		$table = $this->get_table_from_query( $query );
		if ( $table ) {
			$charset = $this->get_table_charset( $table );
			if ( is_wp_error( $charset ) ) {
				return $charset;
			}

			// We can't reliably strip text from tables containing binary/blob columns.
			if ( 'binary' === $charset ) {
				return $query;
			}
		} else {
			$charset = $this->charset;
		}

		$data = array(
			'value'   => $query,
			'charset' => $charset,
			'ascii'   => false,
			'length'  => false,
		);

		$data = $this->strip_invalid_text( array( $data ) );
		if ( is_wp_error( $data ) ) {
			return $data;
		}

		return $data[0]['value'];
	}

	/**
	 * Strips any invalid characters from the string for a given table and column.
	 *
	 * @since 4.2.0
	 *
	 * @param string $table  Table name.
	 * @param string $column Column name.
	 * @param string $value  The text to check.
	 * @return string|WP_Error The converted string, or a WP_Error object if the conversion fails.
	 */
	public function strip_invalid_text_for_column( $table, $column, $value ) {
		if ( ! is_string( $value ) ) {
			return $value;
		}

		$charset = $this->get_col_charset( $table, $column );
		if ( ! $charset ) {
			// Not a string column.
			return $value;
		} elseif ( is_wp_error( $charset ) ) {
			// Bail on real errors.
			return $charset;
		}

		$data = array(
			$column => array(
				'value'   => $value,
				'charset' => $charset,
				'length'  => $this->get_col_length( $table, $column ),
			),
		);

		$data = $this->strip_invalid_text( $data );
		if ( is_wp_error( $data ) ) {
			return $data;
		}

		return $data[ $column ]['value'];
	}

	/**
	 * Finds the first table name referenced in a query.
	 *
	 * @since 4.2.0
	 *
	 * @param string $query The query to search.
	 * @return string|false The table name found, or false if a table couldn't be found.
	 */
	protected function get_table_from_query( $query ) {
		// Remove characters that can legally trail the table name.
		$query = rtrim( $query, ';/-#' );

		// Allow (select...) union [...] style queries. Use the first query's table name.
		$query = ltrim( $query, "rnt (" );

		// Strip everything between parentheses except nested selects.
		$query = preg_replace( '/((?!s*select)[^(]*?)/is', '()', $query );

		// Quickly match most common queries.
		if ( preg_match(
			'/^s*(?:'
				. 'SELECT.*?s+FROM'
				. '|INSERT(?:s+LOW_PRIORITY|s+DELAYED|s+HIGH_PRIORITY)?(?:s+IGNORE)?(?:s+INTO)?'
				. '|REPLACE(?:s+LOW_PRIORITY|s+DELAYED)?(?:s+INTO)?'
				. '|UPDATE(?:s+LOW_PRIORITY)?(?:s+IGNORE)?'
				. '|DELETE(?:s+LOW_PRIORITY|s+QUICK|s+IGNORE)*(?:.+?FROM)?'
			. ')s+((?:[0-9a-zA-Z$_.`-]|[xC2-xDF][x80-xBF])+)/is',
			$query,
			$maybe
		) ) {
			return str_replace( '`', '', $maybe[1] );
		}

		// SHOW TABLE STATUS and SHOW TABLES WHERE Name = 'wp_posts'
		if ( preg_match( '/^s*SHOWs+(?:TABLEs+STATUS|(?:FULLs+)?TABLES).+WHEREs+Names*=s*("|')((?:[0-9a-zA-Z$_.-]|[xC2-xDF][x80-xBF])+)\1/is', $query, $maybe ) ) {
			return $maybe[2];
		}

		/*
		 * SHOW TABLE STATUS LIKE and SHOW TABLES LIKE 'wp_123_%'
		 * This quoted LIKE operand seldom holds a full table name.
		 * It is usually a pattern for matching a prefix so we just
		 * strip the trailing % and unescape the _ to get 'wp_123_'
		 * which drop-ins can use for routing these SQL statements.
		 */
		if ( preg_match( '/^s*SHOWs+(?:TABLEs+STATUS|(?:FULLs+)?TABLES)s+(?:WHEREs+Names+)?LIKEs*("|')((?:[\\0-9a-zA-Z$_.-]|[xC2-xDF][x80-xBF])+)%?\1/is', $query, $maybe ) ) {
			return str_replace( '\_', '_', $maybe[2] );
		}

		// Big pattern for the rest of the table-related queries.
		if ( preg_match(
			'/^s*(?:'
				. '(?:EXPLAINs+(?:EXTENDEDs+)?)?SELECT.*?s+FROM'
				. '|DESCRIBE|DESC|EXPLAIN|HANDLER'
				. '|(?:LOCK|UNLOCK)s+TABLE(?:S)?'
				. '|(?:RENAME|OPTIMIZE|BACKUP|RESTORE|CHECK|CHECKSUM|ANALYZE|REPAIR).*s+TABLE'
				. '|TRUNCATE(?:s+TABLE)?'
				. '|CREATE(?:s+TEMPORARY)?s+TABLE(?:s+IFs+NOTs+EXISTS)?'
				. '|ALTER(?:s+IGNORE)?s+TABLE'
				. '|DROPs+TABLE(?:s+IFs+EXISTS)?'
				. '|CREATE(?:s+w+)?s+INDEX.*s+ON'
				. '|DROPs+INDEX.*s+ON'
				. '|LOADs+DATA.*INFILE.*INTOs+TABLE'
				. '|(?:GRANT|REVOKE).*ONs+TABLE'
				. '|SHOWs+(?:.*FROM|.*TABLE)'
			. ')s+(*s*((?:[0-9a-zA-Z$_.`-]|[xC2-xDF][x80-xBF])+)s*)*/is',
			$query,
			$maybe
		) ) {
			return str_replace( '`', '', $maybe[1] );
		}

		return false;
	}

	/**
	 * Loads the column metadata from the last query.
	 *
	 * @since 3.5.0
	 */
	protected function load_col_info() {
		if ( $this->col_info ) {
			return;
		}

		if ( $this->use_mysqli ) {
			$num_fields = mysqli_num_fields( $this->result );
			for ( $i = 0; $i < $num_fields; $i++ ) {
				$this->col_info[ $i ] = mysqli_fetch_field( $this->result );
			}
		} else {
			$num_fields = mysql_num_fields( $this->result );
			for ( $i = 0; $i < $num_fields; $i++ ) {
				$this->col_info[ $i ] = mysql_fetch_field( $this->result, $i );
			}
		}
	}

	/**
	 * Retrieves column metadata from the last query.
	 *
	 * @since 0.71
	 *
	 * @param string $info_type  Optional. Possible values include 'name', 'table', 'def', 'max_length',
	 *                           'not_null', 'primary_key', 'multiple_key', 'unique_key', 'numeric',
	 *                           'blob', 'type', 'unsigned', 'zerofill'. Default 'name'.
	 * @param int    $col_offset Optional. 0: col name. 1: which table the col's in. 2: col's max length.
	 *                           3: if the col is numeric. 4: col's type. Default -1.
	 * @return mixed Column results.
	 */
	public function get_col_info( $info_type = 'name', $col_offset = -1 ) {
		$this->load_col_info();

		if ( $this->col_info ) {
			if ( -1 === $col_offset ) {
				$i         = 0;
				$new_array = array();
				foreach ( (array) $this->col_info as $col ) {
					$new_array[ $i ] = $col->{$info_type};
					$i++;
				}
				return $new_array;
			} else {
				return $this->col_info[ $col_offset ]->{$info_type};
			}
		}
	}

	/**
	 * Starts the timer, for debugging purposes.
	 *
	 * @since 1.5.0
	 *
	 * @return true
	 */
	public function timer_start() {
		$this->time_start = microtime( true );
		return true;
	}

	/**
	 * Stops the debugging timer.
	 *
	 * @since 1.5.0
	 *
	 * @return float Total time spent on the query, in seconds.
	 */
	public function timer_stop() {
		return ( microtime( true ) - $this->time_start );
	}

	/**
	 * Wraps errors in a nice header and footer and dies.
	 *
	 * Will not die if wpdb::$show_errors is false.
	 *
	 * @since 1.5.0
	 *
	 * @param string $message    The error message.
	 * @param string $error_code Optional. A computer-readable string to identify the error.
	 *                           Default '500'.
	 * @return void|false Void if the showing of errors is enabled, false if disabled.
	 */
	public function bail( $message, $error_code = '500' ) {
		if ( $this->show_errors ) {
			$error = '';

			if ( $this->use_mysqli ) {
				if ( $this->dbh instanceof mysqli ) {
					$error = mysqli_error( $this->dbh );
				} elseif ( mysqli_connect_errno() ) {
					$error = mysqli_connect_error();
				}
			} else {
				if ( is_resource( $this->dbh ) ) {
					$error = mysql_error( $this->dbh );
				} else {
					$error = mysql_error();
				}
			}

			if ( $error ) {
				$message = '<p><code>' . $error . "</code></p>n" . $message;
			}

			wp_die( $message );
		} else {
			if ( class_exists( 'WP_Error', false ) ) {
				$this->error = new WP_Error( $error_code, $message );
			} else {
				$this->error = $message;
			}

			return false;
		}
	}

	/**
	 * Closes the current database connection.
	 *
	 * @since 4.5.0
	 *
	 * @return bool True if the connection was successfully closed,
	 *              false if it wasn't, or if the connection doesn't exist.
	 */
	public function close() {
		if ( ! $this->dbh ) {
			return false;
		}

		if ( $this->use_mysqli ) {
			$closed = mysqli_close( $this->dbh );
		} else {
			$closed = mysql_close( $this->dbh );
		}

		if ( $closed ) {
			$this->dbh           = null;
			$this->ready         = false;
			$this->has_connected = false;
		}

		return $closed;
	}

	/**
	 * Determines whether MySQL database is at least the required minimum version.
	 *
	 * @since 2.5.0
	 *
	 * @global string $wp_version             The WordPress version string.
	 * @global string $required_mysql_version The required MySQL version string.
	 * @return void|WP_Error
	 */
	public function check_database_version() {
		global $wp_version, $required_mysql_version;
		// Make sure the server has the required MySQL version.
		if ( version_compare( $this->db_version(), $required_mysql_version, '<' ) ) {
			/* translators: 1: WordPress version number, 2: Minimum required MySQL version number. */
			return new WP_Error( 'database_version', sprintf( __( '<strong>Error:</strong> WordPress %1$s requires MySQL %2$s or higher' ), $wp_version, $required_mysql_version ) );
		}
	}

	/**
	 * Determines whether the database supports collation.
	 *
	 * Called when WordPress is generating the table scheme.
	 *
	 * Use `wpdb::has_cap( 'collation' )`.
	 *
	 * @since 2.5.0
	 * @deprecated 3.5.0 Use wpdb::has_cap()
	 *
	 * @return bool True if collation is supported, false if not.
	 */
	public function supports_collation() {
		_deprecated_function( __FUNCTION__, '3.5.0', 'wpdb::has_cap( 'collation' )' );
		return $this->has_cap( 'collation' );
	}

	/**
	 * Retrieves the database character collate.
	 *
	 * @since 3.5.0
	 *
	 * @return string The database character collate.
	 */
	public function get_charset_collate() {
		$charset_collate = '';

		if ( ! empty( $this->charset ) ) {
			$charset_collate = "DEFAULT CHARACTER SET $this->charset";
		}
		if ( ! empty( $this->collate ) ) {
			$charset_collate .= " COLLATE $this->collate";
		}

		return $charset_collate;
	}

	/**
	 * Determines whether the database or WPDB supports a particular feature.
	 *
	 * Capability sniffs for the database server and current version of WPDB.
	 *
	 * Database sniffs are based on the version of MySQL the site is using.
	 *
	 * WPDB sniffs are added as new features are introduced to allow theme and plugin
	 * developers to determine feature support. This is to account for drop-ins which may
	 * introduce feature support at a different time to WordPress.
	 *
	 * @since 2.7.0
	 * @since 4.1.0 Added support for the 'utf8mb4' feature.
	 * @since 4.6.0 Added support for the 'utf8mb4_520' feature.
	 *
	 * @see wpdb::db_version()
	 *
	 * @param string $db_cap The feature to check for. Accepts 'collation', 'group_concat',
	 *                       'subqueries', 'set_charset', 'utf8mb4', or 'utf8mb4_520'.
	 * @return bool True when the database feature is supported, false otherwise.
	 */
	public function has_cap( $db_cap ) {
		$db_version     = $this->db_version();
		$db_server_info = $this->db_server_info();

		// Account for MariaDB version being prefixed with '5.5.5-' on older PHP versions.
		if ( '5.5.5' === $db_version && str_contains( $db_server_info, 'MariaDB' )
			&& PHP_VERSION_ID < 80016 // PHP 8.0.15 or older.
		) {
			// Strip the '5.5.5-' prefix and set the version to the correct value.
			$db_server_info = preg_replace( '/^5.5.5-(.*)/', '$1', $db_server_info );
			$db_version     = preg_replace( '/[^0-9.].*/', '', $db_server_info );
		}

		switch ( strtolower( $db_cap ) ) {
			case 'collation':    // @since 2.5.0
			case 'group_concat': // @since 2.7.0
			case 'subqueries':   // @since 2.7.0
				return version_compare( $db_version, '4.1', '>=' );
			case 'set_charset':
				return version_compare( $db_version, '5.0.7', '>=' );
			case 'utf8mb4':      // @since 4.1.0
				if ( version_compare( $db_version, '5.5.3', '<' ) ) {
					return false;
				}
				if ( $this->use_mysqli ) {
					$client_version = mysqli_get_client_info();
				} else {
					$client_version = mysql_get_client_info();
				}

				/*
				 * libmysql has supported utf8mb4 since 5.5.3, same as the MySQL server.
				 * mysqlnd has supported utf8mb4 since 5.0.9.
				 */
				if ( false !== strpos( $client_version, 'mysqlnd' ) ) {
					$client_version = preg_replace( '/^D+([d.]+).*/', '$1', $client_version );
					return version_compare( $client_version, '5.0.9', '>=' );
				} else {
					return version_compare( $client_version, '5.5.3', '>=' );
				}
			case 'utf8mb4_520': // @since 4.6.0
				return version_compare( $db_version, '5.6', '>=' );
		}

		return false;
	}

	/**
	 * Retrieves a comma-separated list of the names of the functions that called wpdb.
	 *
	 * @since 2.5.0
	 *
	 * @return string Comma-separated list of the calling functions.
	 */
	public function get_caller() {
		return wp_debug_backtrace_summary( __CLASS__ );
	}

	/**
	 * Retrieves the database server version.
	 *
	 * @since 2.7.0
	 *
	 * @return string|null Version number on success, null on failure.
	 */
	public function db_version() {
		return preg_replace( '/[^0-9.].*/', '', $this->db_server_info() );
	}

	/**
	 * Retrieves full database server information.
	 *
	 * @since 5.5.0
	 *
	 * @return string|false Server info on success, false on failure.
	 */
	public function db_server_info() {
		if ( $this->use_mysqli ) {
			$server_info = mysqli_get_server_info( $this->dbh );
		} else {
			$server_info = mysql_get_server_info( $this->dbh );
		}

		return $server_info;
	}
}

View on Trac
View on GitHub


Позволяет производить любые операции с базой данных WordPress: вставлять, обновлять, получать или удалять данные.

WordPress предоставляет возможность удобно манипулировать своей базой данных за счет php класса wpdb.

PHP класс — относится к ООП (объектно-ориентированному программированию) и в традиционном своем понимании представляет собой полностью самодостаточный код, который должен выполнять определенную функцию. Например, в этом случае через класс wpdb мы может производить всевозможные операции с Базой Данных WordPress зная всего несколько «рычагов» управления классом, которые называются методами.

Обращаться к методам класса wpdb нужно обязательно через глобальную переменную $wpdb (это экземпляр класса wpdb). Также нужно помнить, что внутри обычных функций нужно обязательно глобализировать $wpdb, иначе она будет простой переменной внутри функции, делается это так:

global $wpdb;

C помощью методов $wpdb можно управлять произвольными таблицами в базе данных, не обязательно только теми, которые были созданы WordPress. Допустим, среди прочих таблиц WP, есть таблица newtable и нам нужно выбрать все поля id из нее. Реализовать это можно таким SQL запросом используя $wpdb:

$newtable = $wpdb->get_results( "SELECT id FROM newtable" );

Создавать свои таблицы рекомендуется с помощью функции dbDelta(). Или можно использовать обычный SQL запрос и метод $wpdb->query(‘CREATE TABLE …’);.

Для плагинов создание новых таблиц обычно вешается на хук активации плагина, см. register_activation_hook().

Создание отдельного подключения к базе данных

Нужно понимать, что один объект класса wpdb{} работает с одной БД — с текущей базой данных WordPress. Если нужно работать параллельно с какой-либо другой БД, то нужно создать еще один объект класса wpdb с указанием новых параметров соединения, отличных от тех что указаны в wp-config.php. Делается это так:

global $wpdb2;

$wpdb2 = new wpdb( 'имя_юзера', 'пароль', 'название_БД', 'localhost' );

// если не удалось подключиться, и нужно оборвать PHP с сообщением об этой ошибке
if( ! empty($wpdb2->error) )
	wp_die( $wpdb2->error );

// Готово, теперь используем функции класса wpdb
$results = $wpdb2->get_results( "SELECT * FROM table" );

Для сложных соединений с несколькими БД (репликами), есть хороший плагин, который рекомендуют разработчики WP — hyperdb. Этот плагин расширяет возможности базового класса wpdb. Устанавливается он не как обычный плагин и требует определенных знаний работы с базами данных (в противном случае, толку от этого плагина не будет).

Хуки из класса

Возвращает

Экземпляр класса wpdb.

Использвоание

global $wpdb;

$result = $wpdb->query( "UPDATE ..." );

Примеры

#1 Демонстрация использования методов класса

global $wpdb;

$done = $wpdb->query( "UPDATE ..." );

// get data

$objects = $wpdb->get_results( "SELECT ..." );

$object = $wpdb->get_row( "SELECT ..." );

$values = $wpdb->get_col( "SELECT ..." );

$var = $wpdb->get_var( "SELECT ..." );

$var = $wpdb->get_var( "SELECT ..." );

// CRUD data

$done = $wpdb->insert( 'table', [ 'column' => 'foo', 'field' => 'bar' ] );

$done = $wpdb->update( 'table', [ 'column' => $_GET['val'] ], [ 'ID' => 1 ] );

$done = $wpdb->delete( 'table', [ 'ID' => 1 ] );

$done = $wpdb->replace( 'table_name', [ 'ID' => 1, 'column' => $_GET['val'] ] );

query — произвольный запрос к Базе Данных WordPress

Build In Post

Выполняет любые запросы к базе данных WordPress.

Этот метод подразумевает выполнение всех запросов кроме SELECT. Для SELECT есть специальные методы: $wpdb->get_results, $wpdb->get_row, $wpdb->get_col, $wpdb->get_var.

Имейте ввиду, что как и для всех функций класса wpdb, передаваемые параметры нужно очистить от SQL инъекций, сделать это можно двумя способами:

// способ 1
esc_sql( $user_entered_data_string )

// способ 2
$wpdb->prepare(  'query' , value_parameter[, value_parameter ... ] )

Подробнее читайте в секции «Защита запросов от SQL инъекций»

Возвращает

int|true|false.

  • true — для запросов CREATE, ALTER, TRUNCATE, DROP.
  • Число — задействованных строк, для запросов: DELETE/UPDATE/SELECT.
  • false — когда запрос вызвал ошибку.

Использование

global $wpdb;
$wpdb->query( $query );
$query(строка) (обязательный)
Database query.

Примеры

#1 Удалить произвольное поле ‘gargle’ и его значение у поста 13

$wpdb->query( "DELETE FROM $wpdb->postmeta WHERE post_id = '13' AND meta_key = 'gargle'" );

#2 Установить родительскую страницу 7 для страницы 15

$wpdb->query( "UPDATE $wpdb->posts SET post_parent = 7 WHERE ID = 15 AND post_status = 'static'" );

#3 Удалить осиротевшие произвольные поля

$wpdb->query("DELETE pm FROM $wpdb->postmeta pm LEFT JOIN wp_posts wp ON wp.ID = pm.post_id WHERE wp.ID IS NULL");

#4 Изменим ключ у полей-повторителей ACF

$wpdb->query( "
	UPDATE $wpdb->postmeta
	SET meta_key = REPLACE(meta_key, 'knowledge-base-type', 'knowledge-base-list')
	WHERE `meta_key` LIKE '%knowledge-base-type%'
" );

get_var — получение определенной ячейки таблицы

Build In Post

Получает значение одной ячейки из результата запроса. По умолчанию берется первая ячейка — это первая колонка и первая строка.

Если результат запроса содержит больше одной колонки и/или больше одной строки, то будет возвращено значение указанной ячейки (указывается во 2 и 3 параметрах). Так, чтобы получить значение второй ячейки из второй строки результата запроса, нужно указать второй и третий параметры: $column_offset = 1, $row_offset = 1.

Если вызывать метод без запроса: $query = null, то вернется значение указанной ячейки из предыдущего запроса.

Возвращает

Строку|null. Значение ячейки таблицы базы данных в виде строки.

  • значение ячейки — если запрос получает значение одной ячейки (колонки в строке).
  • значение первой ячейки первой колонки — если запрос получает одну строку и несколько колонок.
  • значение первой ячейки первой строки и колонки — если запрос получает несколько строк и колонок.
  • NULL — когда результата нет.

Использование

$wpdb->get_var( 'query', $column_offset, $row_offset );
query(строка/null)
Запрос который нужно выполнить. Можно установить этот параметр в значение null, тогда функция вернет результат последнего запроса, который был выполнен классом (сохранился в переменной).
column_offset(число)
Нужная колонка (отступ по колонкам). по умолчанию 0 — первая колонка.
row_offset(число)
Нужная строка (отступ по строкам). по умолчанию 0 — первая строка.

Примеры

#1 Выведем на экран количество пользователей

$user_count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->users;" );
echo '<p>Количество пользователей равно: ' . $user_count . '</p>';

#2 Выведем на экран сумму значений определенных произвольных полей

// определяем произвольный ключ, который нужно посчитать
$meta_key = 'miles';
$allmiles = $wpdb->get_var($wpdb->prepare(
	"SELECT sum(meta_value) FROM $wpdb->postmeta WHERE meta_key = %s", $meta_key
));
echo '<p>Общее количество произвольных полей miles: '.$allmiles . '</p>';

#3 Набор выводов статистики блога

# Общее Количество авторов блога
function get_totalauthors() {
	global $wpdb;
	$totalauthors = intval( $wpdb->get_var(
		"
		SELECT COUNT(ID) FROM $wpdb->users
		LEFT JOIN $wpdb->usermeta ON $wpdb->usermeta.user_id = $wpdb->users.ID
		WHERE $wpdb->users.user_activation_key = '' AND $wpdb->usermeta.meta_key = '{$wpdb->prefix}user_level' AND (meta_value+0.00) > 1
		"
	) );

	return $totalauthors;
}

# Общее Количество постов
function get_totalposts(){
	global $wpdb;
	$totalposts = intval( $wpdb->get_var(
		"SELECT COUNT(ID) FROM $wpdb->posts WHERE post_type = 'post' AND post_status = 'publish'"
	) );

	return $totalposts;
}

# Общее Количество страниц
function get_totalpages() {
	global $wpdb;
	$totalpages = intval( $wpdb->get_var(
		"SELECT COUNT(ID) FROM $wpdb->posts WHERE post_type = 'page' AND post_status = 'publish'"
	));

	return $totalpages;
}

# Общее Количество комментариев
function get_totalcomments() {
	global $wpdb;
	$totalcomments = intval( $wpdb->get_var(
		"SELECT COUNT(comment_ID) FROM $wpdb->comments WHERE comment_approved = '1'"
	));

	return $totalcomments;
}

# Общее Количество комментаторов
function get_totalcommentposters() {
	global $wpdb;
	$totalcommentposters = intval($wpdb->get_var(
		"SELECT COUNT(DISTINCT comment_author) FROM $wpdb->comments WHERE comment_approved = '1' AND comment_type = ''"
	));

	return $totalcommentposters;
}

# Общее Количество ссылок
function get_totallinks() {
	global $wpdb;
	$totallinks = intval( $wpdb->get_var("SELECT COUNT(link_id) FROM $wpdb->links") );

	return $totallinks;
}

get_row — выбор строки таблицы

Build In Post

Получает первую строку из результата SQL запроса. Возвращает строку в виде объекта.

Используйте параметр $row_offset, чтобы получить вторую, третью, …, n-ю строку из запроса.

Возвращает

Массив|Объект|null|null.

  • object — при $output_type = OBJECT (по умолчанию).
  • array — при $output_type = ARRAY_A или ARRAY_N.
  • null — когда не удалось получить данные (запрашиваемых данных нет в бд).

Использование

$wpdb->get_row( $query, $output_type, $row_offset );
$query(строка)
Запрос который нужно выполнить.
$output_type(константа)

Одна из трех констант. Может быть:

  • OBJECT — результат будет возвращен в виде объекта (по умолчанию).
  • ARRAY_A — результат будет возвращен в виде ассоциативного массива.
  • ARRAY_N — результат будет возвращен в виде пронумерованного массива.
    По умолчанию OBJECT
$row_offset(число)
Номер возвращаемой строки результата запроса.
По умолчанию 0 (первая строка)

Примеры

#1 Получим всю информацию о ссылке 10

$mylink = $wpdb->get_row( "SELECT * FROM $wpdb->links WHERE link_id = 10" );

// Теперь, свойства (переменные) $mylink - это названия
//колонок из таблицы $wpdb->links со значениями полей таблицы:
echo $mylink->link_id; // выведет на экран "10"

#2 С использованием константы:

$mylink = $wpdb->get_row( "SELECT * FROM $wpdb->links WHERE link_id = 10", ARRAY_A );

// результатом будет ассоциативный массив
echo $mylink['link_id']; // выведет на экран "10"

или

$mylink = $wpdb->get_row( "SELECT * FROM $wpdb->links WHERE link_id = 10", ARRAY_N );

// результатом будет пронумерованный массив
echo $mylink[1]; // выведет на экран"10"

get_col — выбор столбца таблицы

Build In Post

Делает запрос и получает данные одной колонки таблицы базы данных в виде массива.

Если запрос вернул больше чем одну колонку (столбец), то функция вернет только данные первого столбца. Можно указать отступ в параметре $column_offset, чтобы получить данные не первого столбца, а например второго: $column_offset = 1.

Если указать $query = null, то функция вернет указанную колонку из предыдущего запроса. Используя это свойство можно получить данные других колонок из уже сделанного запроса.

Возвращает

Массив. Индексный массив с данными запроса. Пустой массив, когда не удалось получить данные.

Использование

global $wpdb;
$wpdb->get_col( $query, $x );
$query(строка/null)
Запрос который нужно выполнить. Можно установить этот параметр в значение null, тогда функция вернет результат последнего запроса.
По умолчанию: NULL (предыдущий запрос)
$x(число)
Индекс колонки данные которой нужно вернуть.
По умолчанию: 0 (первая колонка)

Примеры

#1 Пример того как работает метод и что возвращает

Допустим у нас есть такой запрос на получение всех ревизий:

// укажем в запросе одно поле
$revision_ids = $wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE post_type = 'revision'" );

// укажем в запросе все поля
$revision_ids = $wpdb->get_col( "SELECT * FROM $wpdb->posts WHERE post_type = 'revision'" );

/*
В обоих случаях вернется одинаковый массив.
Когда указываются все поля, get_col получает только первое - это ID

Array(
	[0] => 106
	[1] => 101
	[2] => 102
	[3] => 103
	...
)
*/

#2 Использование без указания $query параметра

// сначала сделаем запрос
$wpdb->query( "SELECT * FROM $wpdb->posts WHERE post_type = 'revision' LIMIT 10" );

// теперь получим данные этого запроса
$revision_ids = $wpdb->get_col( null );
$revision_names = $wpdb->get_col( null, 5 ); // 5 - post_title

/*
Array
(
	[0] => 9949
	[1] => 9957
	[2] => 10125
	[3] => 10154
	[4] => 10221
	[5] => 10235
	[6] => 10319
	[7] => 10496
	[8] => 10532
	[9] => 10568
)
Array
(
	[0] => wp_tempnam
	[1] => Шаблоны страницы для типов записей в WP 4.7
	[2] => Политика конфиденциальности
	[3] => walker_nav_menu_start_el
	[4] => Вывод пагинации
	[5] => enter_title_here
	[6] => Smart Custom Fields - простой плагин метаполей
	[7] => register_post_type
	[8] => О сайте
	[9] => REST API в WordPress
)
*/

#3 NULL вместо пустой строки

Этот метод возвращает NULL в качестве значения поля, если в значении пустая строка (проверял на версии WP 5.1.1). Но если нам нужно получить оригинальные данные (пустую строку), можно использовать такую замену get_col():

$wpdb->query( "SELECT * FROM $wpdb->posts WHERE post_type = 'revision'" );

$ids = wp_list_pluck( $wpdb->last_result, 'ID' );

#4 Выбор столбца из результатов запроса

Для этого примера представим, что у нас блог об автомобилях. Каждый пост описывает какой-либо автомобиль (например, Ford Mustang 1969 года). Для каждого поста предусмотрено по 3 произвольных поля: manufacturer (производитель), model(модель) и year(год выпуска). Этот пример выведет на экран заголовки постов, отфильтрованных по производителю (ford) и отсортированных по модели и году.

get_col здесь используется для того, чтобы получить массив ID всех записей, удовлетворяющих определенным критериям и отсортированных в нужном порядке. Затем через цикл foreach мы выводим заголовки по имеющимся у нас ID:

<?php
$meta_key1 = 'model';
$meta_key2 = 'year';
$meta_key3 = 'manufacturer';
$meta_key3_value = 'Ford';

$postids = $wpdb->get_col($wpdb->prepare("
SELECT      key3.post_id
FROM        $wpdb->postmeta key3
INNER JOIN  $wpdb->postmeta key1
			on key1.post_id = key3.post_id
			and key1.meta_key = %s
INNER JOIN  $wpdb->postmeta key2
			on key2.post_id = key3.post_id
			and key2.meta_key = %s
WHERE       key3.meta_key = %s
			and key3.meta_value = %s
ORDER BY    key1.meta_value, key2.meta_value",$meta_key1, $meta_key2, $meta_key3, $meta_key3_value));

if ($postids) {
  echo 'List of ' . $meta_key3_value . '(s), sorted by ' . $meta_key1 . ', ' . $meta_key2;
  foreach( $postids as $id ){
	$post = get_post(intval($id));
	setup_postdata($post);
	?>
	<p><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_title(); ?></a></p>
	<?php
  }
}

#5 Список постов которые имеют определенное произвольное поле (Color)

Но отсортированы они по значению другого произвольного поля (Display_Order).

$meta_key1 = 'Color';
$meta_key2 = 'Display_Order';

$postids = $wpdb->get_col($wpdb->prepare("
SELECT      key1.post_id
FROM        $wpdb->postmeta key1
INNER JOIN  $wpdb->postmeta key2
			on key2.post_id = key1.post_id
			and key2.meta_key = %s
WHERE       key1.meta_key = %s
ORDER BY    key2.meta_value+(0) ASC",
		 $meta_key2,$meta_key1));

if ($postids) {
  echo 'List of '. $meta_key1  . ' posts, sorted by ' . $meta_key2 ;
  foreach ($postids as $id) {
	$post=get_post(intval($id));
	setup_postdata($post);?>
	<p><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_title(); ?></a></p>
	<?php
  }
}

get_results — выбор нескольких строк таблицы

Build In Post

Получает все данные указанного запроса (все строки и колонки). Результат возвращается в виде массива. Каждый элемент массива это объект с данными отдельной строки таблицы.

Возвращает

Массив|Объект|null. Результат запроса к базе данных. Вернет:

  • Массив объектов — когда $output = OBJECT или OBJECT_K.
  • Массив массивов — когда $output = ARRAY_A или ARRAY_N.
  • array() — когда строк по запросу не найдено или ошибка запроса.
  • NULL — когда запрос пустая строка или передан неправильный тип вывода ($output_type).

Использование

global $wpdb;
$wpdb->get_results( $query, $output );
$query(строка)

Запрос который нужно выполнить.

Можно установить этот параметр в значение null, тогда функция вернет результат последнего запроса, который был произведен.

По умолчанию: null

$output(константа/строка)

Флаг указывающий в каком виде нужно вернуть данные. Возможны 4 варианта:

  • OBJECT — вернет массив объектов с числовыми ключами — элементы массива будут объекты строк таблицы — [ 0 => object ].
  • OBJECT_K — похож на предыдущий, только в индексах главного массива будут значения первой колонки результата запроса — [ 'field' => object ].
    Обратите внимание, если в индекс будут попадать одинаковые значения, то данные будут затираться.
  • ARRAY_N — вернет индексный массив, каждый элемент которого будет так же индексным массивом — [ 0 => [...] ].
  • ARRAY_A — вернет индексный массив, каждый элемент которого будет ассоциативным массивом, в котором ключом будет название колонки — [ 'field' => [...] ].

По умолчанию: OBJECT

Примеры

#1 Получим ID и заголовки черновиков, ID автора которых равен 5 и выведем на экран заголовки постов.

$fivesdrafts = $wpdb->get_results( "SELECT ID, post_title FROM $wpdb->posts WHERE post_status = 'draft' AND post_author = 5" );

foreach ( $fivesdrafts as $fivesdraft ) {
	echo $fivesdraft->post_title;
}

#2 Пример сложного запроса с GROUP BY (отзывов в WooCommerce)

/**
* Возвращает результаты рейтинга (отзывов в WooCommerce) сгрупированный по оценкам
*
* @param int $post_id идентификатор поста
*
* @return array массив объектов, где каждый объект - сгрупированные данные по одной из оценок
*/
function get_cnt_rating_reviews_one_product( $post_id ){
	global $wpdb;

	return $wpdb->get_results( $wpdb->prepare(
		"
		SELECT COUNT(meta.meta_id) as num, meta.meta_value
		FROM $wpdb->comments as comments
		INNER JOIN $wpdb->commentmeta as meta ON comments.comment_ID = meta.comment_id
		WHERE comments.comment_post_ID = %d AND meta_key = 'rating'
		GROUP BY meta.meta_value;
		",
		$post_id
	) );

}

// использование
get_cnt_rating_reviews_one_product( 4350 );

#3 Обработка ошибок

Вот как можно перехватывать ошибки из get_results():

global $wpdb;
$result = $wpdb->get_results( "SELECT * FROM invalid query" );

if ( $wpdb->last_error ) {
  echo 'wpdb error: ' . $wpdb->last_error;
}

#4 Выведем на экран ссылки на черновики автора с ID = 5

<?php
$fivesdrafts = $wpdb->get_results( "SELECT * FROM $wpdb->posts WHERE post_status = 'draft' AND post_author = 5");
if( $fivesdrafts ) :
	foreach( $fivesdrafts as $post ){
		setup_postdata($post);
		?>
			<h2><a href="<?php the_permalink(); ?>" rel="bookmark"
				title="Permanent Link to <?php the_title(); ?>"><?php the_title(); ?></a></h2>
		<?php
	}
else :
?>
	<h2> Не найдено</h2>
<?php endif; ?>

insert — вставка новой записи (строки) в таблицу

Build In Post

Вставляет строку (указанные данные) в указанную таблицу.

Метод очищает переданные данные и защищает от SQL инъекций, поэтому данные могут быть «грязные» (неочищенные), например: $_GET['foo'].

После добавления данных созданное значение AUTO_INCREMENT можно получить в переменной: $wpdb->insert_id.

Возвращает

int|false.

  • число — число вставленных строк.
  • false — если данные не были вставлены в таблицу.

ВНИМАНИЕ! Вернет false (без каких либо ошибок), когда передаваемая для вставки строка (значение ячейки) длинее максимально возможного. Например колонка varchar(10) (длина значения 10 символов), а в переданных данных для вставки указана строка с 11 или более символами.

Поймать такой баг очень сложно! Поэтому надо иметь это ввиду, когда все вроде бы должно работать (правильные данные передается), но wpdb::insert() возвращает false без каких-либо ошибок.

Такая проблема касается почти всех методов, это:
wpdb::replace()
wpdb::insert()
wpdb::update()
wpdb::delete()

Использование

global $wpdb;
$wpdb->insert( $table, $data, $format );
$table(строка) (обязательный)
Название таблицы в которую будем вставлять данные.
$data(массив)

Данные которые нужно вставить. Каждый элемент массива выглядит так: [ 'колонка таблицы' => 'значение' ].

Если указать в значении NULL, то в значение будет установлено NULL, указанный формат при этом игнорируется.

Передаваемые данные НЕ должны быть очищены: esc_sql().

$format(массив/строка)

Массив форматов данных которые будут ассоциированы с указанными значениями в параметре $data. Если указана строка, то она (формат) будет ассоциирован со всеми данными. При указании формата, WordPress переводит переданные данные в указанный формат перед тем, как сохранить данные. Возможные форматы:

  • %s — строка
  • %d — целое число
  • %f — дробное число

Если не указать, то для всех значений $data будет указан формат строка, если иное не указано в свойстве wpdb::$field_types.
По умолчанию: null

Примеры

#1 Вставим строку в таблицу БД

// вставка строки с указанием значений для двух полей (значения для остальных полей будут дефолтные)
$wpdb->insert( 'table', [ 'column' => 'foo', 'field' => 'bar' ] );

// с указанием типов данных
$wpdb->insert( 'table', [ 'column' => 'foo', 'field' => 1337 ], [ '%s', '%d' ] );

#2 Получение идентификатора вставленного объекта

Чтобы получить его, используйте $wpdb->insert_id:

global $wpdb;

$table = $wpdb->prefix . 'my_table_name';
$data = [ 'column1' => 'data one', 'column2' => 123 ];

$wpdb->insert( $table, $data );

$my_id = $wpdb->insert_id;

update — обновление записи (строки) в таблице

Build In Post

Обновляет указанные данные в указанной строке таблицы.

Метод включает защиту от SQL инъекций и данные можно передавать как есть, например: $_GET['foo'].

НЕ вставляет данные если их нет в БД — только обновляет существующие данные.

Возвращает

int|false.

  • число — сколько строк было обработано
  • 0 — запрос был выполнен корректно, но ни одна строка не была обработана. Если в БД уже есть данные и вы пытаетесь обновить, указав точно такие же данные, то wpdb::update() вернет 0.
  • false — запрос провалился или ошибка запроса.

Так как возвращается 0, если никакие поля не были обновлены (изменены), но запрос был выполнен корректно, проверку результата запроса на ошибку нужно делать с учетом типа возвращаемых данных $res === false.

Использование

global $wpdb;
$wpdb->update( $table, $data, $where, $format, $where_format );
$table(строка) (обязательный)
Название таблицы, данные в которой нужно обновить.
$data(массив) (обязательный)

Данные, которые нужно обновить в формате [ 'название колонки' => 'новое значение' ].

Если в значении указать NULL, то в значение будет установлено в NULL, соответствующий формат при этом игнорируется.

$where(массив) (обязательный)
Ассоциированный массив с условием выборки строк таблицы данные в которых нужно обновить (SQL WHERE). Формат массива: [ 'название колонки' => 'чему равно' ]. Если указать несколько элементов в массиве, то указанные условия будут объедены через AND — т.е. должны будут совпасть все условия, а НЕ какое-либо одно. Если в значении указать NULL то в запросе получим сравнение IS NULL, соответствующий формат при этом игнорируется.
$format(массив/строка)

Массив форматов данных которые будут ассоциированы с указанными значениями в параметре $data. Если указана строка, то она (формат) будет ассоциирован со всеми данными. При указании формата, WordPress переводит переданные данные в указанный формат перед созданием запроса. Возможные форматы:

  • %s — строка
  • %d — целое число
  • %f — дробное число

Если не указать, то для всех значений $data будет указан формат строка, если иное не указано в свойстве wpdb::$field_types.
По умолчанию: null

$where_format(массив/строка)
Тоже самое что и $format, только для $where данных.
По умолчанию: null

Примеры

#1 Обновим строку ID которой равен 1

Значение первой колонки строка, значение второй колонки число:

$wpdb->update( 'table',
	[ 'column1' => 'value1', 'column2' => $_GET['val'] ],
	[ 'ID' => 1 ]
);

#2 Тоже самое с указанием типов передаваемых данных

$wpdb->update( 'table',
	[ 'column1' => 'value1', 'column2' => $_GET['val'] ],
	[ 'ID' => 1 ],
	[ '%s', '%d' ],
	[ '%d' ]
);
$wpdb->update( 'table', [ 'column' => 'foo', 'field' => 'bar' ], [ 'ID' => 1 ] );
$wpdb->update( 'table', [ 'column' => 'foo', 'field' => 1337 ], [ 'ID' => 1 ], [ '%s', '%d' ], [ '%d' ] );

replace — замена строки

Build In Post

Обновляет или создает строку в таблице.

Если строка с указанным ключом PRIMARY KEY уже есть все остальные указанные поля будут обновлены у строки. Если такой строки в таблице еще нет, то функция вставит (insert) новую строку.

После вставки, ID созданный для колонки AUTO_INCREMENT можно получить в свойстве $wpdb->insert_id.

Метод включает защиту от SQL инъекций. Т.е. можно передавать неочищенные данные, например из параметров запроса: $_GET['foo'].

Для вставки новой строки необязательно указывать поле с авто-инкрементом. Например, у нас есть таблица с полем id (AUTO_INCREMENT). Можно указать значения всех полей кроме id и строка будет добавлена в таблицу.

PRIMARY KEY может состоять из нескольких ключей. В этом случае при поиске для замены существующей строки всегда будут использоваться все колонки указанные в PRIMARY KEY. Все остальные поля, кроме полей из PRIMARY KEY, в поиске существующих строк не участвуют.

Например, PRIMARY KEY состоит из двух колонок ID и type: PRIMARY KEY (ID,type). Тогда для замены существующей строки в параметре $data нужно указать значение этих двух колонок. Если например указать ID и не указать type, то существующая строка не будет найдена и будет создана новая строка с указанным ID и дефолтным значением type.

Если длина строки в параметре $data больше чем допускается в ячейке таблицы MySQL, вставка провалиться и функция вернет false. При этом в свойство $wpdb->last_error сообщение об ошибке НЕ будет записано! Впрочем это же касается и других методов wpdb.

Поэтому очень важно убедиться, что вставляемые данные подходят под размер ячеек (колонок). Иначе просто ничего не произойдет и вы не увидите никаких ошибок или предупреждений.

Всегда заменяются все поля таблицы. Например, если у таблицы есть поля primary, one, two, three, а мы указали в параметре $data только primary, one, то поля two и three получат дефолтные значения, даже если там уже были данные.

Может произойти замена сразу нескольких имеющихся строк — это когда заменяемые данные совпадают с существующими, а уникальный индекс у имеющихся строк разный.

Возвращает

int|false. Число (кол-во обработанных строк), 0 или false.

  • число — сколько строк было обработано (удалено или вставлено). Если была замена (обновление), то для каждой обновленной строки вернется +2 (удаление и вставка). Если была просто вставка, то для каждой вставленной строки вернется +1.
  • 0 — запрос был выполнен корректно, но ни одна строка не была обработана.
  • false — запрос провалился — ошибка запроса. Или когда невозможно заменить или создать новую строку в таблице.

Вернет количество затронутых строк — это сумма вставленных и удаленных строк. Если вернулось 1 при замене одной строки — это значит что одна строка была вставлена и ни одна не была удалена. Если число больше 1 — это значит, что одна или больше строк были удалены перед вставкой новой строки.

Использование

global $wpdb;
$wpdb->replace( $table, $data, $format );
$table(строка) (обязательный)
Название таблицы, в которой нужно заменить данные.
$data(массив) (обязательный)

Данные, которые нужно заменить/вставить в формате [ 'название колонки' => 'новое значение' ].

Если в значении указать NULL, то в значение будет установлено в NULL, соответствующий формат при этом игнорируется.

$format(массив/строка)

Массив форматов данных которые будут ассоциированы с указанными значениями в параметре $data. Если указана строка, то она (формат) будет ассоциирован со всеми данными. При указании формата, WordPress переводит переданные данные в указанный формат перед созданием запроса. Возможные форматы:

  • %s — строка
  • %d — целое число
  • %f — дробное число

Если не указать, то для всех значений $data будет указан формат строка, если иное не указано в свойстве wpdb::$field_types.
По умолчанию: null

Примеры

#1 Заменим строку с главным ключом ID = 1

(подразумевается что таблица состоит из трех колонок ID, column1, column2).

Строка будет добавлена если её нет или полностью обновлена если она есть. Тут важно указывать значения для всех полей, потому что поля без значений получат дефолтные, даже если в них до этого были данные.

$wpdb->replace( 'table_name', [
	'ID'      => 1,
	'column1' => 'value1',
	'column2' => 123
] );

#2 Укажем форматы

$wpdb->replace( 
	'table_name', 
	[ 'column' => 'foo', 'field' => 1337 ], 
	[ '%s', '%d' ] 
);

delete — удаление строки из таблицы

Build In Post

Удаляет строки из таблицы по условию указанному в параметре $where.

Включает защиту от SQL инъекций, это значит что можно передавать неочищенные данные, например: $_GET['foo']

Возвращает

int|false. Число удаленных строк или 0, если ничего не удалено. false возвращается при ошибке запроса.

Использование

global $wpdb;
$wpdb->delete( $table, $where, $where_format );
$table(строка) (обязательный)
Название таблицы.
$where(массив) (обязательный)
Массив условий, по которым будут выбираться строки для удаления в формате [ 'название колонки' => 'чему равно' ]. Несколько условий будут объеденные через AND. Если в значении указать NULL то в запросе получим сравнение IS NULL, соответствующий формат при этом игнорируется.
$where_format(массив/строка)

Массив форматов данных которые будут ассоциированы с указанными значениями в параметре $where. Если указана строка, то она (формат) будет ассоциирован со всеми данными. При указании формата, WordPress переводит переданные данные в указанный формат перед созданием запроса. Возможные форматы:

  • %s — строка
  • %d — целое число
  • %f — дробное число

Если не указать, то для всех значений $data будет указан формат строка, если иное не указано в свойстве wpdb::$field_types.
По умолчанию: null

Примеры

#1 Пример удаления данных из БД

// Удалим строку с полем ID=1 из таблицы table
$wpdb->delete( 'table', [ 'ID' => 1 ] );

// Укажем формат значения $where
$wpdb->delete( 'table', [ 'ID'=>'1' ], [ '%d' ] ); // 1 будет обработано как число (%d).

prepare — защита запроса от SQL инъекций

Build In Post

Позволяет писать SQL запрос с очисткой передаваемых в него параметров.

В строке запроса вместо передаваемого параметра нужно использовать плейсхолдер:

  • %d (integer)
  • %f (float)
  • %s (string)

Также для каждого из плейсхолдеров указывается PHP переменная, которая заменит плейсхолдер. При замене переменная будет очищена. Синтаксис похожий на sprintf().

С WP 3.5 обязательно должны быть переданы минимум 2 параметра: запрос и значение переменной, иначе будет php ошибка (User Notice).

Кавычки для плейсхолдеров %s и '%s'.

Плейсхолдеры могут быть в кавычках или без них: WHERE field = %s или WHERE field = '%s'. Кавычки принято не ставить.

echo $wpdb->prepare( "foo = %s", 'a' );   // foo = 'a'
echo $wpdb->prepare( "foo = '%s'", 'a' ); // foo = 'a'
Параметр для каждого плейсхолдера.

Параметр должен быть указан для каждого плейсхолдера.

echo $wpdb->prepare( 'foo = %s AND bar = %s', 'a' );
echo $wpdb->prepare( 'foo = %1$s AND bar = %1$s', 'a' );
// в обоих случаях увидим ошибку:
// User Notice: wpdb::prepare was called incorrectly.
// The query does not contain the correct number of placeholders (2)
// for the number of arguments passed (1).
Порядковые плейсхолдеры %1$s.

Для совместимости со старыми версиями: порядковые плейсхолдеры (например, %1$s, %5s) обрабатываются иначе — им не добавляются кавычки, поэтому они должны быть снабжены правильными кавычками в строке запроса.

echo $wpdb->prepare( 'foo = %1$s', 'a"a' );   // foo = a"a
echo $wpdb->prepare( 'foo = "%1$s"', 'a"a' ); // foo = "a"a"
echo $wpdb->prepare( 'foo = %1s', 'a"a' );    // foo = a"a
echo $wpdb->prepare( 'foo = %s', 'a"a' );     // foo = 'a"a'
Знак %

Знак % в строке запроса, который не относится к плейсхолдеру нужно записывать так %%.

echo $wpdb->prepare( "%foo AND id = %d", 2 ); // User Notice: wpdb::prepare was called incorrectly.
echo $wpdb->prepare( "%%foo AND id = %d", 2 ); // %foo AND id = 2
% в LIKE синтаксисе

Подстановочные знаки процента % в LIKE синтаксисе должны указываться через параметр подстановки содержащий полную LIKE строку, а не напрямую в запросе. Также смотрите wpdb::esc_like().

$like = '%'. $wpdb->esc_like( "bar's" ) .'%end';
echo $wpdb->prepare( "foo LIKE %s", $like ); // foo LIKE '{a0d1d}bar's{a0d1d}end'

SQL инъекция

В SQL есть такое понятие как «инъекция» (внедрение в запрос SQL кода). Cделать его можно, когда в запрос передаются динамические данные. Например, в запрос передаётся значение input поля, в это поле можно указать данные, которые в итоге станут частью SQL запроса. Так можно внедриться в запрос и что-нибудь испортить или просто нарушить код самого запроса. Выглядит это так:

$sql = "SELECT * FROM table WHERE id = '$var'";

Теперь, если var = 2' AND id = (DROP TABLE table2) то в результате запрос получиться такой:

SELECT * FROM table WHERE id = '2' AND id = (DROP TABLE table2)

Таким образом можно внедриться в сам запрос и изменить его. Чтобы этого не произошло запросы с передаваемыми в них переменными нужно обрабатывать методом prepare():

$sql = $wpdb->prepare( "SELECT * FROM table WHERE id = %s", $var );

esc_sql()

Кроме метода $wpdb->prepare() запрос можно очистить функцией esc_sql(). Но «prepare» предпочтительнее, потому что исправляет некоторые ошибки форматирования.

$name   = esc_sql( $name );
$status = esc_sql( $status );

$wpdb->get_var( "SELECT something FROM table WHERE foo = '$name' and status = '$status'" );

ВАЖНО! После esc_sql() очищенную строку можно использовать только внутри кавычек '' или "". Т.е. правильно писать field = '$value', а не field = $value, где $value = esc_sql( $value );

Возвращает

Строку|null. Sanitized query string, if there is a query to prepare.

Использование

global $wpdb;
$wpdb->prepare( $query, ...$args );
$query(строка) (обязательный)

Строка запроса. В нем можно использовать заменители:

  • %d — число
  • %s — строка
  • %f — дробное число (число с плавающей точкой, с версии 3.3).
…$args(строка/число/массив)

Переменные, которые будут использованы для замены плейсхолдеров %s %d %f в строке запроса.

Эти переменные можно указать через запятую (как дополнительные параметры функции) или в массиве:

  • $wpdb->prepare( 'query', $param1, $param2 )
  • $wpdb->prepare( 'query', [ $param1, $param2 ] ).

Примеры

#1 Демонстрация работы

$wpdb->prepare(
	"SELECT * FROM `table` WHERE `column` = %s AND `field` = %d OR `other_field` LIKE %s",
	[ 'foo', 1337, '%bar' ]
);

$wpdb->prepare(
	"SELECT DATE_FORMAT(`field`, '%%c') FROM `table` WHERE `column` = %s", 'foo'
);

#2 Добавим произвольное поле к посту 10

Из примера видно, что с prepare() нет необходимости заботиться об экранировании кавычек и прочего, что может навредить запросу.

$metakey   = "'крах' БД";
$metavalue = "WordPress может 'сломать' Базу Данных если не экранировать запрос.";

$wpdb->query(
	$wpdb->prepare(
		"INSERT INTO $wpdb->postmeta ( post_id, meta_key, meta_value ) VALUES ( %d, %s, %s )",
		10,
		$metakey,
		$metavalue
  )
);

#3 Передача параметров в виде массива

Это такой же пример, только тут все переменные передаются во втором параметре в виде массива.

Передавать параметры в виде массива, может быть полезно, когда мы заранее не знаем количество аргументов, которые нужно будет передать.

$metakey = "'крах' БД";
$metavalue = "WordPress может 'сломать' Базу Данных если не экранировать запрос.";

$wpdb->query(
	$wpdb->prepare(
		"INSERT INTO $wpdb->postmeta ( post_id, meta_key, meta_value ) VALUES ( %d, %s, %s )",
		array(
			10,
			$metakey,
			$metavalue
		)
  )
);

#4 Очистка значений для WHERE IN условия

Это полезно в случаях, когда у вас есть массив значений, который нужно передать в IN условие запроса. Кол-во элементов массива может быть разное, поэтому заполнители нужно создавать динамически:

$in_values = [ 'one', 'two' ];

$in_pholders = implode( ',', array_fill( 0, count( $in_values ), '%s' ) );

$sql = $wpdb->prepare( 
	"SELECT $wpdb->posts WHERE post_type = %s WHERE post_name IN ( $in_pholders )",
	[ 'page', ...$in_values ]
);

echo $sql; 

// SELECT wp_posts WHERE post_type = 'page' WHERE post_name IN ( 'one','two' )

esc_like — очистка LIKE строки

Build In Post

Подготавливает строку для использования в LIKE части SQL запроса. Обрабатывает спецсимволы % и _.

Пример:

$wild = '%';
$find = 'only 43% of planets';
$like = $wild . $wpdb->esc_like( $find ) . $wild;
$sql  = $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_content LIKE %s", $like );

Пример цепочки вызовов:

$sql = esc_sql( $wpdb->esc_like( $input ) );

Не защищает от SQL инъекций. Для такой защиты результат нужно дополнительно обработать одной из функций: wpdb::prepare() или esc_sql().

Возвращает

Строку. Текст для LIKE части запроса. Результат не очищен для SQL запроса, поэтому используйте wpdb::prepare() или wpdb::_real_escape() для добавления результата в запрос.

Использование

global $wpdb;
$wpdb->esc_like( $text );
$text(строка) (обязательный)
Необработанный текст, спец-символы в котором нужно экранировать для LIKE строки. Строка не должна иметь дополнительных или удаленных слэшей.

Примеры

#1 Пример подготовки строки для LIKE запроса

$wild = '%';
$find = 'only 43% of planets';
$like = $wild . $wpdb->esc_like( $find ) . $wild;
$sql  = $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE post_content LIKE %s", $like );

echo $sql; // SELECT * FROM wp_posts WHERE post_content LIKE '{d710cab}only 43{d710cab} of planets{d710cab}'

#2 Пример с esc_sql()

$esc_like = $wpdb->esc_like( 'only 43% of planets' );
echo $esc_like;                                        // only 43% of planets
echo esc_sql( $esc_like );                             // only 43{f5fa52} of planets

#3 Еще пример подготовки строки для LIKE запроса

global $wpdb;
$link = $wpdb->esc_like( $link ); // подготовим строку для LIKE аргумента
$link = esc_sql( $link );         // очистим переменную
$link = '%' . $link . '%';        // создадим полную переменную поиска LIKE

// найдем комментарии в тексте или ссылке автора, есть указанная ссылка
$spammy = $wpdb->query("SELECT comment_approved FROM $wpdb->comments
	WHERE (comment_content LIKE '$link' OR comment_author_url LIKE '$link')
		AND comment_approved = 'spam'
	LIMIT 1;"
);

#4 Короткая запись с prepare()

global $wpdb;

$link = '%' . $wpdb->esc_like( $link ) . '%';

$comment = $wpdb->get_row( $wpdb->prepare(
	"SELECT * FROM $wpdb->comments WHERE comment_author_url LIKE %s LIMIT 1", $link
 ) );

show/hide/print_error — показать или спрятать ошибки SQL

Есть возможность управлять ошибками, включать или выключать показ ошибок для последнего запроса:

$wpdb->show_errors(); // включит показ ошибок
$wpdb->hide_errors(); // выключит показ ошибок
$wpdb->print_error(); // включит показ ошибок на экран

get_col_info — получить информацию о колонке

Build In Post

Получает массив с информацией о колонках последнего запроса.

Если в запросе колонки не определены, то функция вернет информацию о всех колонках таблицы. Это может пригодится, когда был возвращен объект, о данных которого мы ничего не знаем.

Работает на основе кэша, поэтому сначала нужно сделать запрос используя get_results(), get_col(), get_var() и т.д. а потом вызвать эту функцию — она вернет данные колонок последнего запроса.

Возвращает

Разное. Данные колонок.

Использование

global $wpdb;
$wpdb->get_col_info( $info_type, $col_offset );
$info_type(строка)

Указывает какую информацию нам нужно получить. Список возможных значений:

  • name — название колонки.
  • table — название таблицы к которой принадлежит колонка.
  • max_length — максимальная длинна данных колонки.
  • not_null — 1 если ячейка колонки не может принимать значение NULL.
  • primary_key — 1 если колонка является первичным ключом.
  • unique_key — 1 если ячейки колонки должны быть всегда уникальны.
  • multiple_key — 1 если ячейки колонки могут быть не уникальны.
  • numeric — 1 если колонка содержит числовые данные.
  • blob — 1 если колонка содержит данные типа BLOB (двоичные данные).
  • type — тип колонки.
  • unsigned — 1 если колонка имеет тип данных UNSIGNED.
  • zerofill — 1 если колонка имеет тип данных ZEROFILL.

По умолчанию: name

$col_offset(число)

Указатель, информацию о какой колонке нужно получить:

  • -1 — будет получена информация о всех колонках в виде массива. По умолчанию.
  • 0, 1, 2, ... — будет возвращена информация об указанной колонке, где 0 — первая колонка, 1 — вторая и т.д.

По умолчанию: -1

Примеры

#1 Демонстрация работы

Сделаем запрос:

global $wpdb;

$results = $wpdb->get_results( "SELECT * FROM $wpdb->postmeta" );

Теперь получим данные о колонках таблицы этого запроса:

$cols_data = $wpdb->get_col_info( 'name' );
/*
Array
(
	[0] => meta_id
	[1] => post_id
	[2] => meta_key
	[3] => meta_value
)
*/

$cols_data = $wpdb->get_col_info( 'max_length' );
/*
Array
(
	[0] => 6
	[1] => 5
	[2] => 45
	[3] => 20205
)
*/

$cols_data = $wpdb->get_col_info( 'type' );
/*
Array
(
	[0] => 8
	[1] => 8
	[2] => 253
	[3] => 252
)
*/

Что будет если указать несуществующее имя колонки:

$cols_data = $wpdb->get_col_info( 'primary_key' );
/*
Notice: Undefined property: stdClass::$primary_key in /wpexample.com/public_html/wp-includes/wp-db.php on line 3435
Notice: Undefined property: stdClass::$primary_key in /wpexample.com/public_html/wp-includes/wp-db.php on line 3435
Notice: Undefined property: stdClass::$primary_key in /wpexample.com/public_html/wp-includes/wp-db.php on line 3435
Notice: Undefined property: stdClass::$primary_key in /wpexample.com/public_html/wp-includes/wp-db.php on line 3435

Array
(
	[0] =>
	[1] =>
	[2] =>
	[3] =>
)
*/

Чтобы получить данные отдельной колонки нужно указать её индекс во втором параметре:

echo $wpdb->get_col_info( 'name', 0 );       //> meta_id
echo $wpdb->get_col_info( 'name', 1 );       //> post_id
echo $wpdb->get_col_info( 'max_length', 0 ); //> 6
echo $wpdb->get_col_info( 'max_length', 1 ); //> 5

flush — сброс кэша

Можно сбросить последние сохраненные данные в свойствах класса:

$wpdb->flush();

Эта команда очистит следующие свойства (переменные): $wpdb->last_result, $wpdb->last_query и $wpdb->col_info.

Свойства (переменные) класса

$show_errors
Показывать ошибки или нет, когда возвращается результат.
По умолчанию: true (да)
$suppress_errors
Подавлять ли ошибки в процессе построения запроса.
$last_error
Последняя ошибка из любого запроса.
$num_queries
Количество запросов, которые выполняются.
$num_rows
Количество строк, возвращенных последним запросом.
$rows_affected
Сохраняет число задействованных строк из последнего запроса. Заполняется при следующих sql командах: create, alter, truncate, drop, insert, delete, update, replace — в остальных случаях заполняется свойство $num_rows.
$insert_id
Идентификатор (ID) сгенерированный последним запросом, для SQL параметра AUTO_INCREMENT
$last_query
Последний запрос, который был выполнен классом.
$last_result
Результат последнего запроса.
$func_call
Текстовое описание последнего вызова query/get_row/get_var
$queries
Можно сохранить все запросы которые были сделаны к БД и их время выполнения, для этого нужно определить константу SAVEQUERIES как TRUE (например в config.php). По умолчанию она выключена (false). После того как эта константа включена в эту переменную будут собираться все запросы в виде массива данных.
$col_info
Информация о колонках последнего запроса.
$prefix
Префикс таблиц БД определенный для WordPress. Может пригодиться для мульти-сайтов.
$base_prefix
Префикс базовой таблицы WordPress. В мультисайте для сайтов сети префик отличается. Тут хранится префикс таблиц основного сайта сети.
$ready
Логический. Готов ли класс к выполнению запросов.
$blogid
Идентификатор текущего блога.
$siteid
ID сайта.
$tables

Список названий таблиц, которые используются (копируются) для каждого подсайта сети сайтов. Название таблиц будет отличаться префиксом текущего блога. Названия без префикса по умолчанию:

var $tables = array(
	'posts',
	'comments',
	'links',
	'options',
	'postmeta',
	'terms',
	'term_taxonomy',
	'term_relationships',
	'termmeta',
	'commentmeta',
);
$global_tables

Глобальные таблицы. Не повторяются для подсайтов.

array( 'users', 'usermeta' );
$ms_global_tables

Глобальные таблицы в режиме MU.

var $ms_global_tables = array(
	'blogs',
	'blogmeta',
	'signups',
	'site',
	'sitemeta',
	'sitecategories',
	'registration_log',
);
$collate
Режим сопоставления (сравнивания) данных в колонках базы данных.
$dbh
PHP объект базы mysqli.

Build In Post

Схема базы данных WordPress — структура всех таблиц
Записи — подробнее здесь
$wpdb->posts
Таблица куда записываются посты, постоянные страницы, произвольные типы записей, вложения и т.п.
$wpdb->postmeta
Дополняет таблицу $wpdb->posts. Хранит дополнительные данные записей (постов) их еще называют метаполя.
Пользователи
$wpdb->users
Таблица с данными о зарегистрированных пользователях.
$wpdb->usermeta
Дополнительная информация о пользователях, такая как Имя, Ник, права и прочее.
Мета поля для таблицы $wpdb->users.
Комментарии
$wpdb->comments
Таблица с записями комментариев.
$wpdb->commentmeta
Мета поля для таблицы $wpdb->comments.
Таксономии — подробнее
$wpdb->terms
Таблица содержащая в себе базовую информацию каждом элементе таксономии.
$wpdb->termmeta
Таблица содержащая в себе дополнительные поля для таблицы $wpdb->terms.
$wpdb->term_taxonomy
Таблица с информацией о таксономиях, их описание.
$wpdb->term_relationships
Таблица связывающая таксономии с контентом (постами, записями и т.п.)
Остальные таблицы
$wpdb->links
Таблица с записями ссылок.
$wpdb->options
Таблица опций (настроек).

Таблицы Multisite сборки

$wpdb->blogs
Все сайты подсети.
$wpdb->blog_versions
Содержит текущую версию базы данных каждого сайта. Данные обновляются при обновлении БД для каждого сайта сети.
$wpdb->registration_log
Содержит данные администраторов сайтов, которые создаются при создании сайтов.
$wpdb->signups
Содержит пользователей, которые были зарегистрированы через базовую регистрацию WordPress со страницы: Администрация > Супер Админ > Настройки.
$wpdb->site
Содержит, адреса основных сайтов.
$wpdb->sitemeta
Данные сайтов: различные опции, включая администратора сайта.
$wpdb->users
Список пользователей всех сайтов сети. Это общая таблица пользователей для всей сети. Это привычная таблица, только в мультисайт версии добавляются еще 2 поля: spam и delete.
$wpdb->usermeta
Содержит мета-данные пользователей. Настройки пользователя для разных сайтов сети.
Базовые таблицы каждого сайта сети
Таблицы сайта сети: wp_posts, wp_options и т.д.. Для каждого сайта сети создаются одинаковые таблицы, но с разным префиксом, например: wp_options, wp_1_options, wp_2_options

Все методы класса

  1. public __construct( $dbuser, $dbpassword, $dbname, $dbhost )
  2. public __get( $name )
  3. public __isset( $name )
  4. public __set( $name, $value )
  5. public __unset( $name )
  6. private _do_query( $query )
  7. public _escape( $data )
  8. public _insert_replace_helper( $table, $data, $format = null, $type = ‘INSERT’ )
  9. public _real_escape( $string )
  10. public _weak_escape( $string )
  11. public add_placeholder_escape( $query )
  12. public bail( $message, $error_code = ‘500’ )
  13. protected check_ascii( $string )
  14. public check_connection( $allow_bail = true )
  15. public check_database_version()
  16. protected check_safe_collation( $query )
  17. public close()
  18. public db_connect( $allow_bail = true )
  19. public db_server_info()
  20. public db_version()
  21. public delete( $table, $where, $where_format = null )
  22. public determine_charset( $charset, $collate )
  23. public esc_like( $text )
  24. public escape( $data )
  25. public escape_by_ref( &$string )
  26. public flush()
  27. public get_blog_prefix( $blog_id = null )
  28. public get_caller()
  29. public get_charset_collate()
  30. public get_col( $query = null, $x = 0 )
  31. public get_col_charset( $table, $column )
  32. public get_col_info( $info_type = ‘name’, $col_offset = -1 )
  33. public get_col_length( $table, $column )
  34. public get_results( $query = null, $output = OBJECT )
  35. public get_row( $query = null, $output = OBJECT, $y = 0 )
  36. protected get_table_charset( $table )
  37. protected get_table_from_query( $query )
  38. public get_var( $query = null, $x = 0, $y = 0 )
  39. public has_cap( $db_cap )
  40. public hide_errors()
  41. public init_charset()
  42. public insert( $table, $data, $format = null )
  43. protected load_col_info()
  44. public log_query( $query, $query_time, $query_callstack, $query_start, $query_data )
  45. public parse_db_host( $host )
  46. public placeholder_escape()
  47. public prepare( $query, …$args )
  48. public print_error( $str = » )
  49. protected process_field_charsets( $data, $table )
  50. protected process_field_formats( $data, $format )
  51. protected process_field_lengths( $data, $table )
  52. protected process_fields( $table, $data, $format )
  53. public query( $query )
  54. public remove_placeholder_escape( $query )
  55. public replace( $table, $data, $format = null )
  56. public select( $db, $dbh = null )
  57. public set_blog_id( $blog_id, $network_id = 0 )
  58. public set_charset( $dbh, $charset = null, $collate = null )
  59. public set_prefix( $prefix, $set_table_names = true )
  60. public set_sql_mode( $modes = array() )
  61. public show_errors( $show = true )
  62. protected strip_invalid_text( $data )
  63. public strip_invalid_text_for_column( $table, $column, $value )
  64. protected strip_invalid_text_from_query( $query )
  65. public supports_collation()
  66. public suppress_errors( $suppress = true )
  67. public tables( $scope = ‘all’, $prefix = true, $blog_id = 0 )
  68. public timer_start()
  69. public timer_stop()
  70. public update( $table, $data, $where, $format = null, $where_format = null )

Show errors:

  • $wpdb->show_errors = true shows errors automatically, if WP_DEBUG is set to true.
  • $wpdb->suppress_errors = false stops suppressing errors.

  • Multisite need special treatment

    // Show errors in Multisite:
    global $wpdb, $blog_id;
    // There's no is_multisite(), so we need to check the ID
    // This means, that we can't debug the blog with the ID 1 as MU-blog by default
    // Check if we are on Blog ID#1 and if not, check the defines and add error handling
    if ( 1 !== $blog_id )
        ! defined( 'DIEONDBERROR' ) AND define( 'DIEONDBERROR', true );
    

Output handling

The $wpdb->update() method has three different outputs. To check against it, you must save the result i a var: $result = $wpdb->update( /* ... */ );.

The handle those scenarios:

  • false === $result: Fail
  • 0 === $result: Success, but no update
  • 0 < $result: Success

Class output

  • $wpdb->last_error will show you the last error, if you got one.
  • $wpdb->last_query will assist you with showing the last query (where the error occurred). It is basically the same as array_pop( $wpbd->queries );.

Important (security) Note

Please do NOT add this codes on live site. Especially not if caching plugins are involved. This may expose important DB-related data to visitors!

If you can’t do otherwise: always wrap your code in conditional statements to prevent public facing debug output!

// Example
function debug_query( $result, $data )
{
    global $current_user;
    get_currentuserinfo();

    if ( current_user_can( 'manage_options' ) )
    {
        global $wpdb, $blog_id;
        1 !== $blog_id
            AND ! defined( 'DIEONDBERROR' )
                AND define( 'DIEONDBERROR', true );

        $wpdb->show_errors     = true;
        $wpdb->suppress_errors = false;

        $output = '<pre style="white-space:pre-line;">';
            $output .= 'Last Error: ';
            $output .= var_export( $wpdb->last_error, true );

            $output .= "nnLast Query: ";
            $output .= var_export( $wpdb->last_query, true );

            if ( false === $result )
            {
                $result = new WP_Error( 'query_failed', 'No update.', $data );
            }
            elseif ( 0 === $result )
            {
                $result = new WP_Error( 'update_failed', 'Updated zero rows.', $data );
            }
            elseif ( 0 < $result )
            {
                $result = 'Success';
            }
        $output .= '</pre>';

        // Only abort, if we got an error
        is_wp_error( $result ) 
            AND exit( $output.$result->get_error_message() );
    }
}

Exposing the $wpdb object might also expose your database username and password!

В этой стстье речь пойдёт про класс wpdb. Через этот класс делаются все манипуляции с базой данных в WordPress: добавление, удаление, обновление и получение данных.

В большинстве CMS существуют классы для управления базой данных. Рекомендуем пользоваться именно ими, потому что в отличии от прямого обращения к базе, такие классы иногда содержат различную защиту, которая усложняет взлом сайта. Механизмы в этих классах являются дополнительной линией обороны на случай, если разработчик недостаточно очистит полученные от пользователя данные.

Обращение к методам класса «wpdb» всегда проходит через глобальную переменную «$wpdb». Если нужно воспользоваться этой переменной внутри функций, то необходимо её глобализировать там:

<?php
function MouseDC(){
   global $wpdb;
}

Методы класса «wpdb» позволяют управлять всеми таблицами в базе данных WordPress, а не только системными. Потому что существует возможность выполнить произвольный SQL запрос к любой таблице:

<?php
$food = $wpdb->get_results( "SELECT * FROM food" );

Каждый объект класса «wpdb» работает с одной базой данных. Если нужно подключить к другой базе данных, то нужно создать новый объект. Продемонстрируем это:

<?php
global $db;
$db = new wpdb( 'имя_пользователя', 'пароль', 'название_базы', 'ip_адрес_базы' );

if( ! empty($db->error) ) wp_die( $db->error ); // в случае ошибки соединения

$food = $db->get_results( "SELECT * FROM food" );

Методы класса «wpdb»

Разберём все методы класса «wpdb». Сначала перечислим их:

  • query — делает произвольный SQL запрос
  • get_var — возвращает значение ячейки таблицы
  • get_row — возвращает строку таблицы
  • get_col — возвращает столбец таблицы
  • get_col_info — получает информацию о столбце
  • get_results — возвращает несколько строк таблицы
  • insert — добавляет строку в таблицу
  • update — обновление строку в таблице
  • replace — заменяет строку в таблице
  • delete — удаляет строку из таблицы
  • prepare — очищает данные (от возможных SQL инъекций)
  • esc_like — очищает данные (части LIKE в SQL запросе)
  • show/hide/print_error — распечатывает ошибки SQL
  • flush — сбрасывает кеш

Выполнение запроса «query»

Метод «query» позволяет выполнять любой запрос к базе данных. Метод возвращает число: количество строк, которые были изменены или возвращены базой данных. Если запрос не выполнится, то вернётся «false».

$wpdb->query( 'query' );

У метода всего один аргумент — строка SQL запроса. Туда можно вставлять сырой SQL запрос. К примеру, запрос, который удалит публикацию с ID равным 5:

$wpdb->query( "DELETE FROM $wpdb->posts WHERE id = 5" );

Учтите, что при выполнении запроса лучше передавать в него уже очищенную SQL команду:

$sql = "DELETE FROM $wpdb->posts WHERE id = 5";
$wpdb->query( $wpdb->prepare( $sql ) );

Получение ячейки таблицы «get_var»

С помощью метода «get_var» можно получить значение ячейки в таблице. Результат можно получить в виде массива. Если результата нет, то вернётся «null» значение.

$wpdb->get_var( 'query', $column_offset, $row_offset );

Рассмотрим аргументы этого метода:

Название Тип данных Описание
‘query’ строка SQL запрос для выполнения
$column_offset число Порядковый номер колонки. Начиная с нуля.
$row_offset число Порядковый номер строки. Начиная с нуля.

Получение строки «get_row»

С помощью метода «get_row» можно получить одну строку из таблицы. Результат можно получить в виде объекта или массива. Если результата нет, то вернётся «null» значение.

$wpdb->get_row( 'query', $output_type, $row_offset );

Рассмотрим аргументы этого метода:

Название Тип данных Описание
‘query’ строка SQL запрос для выполнения
$output_type константа Формат возвращаемых данных. Возможные значения:

OBJECT — вернуть данные в объекте (по умолчанию)

ARRAY_A — вернуть данные в ассоциативном массиве

ARRAY_N — вернуть данные в массиве без ключей

$row_offset число Номер строки для получения (считая с нуля). По умолчанию ноль (первая строка).

Пример использования (получение данных публикаций с ID равным 5):

$wpdb->get_row( 'SELECT ID FROM $wpdb->posts WHERE ID = 5' );

Получение столбца «get_col»

С помощью метода «get_col» можно получить один столбец из таблицы. Результат можно получить в виде массива. Если результата нет, то вернётся «null» значение.

$wpdb->get_col( 'query', $column_offset );

Рассмотрим аргументы этого метода:

Название Тип данных Описание
‘query’ строка SQL запрос для выполнения
$column_offset число Номер столбца для получения (считая с нуля). По умолчанию ноль (первый столбец).

Пример использования (получение списка id ревизий публикаций):

$wpdb->get_col( "SELECT ID FROM $wpdb->posts WHERE post_type = 'revision'" );

Получение информации о столбце «get_col_info»

С помощью метода «get_col_info» можно получить информации о колонке из последнего запроса. Метод возвращает массив, описывающий колонки таблицы.

$wpdb->get_col_info( $type, $offset );

Рассмотрим аргументы этого метода:

Название Тип данных Описание
$type строка Какую именно информацию получать. Возможные значения:

table — название таблицы.

name — название колонки.

type — тип колонки

max_length — максимальная длинна данных колонки.

not_null — вернёт «1» если ячейка колонки не может принимать значение NULL

primary_key — вернёт «1» если колонка является первичным ключом

unique_key — вернёт «1» если значения должны быть уникальны

multiple_key — вернёт «1» если значения могут быть не уникальны

numeric — вернёт «1» если колонка содержит число

blob — вернёт «1» если колонка содержит данные типа BLOB

unsigned — вернёт «1» если колонка имеет тип данных UNSIGNED

zerofill — вернёт «1» если колонка имеет тип данных ZEROFILL

$offset число Номер столбца для получения (считая с нуля). По умолчанию ноль (первый столбец). Если указать «-1», то будет возвращена информация о всех колонках в виде массива.

Получение нескольких строк «get_results»

С помощью метода «get_results» можно получить несколько строку из таблицы. Результат можно получить в виде объекта или массива, элементами которого представляют собой результат выполнения метода «get_row». Если результата нет, то вернётся «null» значение.

$wpdb->get_results( 'query', $output_type );

Рассмотрим аргументы этого метода:

Название Тип данных Описание
‘query’ строка SQL запрос для выполнения
$output_type константа Формат возвращаемых данных. Возможные значения:

OBJECT — вернуть данные в объекте (по умолчанию)

ARRAY_A — вернуть данные в ассоциативном массиве

ARRAY_N — вернуть данные в массиве без ключей

Добавление данных «insert»

С помощью метода «insert» можно добавлять данные в таблицу. Метод использует защиту от SQL инъекций, поэтому запрос можно передавать в сыром виде. В результате добавления возвращается либо число вставленных строк, либо «false».

$wpdb->insert( $table, $data, $format );

Рассмотрим аргументы этого метода:

Название Тип данных Описание
$table строка Название таблицы, куда вставляются данные.
$data строка Данные, которые необходимо вставить.
$format строка Формат данных. Возможные значения:

%s — строка

%d — целое число

%f — дробное число

Пример использования (добавление данных типа «строка» и «число»):

$wpdb->insert(
   'название_таблицы',
   array( 'столбец1' => 'значение1', 'столбец2' => 5 ),
   array( '%s', '%d' )
);

Обновление данных «update»

С помощью метода «update» можно обновлять данные в таблице. Метод использует защиту от SQL инъекций, поэтому запрос можно передавать в сыром виде. В результате добавления возвращается либо число обновлённых строк, либо «false» при появлении ошибки. Если возвращён ноль «0», то не было обновлено ни одной строки.

$wpdb->update( $table, $data, $where, $format = null, $where_format = null );

Рассмотрим аргументы этого метода:

Название Тип данных Описание
$table строка Название таблицы, кде происходит обновление данных.
$data массив Данные, которые необходимо обновить (‘название_колонки’ => ‘значение’).
$where массив Массив с условием для замены WHERE (‘название_колонки’ => ‘значение’).
$format строка/массив Формат данных, который указан в аргументе $data.
$where_format строка/массив Формат данных, который указан в аргументе $where.

Пример использования (обновление данных типа «строка» и «число» в строке с ID равным 10):

$wpdb->update(
   'название_таблицы',
   array( 'столбец1' => 'значение1', 'столбец2' => 5 ),
   array( 'ID' => 10 ),
   array( '%s', '%d' )
   array( '%d' )
);

Замена данных «replace»

Метод «replace» обновляет данные, если они есть и добавляет их, если нет. Фактически, метод работает как «update» и «insert». Метод использует защиту от SQL инъекций, поэтому запрос можно передавать в сыром виде.

В результате работы возвращается:

  • Число «1», если была обновлена строка.
  • Число больше единицы, если были удалены строки перед вставкой новой.
  • Число ноль «0», если не было обновлено/добавлено ни одной строки.
  • Логическое «false» при появлении ошибки.
$wpdb->replace( $table, $data, $format = null );

Рассмотрим аргументы этого метода:

Название Тип данных Описание
$table строка Название таблицы, кде происходит обновление данных.
$data массив Данные, которые необходимо обновить (‘название_колонки’ => ‘значение’).
$format строка/массив Формат данных, который указан в аргументе $data.

Пример использования (обновление данных в столбцах «столбец1» и «столбец2» в строке с ID равным 10):

$wpdb->replace(
   'название_таблицы',
   array( 'ID' => 10, 'столбец1' => 'значение1', 'столбец2' => 5 )
);

Удаление строки «delete»

Метод «delete» позволяет удалить строку из таблицы. В результате работы возвращается количество удалённых строк (цифра).

$wpdb->delete( $table, $where, $where_format = null );

Рассмотрим аргументы этого метода:

Название Тип данных Описание
$table строка Название таблицы, кде происходит обновление данных.
$where массив Массив условий, по которому будут выбираться данные для удаления (‘название_колонки’ => ‘значение’).
$where_format строка/массив Формат данных, который указан в аргументе $where.

Пример использования (удаление строки с ID равным 10):

$wpdb->delete(
   'название_таблицы',
   array( 'ID' => 10 )
);

Оббезараживание SQL строки «prepare»

Метод «prepare» позволяет обеззаразить SQL команду. В метод передаётся SQL команда и параметры, которые необходимо вставть в неё (параметров может быть несколько). Возвращает обеззараженную SQL команду, которую можно далее использовать:

$wpdb->prepare( 'query' param1, param2... );

Рассмотрим аргументы этого метода:

Название Тип данных Описание
query строка SQL запрос, в котором принимаемые значения заменены на указатели типа данных:

%s — строка

%d — целое число

%f — дробное число

param1 строка/число/массив Переменная, которая будет использована в запросе.

Пример использования (очистка SQL запроса для получение записи с ID равным 5):

$sql = $wpdb->prepare(
   'SELECT * FROM table WHERE ID = %1$s', 
   '5' 
);

Оббезараживание данных для SQL через «esc_sql»

Функция «esc_sql» позволяет обеззаразить данные, которые использются для SQL команды. Он выполняет ту же функцию, что и метод «prepare», но используется только на переменных, возвращая их обеззараженное значение.

Пример использования (очистка SQL запроса для удаления записи с принимаемым в GET параметре ID):

$id = esc_sql( $_GET['id'] );
$wpdb->get_var( "DELETE FROM $wpdb->posts WHERE ID = '$id' " );

Очищенную строку использовать только в обрамлении кавычек » » или ‘ ‘ . То есть в нашем случае из примера необходимо ставить в запрос «$id» или ‘$id’.

Очистка LIKE части запроса «esc_like»

Метод «esc_like» позволяет очистить данные данные, которые использются для LIKE части запроса SQL команды.

Пример использования (очистка SQL запроса для получение записи с названием, принимаемым в GET параметре ‘name’):

$name = '%' . $wpdb->esc_like( $_GET['name'] ) . '%';
$wpdb->get_var( "SELECT * FROM $wpdb->posts WHERE post_name LIKE '$name' " );

Вывод ошибок «get_col_info»

С помощью метода «get_col_info» можно скрыть или показать ошибки, возникающие в просессе работы с классом «$wpdb»:

$wpdb->show_errors(); // включить показ ошибок
$wpdb->hide_errors(); // выключить показ ошибок
$wpdb->print_error(); // вывести последнюю ошибку

Сброс кеша «flush»

При выполнении запросов в свойствах объекта класса «wpdb» сохраняется кеш возвращённых значений. Его можно сбросить с помощью метода «flush»:

$wpdb->get_row( 'query', $output_type, $row_offset );

Грубо говоря, этот метод устанавливает следующие значения:

<?php
$wpdb->last_result = array();
$wpdb->col_info = null;
$wpdb->last_query = null;
$wpdb->rows_affected = 0;
$wpdb->num_rows = 0;
$wpdb->last_error = '';

Languages:
English
Italiano •

日本語
Русский •

中文(简体) •
中文(繁體) •
한국어 •
(Add your language)

Contents

  • 1 Talking to the Database: The wpdb Class
    • 1.1 Using the $wpdb Object
    • 1.2 A Warning
  • 2 SELECT a Variable
    • 2.1 Examples
  • 3 SELECT a Row
    • 3.1 Examples
  • 4 SELECT a Column
    • 4.1 Examples
  • 5 SELECT Generic Results
    • 5.1 Examples
  • 6 INSERT row
    • 6.1 Examples
  • 7 REPLACE row
    • 7.1 Examples
  • 8 UPDATE rows
    • 8.1 Examples
  • 9 DELETE Rows
    • 9.1 Usage
    • 9.2 Parameters
    • 9.3 Examples
  • 10 Running General Queries
    • 10.1 General Syntax
    • 10.2 Examples
  • 11 Protect Queries Against SQL Injection Attacks
    • 11.1 Placeholders
    • 11.2 Examples
  • 12 Show and Hide SQL Errors
  • 13 Getting Column Information
  • 14 Clearing the Cache
  • 15 Class Variables
    • 15.1 Multi-Site Variables
  • 16 Tables
    • 16.1 Multisite Tables
  • 17 Source File
  • 18 Related
    • 18.1 Articles
    • 18.2 Code Documentation

Talking to the Database: The wpdb Class

WordPress defines a class called wpdb, which contains a set of functions used to interact with a database. Its primary purpose is to provide an interface with the WordPress database, but can be used to communicate with any other appropriate database. The class source code is loosely based on the ezSQL class; written and maintained by Justin Vincent

Using the $wpdb Object

Warning: Methods in the wpdb() class should not be called directly. Use the global $wpdb object instead!

WordPress provides a global object variable, $wpdb, which is an instantiation of the wpdb class defined in /wp-includes/wp-db.php. By default, $wpdb is instantiated to talk to the WordPress database. To access $wpdb in your WordPress PHP code, declare $wpdb as a global variable using the global keyword, or use the superglobal $GLOBALS in the following manner:

// 1st Method - Declaring $wpdb as global and using it to execute an SQL query statement that returns a PHP object

global $wpdb;
$results = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}options WHERE option_id = 1", OBJECT );

// 2nd Method - Utilizing the $GLOBALS superglobal. Does not require global keyword ( but may not be best practice )

$results = $GLOBALS['wpdb']->get_results( "SELECT * FROM {$wpdb->prefix}options WHERE option_id = 1", OBJECT );


The $wpdb object is not limited to the default tables created by WordPress; it can be used to read data from any table in the WordPress database (such as custom plugin tables). For example to SELECT some information from a custom table called «mytable», you can do the following.

$myrows = $wpdb->get_results( "SELECT id, name FROM mytable" );


The $wpdb object can talk to any number of tables, but only to one database at a time; by default the WordPress database. In the rare case you need to connect to another database, you will need to instantiate your own object from the wpdb class with your own database connection information. For extremely complicated setups with many databases, consider using hyperdb instead.

A Warning

Some of the functions in this class take an SQL statement as input. You must SQL escape all untrusted values you incorporate into the SQL query to prevent SQL injection attacks. Check the documentation to see if the function you plan to use escapes SQL for you or expects it to be pre-escaped.

For more on SQL escaping in WordPress, see the section entitled Protect Queries Against SQL Injection Attacks below.

SELECT a Variable

The get_var function returns a single variable from the database. Though only one variable is returned, the entire result of the query is cached for later use. Returns NULL if no result is found.


 <?php $wpdb->get_var'query'column_offsetrow_offset ); ?> 

query 
(string) The query you wish to run. Setting this parameter to null will return the specified variable from the cached results of the previous query.
column_offset 
(integer) The desired column (0 being the first). Defaults to 0.
row_offset 
(integer) The desired row (0 being the first). Defaults to 0.

Examples

Retrieve and display the number of users.

<?php
$user_count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->users" );
echo "<p>User count is {$user_count}</p>";
?>

Retrieve and display the sum of a Custom Field value.

<?php
// set the meta_key to the appropriate custom field meta key
$meta_key = 'miles';
$allmiles = $wpdb->get_var( $wpdb->prepare( 
	"
		SELECT sum(meta_value) 
		FROM $wpdb->postmeta 
		WHERE meta_key = %s
	", 
	$meta_key
) );
echo "<p>Total miles is {$allmiles}</p>";
?> 

SELECT a Row

To retrieve an entire row from a query, use get_row. The function can return the row as an object, an associative array, or as a numerically indexed array. If more than one row is returned by the query, only the specified row is returned by the function, but all rows are cached for later use. Returns NULL if no result is found, consider this when using the returned value in arguments, see example below.


 <?php $wpdb->get_row('query'output_typerow_offset); ?> 

query 
(string) The query you wish to run.
output_type 
One of three pre-defined constants. Defaults to OBJECT.

  • OBJECT — result will be output as an object.
  • ARRAY_A — result will be output as an associative array.
  • ARRAY_N — result will be output as a numerically indexed array.
row_offset 
(integer) The desired row (0 being the first). Defaults to 0.

Examples

Get all the information about Link 10.

$mylink = $wpdb->get_row( "SELECT * FROM $wpdb->links WHERE link_id = 10" );

The properties of the $mylink object are the column names of the result from the SQL query (in this example all the columns from the $wpdb->links table, but you could also query for specific columns only).

echo $mylink->link_id; // prints "10"

In contrast, using

$mylink = $wpdb->get_row( "SELECT * FROM $wpdb->links WHERE link_id = 10", ARRAY_A );

would result in an associative array:

echo $mylink['link_id']; // prints "10"

and

$mylink = $wpdb->get_row( "SELECT * FROM $wpdb->links WHERE link_id = 10", ARRAY_N );

would result in a numerically indexed array:

echo $mylink[1]; // prints "10"

If there is no record with ID 10 in the links table, null will be returned. The following would then be false:

if ( null !== $mylink ) {
  // do something with the link 
  return true;
} else {
  // no link found
  return false;
}

SELECT a Column

To SELECT a column, use get_col. This function outputs a one dimensional array. If more than one column is returned by the query, only the specified column will be returned by the function, but the entire result is cached for later use. Returns an empty array if no result is found.


 <?php $wpdb->get_col'query'column_offset ); ?> 

query 
(string) the query you wish to execute. Setting this parameter to null will return the specified column from the cached results of the previous query.
column_offset 
(integer) The desired column (0 being the first). Defaults to 0.

Examples

For this example, assume the blog is devoted to information about automobiles. Each post describes a particular car (e.g. 1969 Ford Mustang), and three Custom Fields, manufacturer, model, and year, are assigned to each post. This example will display the post titles, filtered by a particular manufacturer (Ford), and sorted by model and year.

The get_col form of the wpdb Class is used to return an array of all the post ids meeting the criteria and sorted in the correct order. Then a foreach construct is used to iterate through that array of post ids, displaying the title of each post. Note that the SQL for this example was created by Andomar.

<?php 
$meta_key1		= 'model';
$meta_key2		= 'year';
$meta_key3		= 'manufacturer';
$meta_key3_value	= 'Ford';

$postids=$wpdb->get_col( $wpdb->prepare( 
	"
	SELECT      key3.post_id
	FROM        $wpdb->postmeta key3
	INNER JOIN  $wpdb->postmeta key1 
	            ON key1.post_id = key3.post_id
	            AND key1.meta_key = %s 
	INNER JOIN  $wpdb->postmeta key2
	            ON key2.post_id = key3.post_id
	            AND key2.meta_key = %s
	WHERE       key3.meta_key = %s 
	            AND key3.meta_value = %s
	ORDER BY    key1.meta_value, key2.meta_value
	",
	$meta_key1, 
	$meta_key2, 
	$meta_key3, 
	$meta_key3_value
) ); 

if ( $postids ) 
{
	echo "List of {$meta_key3_value}(s), sorted by {$meta_key1}, {$meta_key2}";
	foreach ( $postids as $id ) 
	{ 
		$post = get_post( intval( $id ) );
		setup_postdata( $post );
		?>
		<p>
			<a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>">
				<?php the_title(); ?>
			</a>
		</p>
		<?php
	} 
}
?>

This example lists all posts that contain a particular custom field, but sorted by the value of a second custom field.

<?php
// List all posts with custom field Color, sorted by the value of custom field Display_Order
// does not exclude any 'post_type'
// assumes each post has just one custom field for Color, and one for Display_Order
$meta_key1 = 'Color';
$meta_key2 = 'Display_Order';

$postids = $wpdb->get_col( $wpdb->prepare( 
	"
	SELECT      key1.post_id
	FROM        $wpdb->postmeta key1
	INNER JOIN  $wpdb->postmeta key2
	            ON key2.post_id = key1.post_id
	            AND key2.meta_key = %s
	WHERE       key1.meta_key = %s
	ORDER BY    key2.meta_value+(0) ASC
	",
        $meta_key2,
	$meta_key1
) ); 

if ( $postids ) 
{
	echo "List of {$meta_key1} posts, sorted by {$meta_key2}";
	foreach ( $postids as $id ) 
	{
		$post = get_post( intval( $id ) );
		setup_postdata( $post );
		?>
		<p>
			<a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>">
				<?php the_title(); ?>
			</a>
		</p>
		<?php
	}
}
?>

SELECT Generic Results

Generic, multiple row results can be pulled from the database with get_results. The function returns the entire query result as an array. Each element of this array corresponds to one row of the query result and, like get_row, can be an object, an associative array, or a numbered array. If no matching rows are found, or if there is a database error, the return value will be an empty array. If your $query string is empty, or you pass an invalid $output_type, NULL will be returned.


 <?php $wpdb->get_results'query'output_type ); ?> 

query 
(string) The query you wish to run.
output_type 
One of four pre-defined constants. Defaults to OBJECT. See SELECT a Row and its examples for more information.

  • OBJECT — result will be output as a numerically indexed array of row objects.
  • OBJECT_K — result will be output as an associative array of row objects, using first column’s values as keys (duplicates will be discarded).
  • ARRAY_A — result will be output as a numerically indexed array of associative arrays, using column names as keys.
  • ARRAY_N — result will be output as a numerically indexed array of numerically indexed arrays.

Since this function uses the $wpdb->query() function all the class variables are properly set.
The results count for a ‘SELECT’ query will be stored in $wpdb->num_rows.

Examples

Get the IDs and Titles of all the Drafts by User 5 and echo the Titles.

$fivesdrafts = $wpdb->get_results( 
	"
	SELECT ID, post_title 
	FROM $wpdb->posts
	WHERE post_status = 'draft' 
		AND post_author = 5
	"
);

foreach ( $fivesdrafts as $fivesdraft ) 
{
	echo $fivesdraft->post_title;
}

Get all information on the Drafts by User 5.

<?php
$fivesdrafts = $wpdb->get_results( 
	"
	SELECT * 
	FROM $wpdb->posts
	WHERE post_status = 'draft' 
		AND post_author = 5
	"
);

if ( $fivesdrafts )
{
	foreach ( $fivesdrafts as $post )
	{
		setup_postdata( $post );
		?>
		<h2>
			<a href="<?php the_permalink(); ?>" rel="bookmark" title="Permalink: <?php the_title(); ?>">
				<?php the_title(); ?>
			</a>
		</h2>
		<?php
	}	
}
else
{
	?>
	<h2>Not Found</h2>
	<?php
}
?>

INSERT row

Insert a row into a table.


 <?php $wpdb->insert$table$data$format ); ?> 

table 
(string) The name of the table to insert data into.
data 
(array) Data to insert (in column => value pairs). Both $data columns and $data values should be «raw» (neither should be SQL escaped).
format 
(array|string) (optional) An array of formats to be mapped to each of the values in $data. If string, that format will be used for all of the values in $data. If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.

Possible format values: %s as string; %d as integer (whole number); and %f as float. (See below for more information.)

After insert, the ID generated for the AUTO_INCREMENT column can be accessed with:

$wpdb->insert_id

This function returns false if the row could not be inserted. Otherwise, it returns the number of affected rows (which will always be 1).

Please note: The value portion of the data parameter’s column=>value pairs must be scalar. If you pass an array (or object) as a value to be inserted you will generate a warning similar to «mysql_real_escape_string() expects parameter 1 to be string, array given on line 880 in file /var/www/html/wp-includes/wp-db.php».

Examples

Insert two columns in a row, the first value being a string and the second a number:

$wpdb->insert( 
	'table', 
	array( 
		'column1' => 'value1', 
		'column2' => 123 
	), 
	array( 
		'%s', 
		'%d' 
	) 
);

REPLACE row

Replace a row in a table if it exists or insert a new row in a table if the row did not already exist.


 <?php $wpdb->replace$table$data$format ); ?> 

table 
(string) The name of the table to replace data in.
data 
(array) Data to replace (in column => value pairs). Both $data columns and $data values should be «raw» (neither should be SQL escaped).
format 
(array|string) (optional) An array of formats to be mapped to each of the value in $data. If string, that format will be used for all of the values in $data. If omitted, all values in $data will be treated as strings unless otherwise specified in wpdb::$field_types.

Possible format values: %s as string; %d as integer (whole number); and %f as float. (See below for more information.)

If the length of a string element in the $data array parameter is longer that the defined length in the MySql database table, the insert will fail, this function will return false, but $wpdb->last_error will not be set to a descriptive message. You must ensure the data you wish to insert
will fit in the database — do not assume the MySql will truncate the data.

After replace, the ID generated for the AUTO_INCREMENT column can be accessed with:

$wpdb->insert_id

This function returns a count to indicate the number of rows affected. This is the sum of the rows deleted and inserted. If the count is 1 for a single-row REPLACE, a row was inserted and no rows were deleted. If the count is greater than 1, one or more old rows were deleted before the new row was inserted. It is possible for a single row to replace more than one old row if the table contains multiple unique indexes and the new row duplicates values for different old rows in different unique indexes.

This function returns false if an existing row could not be replaced and a new row could not be inserted.

Examples

Replace a row, the first value being the row id, the second a string and the third a number:

$wpdb->replace( 
	'table', 
	array( 
                'indexed_id' => 1,
		'column1' => 'value1', 
		'column2' => 123 
	), 
	array( 
                '%d',
		'%s', 
		'%d' 
	) 
);

UPDATE rows

Update a row in the table. Returns false if errors, or the number of rows affected if successful.


 <?php $wpdb->update$table$data$where$format null$where_format null ); ?> 

table 
(string) The name of the table to update.
data 
(array) Data to update (in column => value pairs). Both $data columns and $data values should be «raw» (neither should be SQL escaped). This means that if you are using GET or POST data you may need to use stripslashes() to avoid slashes ending up in the database.
where 
(array) A named array of WHERE clauses (in column => value pairs). Multiple clauses will be joined with ANDs. Both $where columns and $where values should be «raw».
format 
(array|string) (optional) An array of formats to be mapped to each of the values in $data. If string, that format will be used for all of the values in $data.
where_format 
(array|string) (optional) An array of formats to be mapped to each of the values in $where. If string, that format will be used for all of the items in $where.

Possible format values: %s as string; %d as integer (whole number) and %f as float. (See below for more information.) If omitted, all values in $where will be treated as strings.

Return values: This function returns the number of rows updated, or false if there is an error. Keep in mind that if the $data matches what is already in the database, no rows will be updated, so 0 will be returned. Because of this, you should probably check the return with false === $result

Examples

Update a row, where the ID is 1, the value in the first column is a string and the value in the second column is a number:

$wpdb->update( 
	'table', 
	array( 
		'column1' => 'value1',	// string
		'column2' => 'value2'	// integer (number) 
	), 
	array( 'ID' => 1 ), 
	array( 
		'%s',	// value1
		'%d'	// value2
	), 
	array( '%d' ) 
);

Attention: %d can’t deal with comma values — if you’re not using full numbers, use string/%s.

DELETE Rows

The delete function was added in WordPress 3.4.0, and can be used to delete rows from a table. The usage is very similar to update and insert. It returns the number of rows updated, or false on error.

Usage


<?php $wpdb->delete$table$where$where_format null ); ?>

Parameters

$table
(string) (required) Table name.

Default: None
$where
(array) (required) A named array of WHERE clauses (in column -> value pairs). Multiple clauses will be joined with ANDs. Both $where columns and $where values should be ‘raw’.

Default: None
$where_format
(string/array) (optional) An array of formats to be mapped to each of the values in $where. If a string, that format will be used for all of the items in $where. A format is one of ‘%d’, ‘%f’, ‘%s’ (integer, float, string; see below for more information). If omitted, all values in $where will be treated as strings unless otherwise specified in wpdb::$field_types.

Default: null

Examples

// Default usage.
$wpdb->delete( 'table', array( 'ID' => 1 ) );

// Using where formatting.
$wpdb->delete( 'table', array( 'ID' => 1 ), array( '%d' ) );

Running General Queries

The query function allows you to execute any SQL query on the WordPress database. It is best used when there is a need for specific, custom, or otherwise complex SQL queries. For more basic queries, such as selecting information from a table, see the other wpdb functions above such as get_results, get_var, get_row or get_col.

General Syntax


 <?php $wpdb->query('query'); ?> 

query 
(string) The SQL query you wish to execute.

This function returns an integer value indicating the number of rows affected/selected for SELECT, INSERT, DELETE, UPDATE, etc. For CREATE, ALTER, TRUNCATE and DROP SQL statements, (which affect whole tables instead of specific rows) this function returns TRUE on success. If a MySQL error is encountered, the function will return FALSE. Note that since both 0 and FALSE may be returned for row queries, you should be careful when checking the return value. Use the identity operator (===) to check for errors (e.g., false === $result), and whether any rows were affected (e.g., 0 === $result).

Examples

Delete the ‘gargle’ meta key and value from Post 13. (We’ll add the ‘prepare’ method to make sure we’re not dealing with an illegal operation or any illegal characters):

$wpdb->query( 
	$wpdb->prepare( 
		"
                DELETE FROM $wpdb->postmeta
		 WHERE post_id = %d
		 AND meta_key = %s
		",
	        13, 'gargle' 
        )
);

Performed in WordPress by delete_post_meta().

Set the parent of Page 15 to Page 7.

$wpdb->query( $wpdb->prepare( 
	"
	UPDATE $wpdb->posts 
	SET post_parent = %d
	WHERE ID = %d
		AND post_status = %s
	",
        7, 15, 'static'
) );

Protect Queries Against SQL Injection Attacks

For a more complete overview of SQL escaping in WordPress, see database Data Validation. It is a must-read for all WordPress code contributors and plugin authors.

All data in SQL queries must be SQL-escaped before the SQL query is executed to prevent against SQL injection attacks. The prepare method performs this functionality for WordPress, which supports both a sprintf()-like and vsprintf()-like syntax.

Please note: As of 3.5, wpdb::prepare() enforces a minimum of 2 arguments. [more info]


 <?php $sql $wpdb->prepare'query' value_parameter[, value_parameter ... ] ); ?> 

query 
(string) The SQL query you wish to execute, with placeholders (see below).
value_parameter 
(int|string|array) The value to substitute into the placeholder. Many values may be passed by simply passing more arguments in a sprintf()-like fashion. Alternatively the second argument can be an array containing the values as in PHP’s vsprintf() function. Care must be taken not to allow direct user input to this parameter, which would enable array manipulation of any query with multiple placeholders. Values cannot be SQL-escaped.

Placeholders

The query parameter for prepare accepts sprintf()-like placeholders. The %s (string), %d (integer) and %f (float) formats are supported. (The %s and %d placeholders have been available since the function was added to core in Version 2.3, %f has only been available since Version 3.3.) Any other % characters may cause parsing errors unless they are escaped. All % characters inside SQL string literals, including LIKE wildcards, must be double-% escaped as %%. All of %d, %f, and %s are to be left unquoted in the query string. Note that the %d placeholder only accepts integers, so you can’t pass numbers that have comma values via %d. If you need comma values, use %f as float instead.

Examples

Add Meta key => value pair «Harriet’s Adages» => «WordPress’ database interface is like Sunday Morning: Easy.» to Post 10.

$metakey	= "Harriet's Adages";
$metavalue	= "WordPress' database interface is like Sunday Morning: Easy.";

$wpdb->query( $wpdb->prepare( 
	"
		INSERT INTO $wpdb->postmeta
		( post_id, meta_key, meta_value )
		VALUES ( %d, %s, %s )
	", 
        10, 
	$metakey, 
	$metavalue 
) );

Performed in WordPress by add_meta().

The same query using vsprintf()-like syntax.

$metakey = "Harriet's Adages";
$metavalue = "WordPress' database interface is like Sunday Morning: Easy.";

$wpdb->query( $wpdb->prepare( 
	"
		INSERT INTO $wpdb->postmeta
		( post_id, meta_key, meta_value )
		VALUES ( %d, %s, %s )
	", 
        array(
		10, 
		$metakey, 
		$metavalue
	) 
) );

Note that in this example we pack the values together in an array. This can be useful when we don’t know the number of arguments we need to pass until runtime.

Notice that you do not have to worry about quoting strings. Instead of passing the variables directly into the SQL query, use a %s placeholder for strings, a %d placedolder for integers, and a %f as a placeholder for floats. You can pass as many values as you like, each as a new parameter in the prepare() method.

Show and Hide SQL Errors

You can turn error echoing on and off with the show_errors and hide_errors, respectively.


 <?php $wpdb->show_errors(); ?> 
 <?php $wpdb->hide_errors(); ?> 

You can also print the error (if any) generated by the most recent query with print_error.


 <?php $wpdb->print_error(); ?> 

Note: If you are running WordPress Multisite, you must define the DIEONDBERROR constant for database errors to display like so:


 <?php define'DIEONDBERROR'true ); ?> 

Getting Column Information

You can retrieve information about the columns of the most recent query result with get_col_info. This can be useful when a function has returned an OBJECT whose properties you don’t know. The function will output the desired information from the specified column, or an array with information on all columns from the query result if no column is specified.


 <?php $wpdb->get_col_info('type'offset); ?> 

type 
(string) What information you wish to retrieve. May take on any of the following values (list taken from the ezSQL docs). Defaults to name.

  • name — column name. Default.
  • table — name of the table the column belongs to
  • max_length — maximum length of the column
  • not_null — 1 if the column cannot be NULL
  • primary_key — 1 if the column is a primary key
  • unique_key — 1 if the column is a unique key
  • multiple_key — 1 if the column is a non-unique key
  • numeric — 1 if the column is numeric
  • blob — 1 if the column is a BLOB
  • type — the type of the column
  • unsigned — 1 if the column is unsigned
  • zerofill — 1 if the column is zero-filled
offset 
(integer) Specify the column from which to retrieve information (with 0 being the first column). Defaults to -1.

  • -1 — Retrieve information from all columns. Output as array. Default.
  • Non-negative integer — Retrieve information from specified column (0 being the first).

Clearing the Cache

You can clear the SQL result cache with flush.


 <?php $wpdb->flush(); ?> 

This clears $wpdb->last_result, $wpdb->last_query, and $wpdb->col_info.

Class Variables

$show_errors 
Whether or not Error echoing is turned on. Defaults to TRUE.
$num_queries 
The number of queries that have been executed.
$last_query 
The most recent query to have been executed.
$last_error 
The most recent error text generated by MySQL.
$queries 
You may save all of the queries run on the database and their stop times by setting the SAVEQUERIES constant to TRUE (this constant defaults to FALSE). If SAVEQUERIES is TRUE, your queries will be stored in this variable as an array.
$last_result 
The most recent query results.
$col_info 
The column information for the most recent query results. See Getting Column Information.
$insert_id 
ID generated for an AUTO_INCREMENT column by the most recent INSERT query.
$num_rows 
The number of rows returned by the last query.
$prefix 
The assigned WordPress table prefix for the site.
$base_prefix 
The original prefix as defined in wp-config.php. For multi-site: Use if you want to get the prefix without the blog number appended.

Multi-Site Variables

If you are using Multi-Site, you also have access to the following:

$blogid 
The id of the current site (blog).
$siteid 
The id of the current network (formerly «site»). WordPress currently only supports one network per multi-site install, but that could change in future. See the following for more information:
  • WordPress: difference between site_id and blog_id?
  • http://stackoverflow.com/a/4189358/1924128 — Another good answer to the same question.

Tables

The WordPress database tables are easily referenced in the wpdb class.

$posts 
The table of Posts.
$postmeta 
The Meta Content (a.k.a. Custom Fields) table.
$comments 
The Comments table.
$commentmeta 
The table contains additional comment information.
$termmeta 
The termmeta table contains the term meta values.
$terms 
The terms table contains the ‘description’ of Categories, Link Categories, Tags.
$term_taxonomy 
The term_taxonomy table describes the various taxonomies (classes of terms). Categories, Link Categories, and Tags are taxonomies.
$term_relationships 
The term relationships table contains link between the term and the object that uses that term, meaning this file point to each Category used for each Post.
$users 
The table of Users.
$usermeta 
The usermeta table contains additional user information, such as nicknames, descriptions and permissions.
$links 
The table of Links.
$options 
The Options table.

Multisite Tables

These tables are used only in multisite installations.

$blogs 
The Blogs table contains a list of the separate blogs (sites) that have been set up within the network(s).
$signups 
The Signups table.
$site 
The Site table contains a list of the networks (previously known as «sites» in WPMU) that are set up in the installation (usually there is only one site listed in this table).
$sitemeta 
The Network Options (Site Meta) table contains any options that are applicable to the entire multisite installation.
$sitecategories 
The Site Categories table.
$registration_log 
The Registration Log table.
$blog_versions 
The Blog Versions table.

Source File

wpdb() is located in wp-includes/wp-db.php.

  • Member Function: wpdb::esc_like() — Escape LIKE statements before use in SQL.

Articles

  • Article: The Loop — A basic overview of its use of query within the WordPress loop.
  • Article: Query Overview — Explanation of how to determine which queries generate WordPress.
  • Article: Customizing Queries via Hook
  • Article: View Articles MYSQL query using custom
  • Article: Build advanced queries on Taxonomies
  • Article: Build custom query using Offset and pagination

Code Documentation

  • Class: WP_Query — Detailed Overview of class WP_Query
  • Class: WP_Comment_Query — Class for comment-related queries
  • Class: WP_User_Query — Class for user-related queries
  • Object: $wpdb — Overview on the use of the $wpdb object
  • Function: set_query_var()
  • Function: get_query_var()
  • Function: query_posts() — Create additional custom query
  • Function: get_post() — Take an ID of an item and return the records in the database for that article
  • Function: get_posts() — A specialized function that returns an array of items
  • Function: get_pages() — A specialized function that returns an array of pages
  • Function: have_posts() — A condition that determines whether the query returned an article
  • Function: the_post() — Used to automatically set the loop after a query
  • Function: rewind_posts() — Clears the current loop
  • Function: setup_postdata() — Sets the data for a single query result within a loop
  • Function: wp_reset_postdata() — Restores the previous query (usually after a loop within another loop)
  • Function: wp_reset_query()
  • Function: is_main_query() — Ensures that the query that is being changed is only the main query
  • Action Hook: pre_get_posts — Change WordPress queries before they are executed
  • Action Hook: the_post — Modify the post object after query
  • Filter Hook: found_posts — Changes the value of the object found_posts WP_Query

Я использую $wpdb->updateдля обновления пользовательской таблицы в моей базе данных. Когда я var_dumpвозвращаю результат:

int(0)

Поэтому я попытался $wpdb->print_error()понять, что не так. Однако это ничего не показывает. Я тоже пытался $wpdb->show_errors(), но опять ничего не показывало.

Документы wpdb не содержат подробностей о том, как использовать эти функции, поэтому я не уверен, правильно ли я их использую. Но почему в результате обновления таблицы возвращается 0, а ошибки не отображаются?

Ответы:


Я бы порекомендовал запустить следующий код сразу после вашего запроса, чтобы увидеть, что происходит:

exit( var_dump( $wpdb->last_query ) );

Это должно напечатать последний запрос, который попал в вашу базу данных. В таких случаях я обычно вручную запускаю такой запрос через phpMyAdmin, чтобы посмотреть, выполняется ли он без ошибок, и посмотреть, влияет ли он вообще на базу данных. Кроме того, увидев фактически выполненный запрос, вы можете обнаружить проблемы в запросе, который возникает из вашего кода. Например, запрос может не возвращать никаких ошибок MySQL, но он может выполнить запрос, отличный от ожидаемого. С помощью этого кода отладки вы, по крайней мере, сможете увидеть, что это такое, и продолжить замечательный путь отладки! Кроме того, вы можете захотеть изучить больше «Переменных классов» ( Кодекс ), $wpdbпоскольку они могут помочь в дальнейшем устранении вашей проблемы.




Показать ошибки:

  • $wpdb->show_errors = trueпоказывает ошибки автоматически, если WP_DEBUGустановлено значение true.
  • $wpdb->suppress_errors = false перестает подавлять ошибки.

  • Мультисайт нуждается в особом уходе

    // Show errors in Multisite:
    global $wpdb, $blog_id;
    // There's no is_multisite(), so we need to check the ID
    // This means, that we can't debug the blog with the ID 1 as MU-blog by default
    // Check if we are on Blog ID#1 and if not, check the defines and add error handling
    if ( 1 !== $blog_id )
        ! defined( 'DIEONDBERROR' ) AND define( 'DIEONDBERROR', true );

Обработка вывода

$wpdb->update()Метод имеет три различных выходов. Для того, чтобы проверить против него, вы должны сохранить результат ıA вар: $result = $wpdb->update( /* ... */ );.

Обрабатывать эти сценарии:

  • false === $result: Провал
  • 0 === $result: Успех, но без обновления
  • 0 < $result: Успех

Выход класса

  • $wpdb->last_error покажет вам последнюю ошибку, если вы ее получили.
  • $wpdb->last_queryпоможет вам с отображением последнего запроса (где произошла ошибка). Это в основном так же, как array_pop( $wpbd->queries );.

Важное (безопасность) Примечание

Пожалуйста, НЕ добавляйте эти коды на сайт. Особенно, если кеш-плагины задействованы. Это может предоставить важные данные, связанные с БД, посетителям !

Если вы не можете поступить иначе: всегда оборачивайте свой код в условные операторы, чтобы предотвратить публичный вывод отладочной информации!

// Example
function debug_query( $result, $data )
{
    global $current_user;
    get_currentuserinfo();

    if ( current_user_can( 'manage_options' ) )
    {
        global $wpdb, $blog_id;
        1 !== $blog_id
            AND ! defined( 'DIEONDBERROR' )
                AND define( 'DIEONDBERROR', true );

        $wpdb->show_errors     = true;
        $wpdb->suppress_errors = false;

        $output = '<pre style="white-space:pre-line;">';
            $output .= 'Last Error: ';
            $output .= var_export( $wpdb->last_error, true );

            $output .= "nnLast Query: ";
            $output .= var_export( $wpdb->last_query, true );

            if ( false === $result )
            {
                $result = new WP_Error( 'query_failed', 'No update.', $data );
            }
            elseif ( 0 === $result )
            {
                $result = new WP_Error( 'update_failed', 'Updated zero rows.', $data );
            }
            elseif ( 0 < $result )
            {
                $result = 'Success';
            }
        $output .= '</pre>';

        // Only abort, if we got an error
        is_wp_error( $result ) 
            AND exit( $output.$result->get_error_message() );
    }
}

Экспонирование $wpdbобъекта может также раскрыть имя пользователя и пароль вашей базы данных!




Нулевой ответ означает, что затронуто ноль строк, что отличается от ошибки.

Трудно сказать, не глядя на ваш запрос, почему ни одна строка не обновляется. Один из инструментов отладки, который вы можете попробовать — установить значение » SAVEQUERIES» в true в вашем файле wp-config.php.

Затем, после выполнения запроса, попробуйте var_dumping $wpdb->queries.


$wpdb->show_errors();
$wpdb->print_error();


Попробуйте это перед вашим запросом:

$wpdb->show_errors = TRUE;
$wpdb->suppress_errors = FALSE;

или, возможно, это после вашего запроса:

if ($wpdb->last_error) {
  die('error=' . var_dump($wpdb->last_query) . ',' . var_dump($wpdb->error));
}

Понравилась статья? Поделить с друзьями:
  • Wp ошибка error establishing a database connection
  • Wp send json error
  • Wp login php internal server error
  • Wp login php error 500
  • Wp http error curl error 28 connection timed out after 10000 milliseconds