: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
$tables = $wpdb->tables( 'global' );
// sitecategories may not exist.
if ( ! $wpdb->get_var( "SHOW TABLES LIKE '{$tables['sitecategories']}'" ) ) {
unset( $tables['sitecategories'] );
foreach ( $tables as $table ) {
maybe_convert_table_to_utf8mb4( $table );
if ( $wp_current_db_version < 33055 && 'utf8mb4' === $wpdb->charset ) {
if ( wp_should_upgrade_global_tables() ) {
$indexes = $wpdb->get_results( "SHOW INDEXES FROM $wpdb->signups" );
foreach ( $indexes as $index ) {
if ( 'domain_path' === $index->Key_name && 'domain' === $index->Column_name && 140 != $index->Sub_part ) {
$wpdb->query( "ALTER TABLE $wpdb->signups DROP INDEX domain_path, ADD INDEX domain_path(domain(140),path(51))" );
$tables = $wpdb->tables( 'global' );
// sitecategories may not exist.
if ( ! $wpdb->get_var( "SHOW TABLES LIKE '{$tables['sitecategories']}'" ) ) {
unset( $tables['sitecategories'] );
foreach ( $tables as $table ) {
maybe_convert_table_to_utf8mb4( $table );
if ( $wp_current_db_version < 44467 ) {
$network_id = get_main_network_id();
delete_network_option( $network_id, 'site_meta_supported' );
is_site_meta_supported();
// General functions we use to actually do stuff.
* Creates a table in the database, if it doesn't already exist.
* This method checks for an existing database table and creates a new one if it's not
* already present. It doesn't rely on MySQL's "IF NOT EXISTS" statement, but chooses
* to query all tables first and then run the SQL statement creating the table.
* @global wpdb $wpdb WordPress database abstraction object.
* @param string $table_name Database table name.
* @param string $create_ddl SQL statement to create table.
* @return bool True on success or if the table already exists. False on failure.
function maybe_create_table( $table_name, $create_ddl ) {
$query = $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $table_name ) );
if ( $wpdb->get_var( $query ) === $table_name ) {
// Didn't find it, so try to create it.
$wpdb->query( $create_ddl );
// We cannot directly tell that whether this succeeded!
if ( $wpdb->get_var( $query ) === $table_name ) {
* Drops a specified index from a table.
* @global wpdb $wpdb WordPress database abstraction object.
* @param string $table Database table name.
* @param string $index Index name to drop.
* @return true True, when finished.
function drop_index( $table, $index ) {
$wpdb->query( "ALTER TABLE `$table` DROP INDEX `$index`" );
// Now we need to take out all the extra ones we may have created.
for ( $i = 0; $i < 25; $i++ ) {
$wpdb->query( "ALTER TABLE `$table` DROP INDEX `{$index}_$i`" );
* Adds an index to a specified table.
* @global wpdb $wpdb WordPress database abstraction object.
* @param string $table Database table name.
* @param string $index Database table index column.
* @return true True, when done with execution.
function add_clean_index( $table, $index ) {
drop_index( $table, $index );
$wpdb->query( "ALTER TABLE `$table` ADD INDEX ( `$index` )" );
* Adds column to a database table, if it doesn't already exist.
* @global wpdb $wpdb WordPress database abstraction object.
* @param string $table_name Database table name.
* @param string $column_name Table column name.
* @param string $create_ddl SQL statement to add column.
* @return bool True on success or if the column already exists. False on failure.
function maybe_add_column( $table_name, $column_name, $create_ddl ) {
foreach ( $wpdb->get_col( "DESC $table_name", 0 ) as $column ) {
if ( $column === $column_name ) {
// Didn't find it, so try to create it.
$wpdb->query( $create_ddl );
// We cannot directly tell that whether this succeeded!
foreach ( $wpdb->get_col( "DESC $table_name", 0 ) as $column ) {
if ( $column === $column_name ) {
* If a table only contains utf8 or utf8mb4 columns, convert it to utf8mb4.
* @global wpdb $wpdb WordPress database abstraction object.
* @param string $table The table to convert.
* @return bool True if the table was converted, false if it wasn't.
function maybe_convert_table_to_utf8mb4( $table ) {
$results = $wpdb->get_results( "SHOW FULL COLUMNS FROM `$table`" );
foreach ( $results as $column ) {
if ( $column->Collation ) {
list( $charset ) = explode( '_', $column->Collation );
$charset = strtolower( $charset );
if ( 'utf8' !== $charset && 'utf8mb4' !== $charset ) {
// Don't upgrade tables that have non-utf8 columns.
$table_details = $wpdb->get_row( "SHOW TABLE STATUS LIKE '$table'" );
if ( ! $table_details ) {
list( $table_charset ) = explode( '_', $table_details->Collation );
$table_charset = strtolower( $table_charset );
if ( 'utf8mb4' === $table_charset ) {
return $wpdb->query( "ALTER TABLE $table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci" );
* Retrieve all options as it was for 1.2.
* @global wpdb $wpdb WordPress database abstraction object.
* @return stdClass List of options.
function get_alloptions_110() {
$all_options = new stdClass();
$options = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options" );
foreach ( $options as $option ) {
if ( 'siteurl' === $option->option_name || 'home' === $option->option_name || 'category_base' === $option->option_name ) {
$option->option_value = untrailingslashit( $option->option_value );
$all_options->{$option->option_name} = stripslashes( $option->option_value );
* Utility version of get_option that is private to installation/upgrade.
* @global wpdb $wpdb WordPress database abstraction object.
* @param string $setting Option name.
function __get_option( $setting ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore
if ( 'home' === $setting && defined( 'WP_HOME' ) ) {
return untrailingslashit( WP_HOME );
if ( 'siteurl' === $setting && defined( 'WP_SITEURL' ) ) {
return untrailingslashit( WP_SITEURL );
$option = $wpdb->get_var( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s", $setting ) );
if ( 'home' === $setting && ! $option ) {
return __get_option( 'siteurl' );
if ( in_array( $setting, array( 'siteurl', 'home', 'category_base', 'tag_base' ), true ) ) {
$option = untrailingslashit( $option );
return maybe_unserialize( $option );
* Filters for content to remove unnecessary slashes.
* @param string $content The content to modify.
* @return string The de-slashed content.
function deslash( $content ) {
// Note: \\\ inside a regex denotes a single backslash.
* Replace one or more backslashes followed by a single quote with
$content = preg_replace( "/\\\+'/", "'", $content );
* Replace one or more backslashes followed by a double quote with
$content = preg_replace( '/\\\+"/', '"', $content );
// Replace one or more backslashes with one backslash.
$content = preg_replace( '/\\\+/', '\\', $content );
* Modifies the database based on specified SQL statements.
* Useful for creating new tables and updating existing tables to a new structure.
* @since 6.1.0 Ignores display width for integer data types on MySQL 8.0.17 or later,
* to match MySQL behavior. Note: This does not affect MariaDB.
* @global wpdb $wpdb WordPress database abstraction object.
* @param string[]|string $queries Optional. The query to run. Can be multiple queries
* in an array, or a string of queries separated by
* semicolons. Default empty string.
* @param bool $execute Optional. Whether or not to execute the query right away.
* @return array Strings containing the results of the various update queries.
function dbDelta( $queries = '', $execute = true ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid
if ( in_array( $queries, array( '', 'all', 'blog', 'global', 'ms_global' ), true ) ) {
$queries = wp_get_db_schema( $queries );
// Separate individual queries into an array.
if ( ! is_array( $queries ) ) {
$queries = explode( ';', $queries );
$queries = array_filter( $queries );
* Filters the dbDelta SQL queries.
* @param string[] $queries An array of dbDelta SQL queries.
$queries = apply_filters( 'dbdelta_queries', $queries );
$cqueries = array(); // Creation queries.
$iqueries = array(); // Insertion queries.
// Create a tablename index for an array ($cqueries) of recognized query types.
foreach ( $queries as $qry ) {
if ( preg_match( '|CREATE TABLE ([^ ]*)|', $qry, $matches ) ) {
$cqueries[ trim( $matches[1], '`' ) ] = $qry;
$for_update[ $matches[1] ] = 'Created table ' . $matches[1];
if ( preg_match( '|CREATE DATABASE ([^ ]*)|', $qry, $matches ) ) {
array_unshift( $cqueries, $qry );
if ( preg_match( '|INSERT INTO ([^ ]*)|', $qry, $matches ) ) {
if ( preg_match( '|UPDATE ([^ ]*)|', $qry, $matches ) ) {
* Filters the dbDelta SQL queries for creating tables and/or databases.
* Queries filterable via this hook contain "CREATE TABLE" or "CREATE DATABASE".
* @param string[] $cqueries An array of dbDelta create SQL queries.
$cqueries = apply_filters( 'dbdelta_create_queries', $cqueries );
* Filters the dbDelta SQL queries for inserting or updating.
* Queries filterable via this hook contain "INSERT INTO" or "UPDATE".
* @param string[] $iqueries An array of dbDelta insert or update SQL queries.
$iqueries = apply_filters( 'dbdelta_insert_queries', $iqueries );
$text_fields = array( 'tinytext', 'text', 'mediumtext', 'longtext' );
$blob_fields = array( 'tinyblob', 'blob', 'mediumblob', 'longblob' );
$int_fields = array( 'tinyint', 'smallint', 'mediumint', 'int', 'integer', 'bigint' );
$global_tables = $wpdb->tables( 'global' );
$db_version = $wpdb->db_version();
$db_server_info = $wpdb->db_server_info();
foreach ( $cqueries as $table => $qry ) {
// Upgrade global tables only for the main site. Don't upgrade at all if conditions are not optimal.
if ( in_array( $table, $global_tables, true ) && ! wp_should_upgrade_global_tables() ) {
unset( $cqueries[ $table ], $for_update[ $table ] );
// Fetch the table column structure from the database.
$suppress = $wpdb->suppress_errors();
$tablefields = $wpdb->get_results( "DESCRIBE {$table};" );
$wpdb->suppress_errors( $suppress );
// Clear the field and index arrays.
$indices_without_subparts = array();
// Get all of the field names in the query from between the parentheses.
preg_match( '|\((.*)\)|ms', $qry, $match2 );
$qryline = trim( $match2[1] );
// Separate field lines into an array.
$flds = explode( "\n", $qryline );
// For every field line specified in the query.
foreach ( $flds as $fld ) {
$fld = trim( $fld, " \t\n\r\0\x0B," ); // Default trim characters, plus ','.
// Extract the field name.
preg_match( '|^([^ ]*)|', $fld, $fvals );
$fieldname = trim( $fvals[1], '`' );
$fieldname_lowercased = strtolower( $fieldname );
// Verify the found field name.
switch ( $fieldname_lowercased ) {
* Normalize the index definition.
* This is done so the definition can be compared against the result of a
* `SHOW INDEX FROM $table_name` query which returns the current table
// Extract type, name and columns from the definition.
(?P<index_type> # 1) Type of the index.
PRIMARY\s+KEY|(?:UNIQUE|FULLTEXT|SPATIAL)\s+(?:KEY|INDEX)|KEY|INDEX
\s+ # Followed by at least one white space character.
(?: # Name of the index. Optional if type is PRIMARY KEY.
`? # Name can be escaped with a backtick.
(?P<index_name> # 2) Name of the index.
(?:[0-9a-zA-Z$_-]|[\xC2-\xDF][\x80-\xBF])+
`? # Name can be escaped with a backtick.
\s+ # Followed by at least one white space character.
\( # Opening bracket for the columns.
.+? # 3) Column names, index prefixes, and orders.
\) # Closing bracket for the columns.
// Uppercase the index type and normalize space characters.
$index_type = strtoupper( preg_replace( '/\s+/', ' ', trim( $index_matches['index_type'] ) ) );
// 'INDEX' is a synonym for 'KEY', standardize on 'KEY'.
$index_type = str_replace( 'INDEX', 'KEY', $index_type );
// Escape the index name with backticks. An index for a primary key has no name.
$index_name = ( 'PRIMARY KEY' === $index_type ) ? '' : '`' . strtolower( $index_matches['index_name'] ) . '`';
// Parse the columns. Multiple columns are separated by a comma.
$index_columns = array_map( 'trim', explode( ',', $index_matches['index_columns'] ) );
$index_columns_without_subparts = $index_columns;
foreach ( $index_columns as $id => &$index_column ) {
// Extract column name and number of indexed characters (sub_part).