: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
`? # Name can be escaped with a backtick.
(?P<column_name> # 1) Name of the column.
(?:[0-9a-zA-Z$_-]|[\xC2-\xDF][\x80-\xBF])+
`? # Name can be escaped with a backtick.
\s* # Optional white space character between name and opening bracket.
\( # Opening bracket for the sub part.
\s* # Optional white space character after opening bracket.
\d+ # 2) Number of indexed characters.
\s* # Optional white space character before closing bracket.
\) # Closing bracket for the sub part.
// Escape the column name with backticks.
$index_column = '`' . $index_column_matches['column_name'] . '`';
// We don't need to add the subpart to $index_columns_without_subparts
$index_columns_without_subparts[ $id ] = $index_column;
// Append the optional sup part with the number of indexed characters.
if ( isset( $index_column_matches['sub_part'] ) ) {
$index_column .= '(' . $index_column_matches['sub_part'] . ')';
// Build the normalized index definition and add it to the list of indices.
$indices[] = "{$index_type} {$index_name} (" . implode( ',', $index_columns ) . ')';
$indices_without_subparts[] = "{$index_type} {$index_name} (" . implode( ',', $index_columns_without_subparts ) . ')';
// Destroy no longer needed variables.
unset( $index_column, $index_column_matches, $index_matches, $index_type, $index_name, $index_columns, $index_columns_without_subparts );
// If it's a valid field, add it to the field array.
$cfields[ $fieldname_lowercased ] = $fld;
// For every field in the table.
foreach ( $tablefields as $tablefield ) {
$tablefield_field_lowercased = strtolower( $tablefield->Field );
$tablefield_type_lowercased = strtolower( $tablefield->Type );
$tablefield_type_without_parentheses = preg_replace(
. '(.+)' // Field type, e.g. `int`.
. '\(\d*\)' // Display width.
. '(.*)' // Optional attributes, e.g. `unsigned`.
$tablefield_type_lowercased
// Get the type without attributes, e.g. `int`.
$tablefield_type_base = strtok( $tablefield_type_without_parentheses, ' ' );
// If the table field exists in the field array...
if ( array_key_exists( $tablefield_field_lowercased, $cfields ) ) {
// Get the field type from the query.
preg_match( '|`?' . $tablefield->Field . '`? ([^ ]*( unsigned)?)|i', $cfields[ $tablefield_field_lowercased ], $matches );
$fieldtype = $matches[1];
$fieldtype_lowercased = strtolower( $fieldtype );
$fieldtype_without_parentheses = preg_replace(
. '(.+)' // Field type, e.g. `int`.
. '\(\d*\)' // Display width.
. '(.*)' // Optional attributes, e.g. `unsigned`.
// Get the type without attributes, e.g. `int`.
$fieldtype_base = strtok( $fieldtype_without_parentheses, ' ' );
// Is actual field type different from the field type in query?
if ( $tablefield->Type != $fieldtype ) {
if ( in_array( $fieldtype_lowercased, $text_fields, true ) && in_array( $tablefield_type_lowercased, $text_fields, true ) ) {
if ( array_search( $fieldtype_lowercased, $text_fields, true ) < array_search( $tablefield_type_lowercased, $text_fields, true ) ) {
if ( in_array( $fieldtype_lowercased, $blob_fields, true ) && in_array( $tablefield_type_lowercased, $blob_fields, true ) ) {
if ( array_search( $fieldtype_lowercased, $blob_fields, true ) < array_search( $tablefield_type_lowercased, $blob_fields, true ) ) {
if ( in_array( $fieldtype_base, $int_fields, true ) && in_array( $tablefield_type_base, $int_fields, true )
&& $fieldtype_without_parentheses === $tablefield_type_without_parentheses
* MySQL 8.0.17 or later does not support display width for integer data types,
* so if display width is the only difference, it can be safely ignored.
* Note: This is specific to MySQL and does not affect MariaDB.
if ( version_compare( $db_version, '8.0.17', '>=' )
&& ! str_contains( $db_server_info, 'MariaDB' )
// Add a query to change the column type.
$cqueries[] = "ALTER TABLE {$table} CHANGE COLUMN `{$tablefield->Field}` " . $cfields[ $tablefield_field_lowercased ];
$for_update[ $table . '.' . $tablefield->Field ] = "Changed type of {$table}.{$tablefield->Field} from {$tablefield->Type} to {$fieldtype}";
// Get the default value from the array.
if ( preg_match( "| DEFAULT '(.*?)'|i", $cfields[ $tablefield_field_lowercased ], $matches ) ) {
$default_value = $matches[1];
if ( $tablefield->Default != $default_value ) {
// Add a query to change the column's default value
$cqueries[] = "ALTER TABLE {$table} ALTER COLUMN `{$tablefield->Field}` SET DEFAULT '{$default_value}'";
$for_update[ $table . '.' . $tablefield->Field ] = "Changed default value of {$table}.{$tablefield->Field} from {$tablefield->Default} to {$default_value}";
// Remove the field from the array (so it's not added).
unset( $cfields[ $tablefield_field_lowercased ] );
// This field exists in the table, but not in the creation queries?
// For every remaining field specified for the table.
foreach ( $cfields as $fieldname => $fielddef ) {
// Push a query line into $cqueries that adds the field to that table.
$cqueries[] = "ALTER TABLE {$table} ADD COLUMN $fielddef";
$for_update[ $table . '.' . $fieldname ] = 'Added column ' . $table . '.' . $fieldname;
// Index stuff goes here. Fetch the table index structure from the database.
$tableindices = $wpdb->get_results( "SHOW INDEX FROM {$table};" );
// Clear the index array.
// For every index in the table.
foreach ( $tableindices as $tableindex ) {
$keyname = strtolower( $tableindex->Key_name );
// Add the index to the index data array.
$index_ary[ $keyname ]['columns'][] = array(
'fieldname' => $tableindex->Column_name,
'subpart' => $tableindex->Sub_part,
$index_ary[ $keyname ]['unique'] = ( 0 == $tableindex->Non_unique ) ? true : false;
$index_ary[ $keyname ]['index_type'] = $tableindex->Index_type;
// For each actual index in the index array.
foreach ( $index_ary as $index_name => $index_data ) {
// Build a create string to compare to the query.
if ( 'primary' === $index_name ) {
$index_string .= 'PRIMARY ';
} elseif ( $index_data['unique'] ) {
$index_string .= 'UNIQUE ';
if ( 'FULLTEXT' === strtoupper( $index_data['index_type'] ) ) {
$index_string .= 'FULLTEXT ';
if ( 'SPATIAL' === strtoupper( $index_data['index_type'] ) ) {
$index_string .= 'SPATIAL ';
if ( 'primary' !== $index_name ) {
$index_string .= '`' . $index_name . '`';
// For each column in the index.
foreach ( $index_data['columns'] as $column_data ) {
if ( '' !== $index_columns ) {
// Add the field to the column list string.
$index_columns .= '`' . $column_data['fieldname'] . '`';
// Add the column list to the index create string.
$index_string .= " ($index_columns)";
// Check if the index definition exists, ignoring subparts.
$aindex = array_search( $index_string, $indices_without_subparts, true );
if ( false !== $aindex ) {
// If the index already exists (even with different subparts), we don't need to create it.
unset( $indices_without_subparts[ $aindex ] );
unset( $indices[ $aindex ] );
// For every remaining index specified for the table.
foreach ( (array) $indices as $index ) {
// Push a query line into $cqueries that adds the index to that table.
$cqueries[] = "ALTER TABLE {$table} ADD $index";
$for_update[] = 'Added index ' . $table . ' ' . $index;
// Remove the original table creation query from processing.
unset( $cqueries[ $table ], $for_update[ $table ] );
$allqueries = array_merge( $cqueries, $iqueries );
foreach ( $allqueries as $query ) {
* Updates the database tables to a new schema.
* By default, updates all the tables to use the latest defined schema, but can also
* be used to update a specific set of tables in wp_get_db_schema().
* @param string $tables Optional. Which set of tables to update. Default is 'all'.
function make_db_current( $tables = 'all' ) {
$alterations = dbDelta( $tables );
foreach ( $alterations as $alteration ) {
echo "<li>$alteration</li>\n";
* Updates the database tables to a new schema, but without displaying results.
* By default, updates all the tables to use the latest defined schema, but can
* also be used to update a specific set of tables in wp_get_db_schema().
* @param string $tables Optional. Which set of tables to update. Default is 'all'.
function make_db_current_silent( $tables = 'all' ) {
* Creates a site theme from an existing theme.
* {@internal Missing Long Description}}
* @param string $theme_name The name of the theme.
* @param string $template The directory name of the theme.
function make_site_theme_from_oldschool( $theme_name, $template ) {
$home_path = get_home_path();
$site_dir = WP_CONTENT_DIR . "/themes/$template";
$default_dir = WP_CONTENT_DIR . '/themes/' . WP_DEFAULT_THEME;
if ( ! file_exists( "$home_path/index.php" ) ) {
* Copy files from the old locations to the site theme.
* TODO: This does not copy arbitrary include dependencies. Only the standard WP files are copied.
'index.php' => 'index.php',
'wp-layout.css' => 'style.css',
'wp-comments.php' => 'comments.php',
'wp-comments-popup.php' => 'comments-popup.php',
foreach ( $files as $oldfile => $newfile ) {
if ( 'index.php' === $oldfile ) {
// Check to make sure it's not a new index.
if ( 'index.php' === $oldfile ) {
$index = implode( '', file( "$oldpath/$oldfile" ) );
if ( str_contains( $index, 'WP_USE_THEMES' ) ) {
if ( ! copy( "$default_dir/$oldfile", "$site_dir/$newfile" ) ) {
if ( ! copy( "$oldpath/$oldfile", "$site_dir/$newfile" ) ) {
chmod( "$site_dir/$newfile", 0777 );
// Update the blog header include in each file.
$lines = explode( "\n", implode( '', file( "$site_dir/$newfile" ) ) );
$f = fopen( "$site_dir/$newfile", 'w' );
foreach ( $lines as $line ) {
if ( preg_match( '/require.*wp-blog-header/', $line ) ) {
// Update stylesheet references.
"<?php echo __get_option('siteurl'); ?>/wp-layout.css",
"<?php bloginfo('stylesheet_url'); ?>",
// Update comments template inclusion.
"<?php include(ABSPATH . 'wp-comments.php'); ?>",
'<?php comments_template(); ?>',
fwrite( $f, "{$line}\n" );
"Theme Name: $theme_name\n" .
'Theme URI: ' . __get_option( 'siteurl' ) . "\n" .
"Description: A theme automatically created by the update.\n" .
$stylelines = file_get_contents( "$site_dir/style.css" );
$f = fopen( "$site_dir/style.css", 'w' );
fwrite( $f, $stylelines );
* Creates a site theme from the default theme.
* {@internal Missing Long Description}}
* @param string $theme_name The name of the theme.
* @param string $template The directory name of the theme.
function make_site_theme_from_default( $theme_name, $template ) {
$site_dir = WP_CONTENT_DIR . "/themes/$template";
$default_dir = WP_CONTENT_DIR . '/themes/' . WP_DEFAULT_THEME;
* Copy files from the default theme to the site theme.
* $files = array( 'index.php', 'comments.php', 'comments-popup.php', 'footer.php', 'header.php', 'sidebar.php', 'style.css' );
$theme_dir = @opendir( $default_dir );
while ( ( $theme_file = readdir( $theme_dir ) ) !== false ) {
if ( is_dir( "$default_dir/$theme_file" ) ) {
if ( ! copy( "$default_dir/$theme_file", "$site_dir/$theme_file" ) ) {
chmod( "$site_dir/$theme_file", 0777 );
// Rewrite the theme header.
$stylelines = explode( "\n", implode( '', file( "$site_dir/style.css" ) ) );
$f = fopen( "$site_dir/style.css", 'w' );
'Theme Name:' => $theme_name,
'Theme URI:' => __get_option( 'url' ),
'Description:' => 'Your theme.',
foreach ( $stylelines as $line ) {
foreach ( $headers as $header => $value ) {
if ( str_contains( $line, $header ) ) {
$line = $header . ' ' . $value;
fwrite( $f, $line . "\n" );
if ( ! mkdir( "$site_dir/images", 0777 ) ) {
$images_dir = @opendir( "$default_dir/images" );
while ( ( $image = readdir( $images_dir ) ) !== false ) {
if ( is_dir( "$default_dir/images/$image" ) ) {
if ( ! copy( "$default_dir/images/$image", "$site_dir/images/$image" ) ) {
chmod( "$site_dir/images/$image", 0777 );
* {@internal Missing Long Description}}
function make_site_theme() {
// Name the theme after the blog.
$theme_name = __get_option( 'blogname' );
$template = sanitize_title( $theme_name );
$site_dir = WP_CONTENT_DIR . "/themes/$template";
// If the theme already exists, nothing to do.
if ( is_dir( $site_dir ) ) {
// We must be able to write to the themes dir.
if ( ! is_writable( WP_CONTENT_DIR . '/themes' ) ) {