728x90
dbDelta( string|array $queries = '', bool $execute = true )
Modifies the database based on specified SQL statements.
Description #Description
Useful for creating new tables and updating existing tables to a new structure.
Parameters #Parameters
- $queries
(string|array) (Optional) The query to run. Can be multiple queries in an array, or a string of queries separated by semicolons.
Default value: ''
- $execute
(bool) (Optional) Whether or not to execute the query right away.
Default value: true
Return #Return
(array) Strings containing the results of the various update queries.
Source #Source
File: wp-admin/includes/upgrade.php
2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 | function dbDelta( $queries = '' , $execute = true ) { global $wpdb ; 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. * * @since 3.3.0 * * @param array $queries An array of dbDelta SQL queries. */ $queries = apply_filters( 'dbdelta_queries' , $queries ); $cqueries = array (); // Creation Queries $iqueries = array (); // Insertion Queries $for_update = array (); // Create a tablename index for an array ($cqueries) of queries foreach ( $queries as $qry ) { if ( preg_match( "|CREATE TABLE ([^ ]*)|" , $qry , $matches ) ) { $cqueries [ trim( $matches [1], '`' ) ] = $qry ; $for_update [ $matches [1]] = 'Created table ' . $matches [1]; } elseif ( preg_match( "|CREATE DATABASE ([^ ]*)|" , $qry , $matches ) ) { array_unshift ( $cqueries , $qry ); } elseif ( preg_match( "|INSERT INTO ([^ ]*)|" , $qry , $matches ) ) { $iqueries [] = $qry ; } elseif ( preg_match( "|UPDATE ([^ ]*)|" , $qry , $matches ) ) { $iqueries [] = $qry ; } else { // Unrecognized query type } } /** * Filters the dbDelta SQL queries for creating tables and/or databases. * * Queries filterable via this hook contain "CREATE TABLE" or "CREATE DATABASE". * * @since 3.3.0 * * @param array $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". * * @since 3.3.0 * * @param array $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' ); $global_tables = $wpdb ->tables( 'global' ); 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 ) && ! wp_should_upgrade_global_tables() ) { unset( $cqueries [ $table ], $for_update [ $table ] ); continue ; } // Fetch the table column structure from the database $suppress = $wpdb ->suppress_errors(); $tablefields = $wpdb ->get_results( "DESCRIBE {$table};" ); $wpdb ->suppress_errors( $suppress ); if ( ! $tablefields ) continue ; // Clear the field and index arrays. $cfields = $indices = $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. $validfield = true; switch ( $fieldname_lowercased ) { case '' : case 'primary' : case 'index' : case 'fulltext' : case 'unique' : case 'key' : case 'spatial' : $validfield = false; /* * 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 * index information. */ // Extract type, name and columns from the definition. preg_match( '/^' . '(?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. . '(?P<index_columns>' . '.+?' // 3) Column names, index prefixes, and orders. . ')' . '\)' // Closing bracket for the columns. . '$/im' , $fld , $index_matches ); // 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 = $index_columns_without_subparts = array_map ( 'trim' , explode ( ',' , $index_matches [ 'index_columns' ] ) ); // Normalize columns. foreach ( $index_columns as $id => & $index_column ) { // Extract column name and number of indexed characters (sub_part). preg_match( '/' . '`?' // 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. . '(?:' // Optional sub part. . '\s*' // Optional white space character between name and opening bracket. . '\(' // Opening bracket for the sub part. . '\s*' // Optional white space character after opening bracket. . '(?P<sub_part>' . '\d+' // 2) Number of indexed characters. . ')' . '\s*' // Optional white space character before closing bracket. . '\)' // Closing bracket for the sub part. . ')?' . '/' , $index_column , $index_column_matches ); // 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 ); break ; } // If it's a valid field, add it to the field array. if ( $validfield ) { $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 ); // 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 ); // Is actual field type different from the field type in query? if ( $tablefield ->Type != $fieldtype ) { $do_change = true; if ( in_array( $fieldtype_lowercased , $text_fields ) && in_array( $tablefield_type_lowercased , $text_fields ) ) { if ( array_search ( $fieldtype_lowercased , $text_fields ) < array_search ( $tablefield_type_lowercased , $text_fields ) ) { $do_change = false; } } if ( in_array( $fieldtype_lowercased , $blob_fields ) && in_array( $tablefield_type_lowercased , $blob_fields ) ) { if ( array_search ( $fieldtype_lowercased , $blob_fields ) < array_search ( $tablefield_type_lowercased , $blob_fields ) ) { $do_change = false; } } if ( $do_change ) { // 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 ] ); } else { // 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};" ); if ( $tableindices ) { // Clear the index array. $index_ary = array (); // For every index in the table. foreach ( $tableindices as $tableindex ) { // Add the index to the index data array. $keyname = strtolower ( $tableindex ->Key_name ); $index_ary [ $keyname ][ 'columns' ][] = array ( 'fieldname' => $tableindex ->Column_name, 'subpart' => $tableindex ->Sub_part); $index_ary [ $keyname ][ 'unique' ] = ( $tableindex ->Non_unique == 0)?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. $index_string = '' ; if ( $index_name == 'primary' ) { $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 ' ; } $index_string .= 'KEY ' ; if ( 'primary' !== $index_name ) { $index_string .= '`' . $index_name . '`' ; } $index_columns = '' ; // For each column in the index. foreach ( $index_data [ 'columns' ] as $column_data ) { if ( $index_columns != '' ) { $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. if ( ! ( ( $aindex = array_search ( $index_string , $indices_without_subparts ) ) === false ) ) { // 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 ); if ( $execute ) { foreach ( $allqueries as $query ) { $wpdb ->query( $query ); } } return $for_update ; } |
Changelog #Changelog
Version | Description |
---|---|
1.5.0 | Introduced. |
Related #Related
Uses #Uses
- wp-admin/includes/upgrade.php: wp_should_upgrade_global_tables()
- wp-admin/includes/schema.php: wp_get_db_schema()
- wp-admin/includes/upgrade.php: dbdelta_create_queries
- wp-admin/includes/upgrade.php: dbdelta_insert_queries
- wp-admin/includes/upgrade.php: dbdelta_queries Show 5 more uses
Used By #Used By
- wp-admin/includes/schema.php: install_network()
- wp-admin/includes/upgrade.php: make_db_current()
- wp-admin/includes/upgrade.php: make_db_current_silent()
- wp-admin/includes/upgrade.php: install_global_terms()
User Contributed Notes #User Contributed Notes
'WEB > WP(WordPress)' 카테고리의 다른 글
WC_API – The WooCommerce API Callback (0) | 2018.04.23 |
---|---|
add_query_arg() (0) | 2018.04.20 |
woocommerce-gateway-offline/woocommerce-gateway-offline.php (0) | 2018.04.16 |
$wpdb Fatal error (0) | 2018.04.16 |
Adding Javascript To WordPress Themes The Right Way (0) | 2018.04.14 |
You must be very careful in your SQL command structure when creating tables with indexes.
Here is a simple example of the proper create table syntax for a table with a primary key on a field named “id” and a secondary key on a field named “first”.
PRIMARY KEY must be followed by TWO SPACES then the open parenthesis then the field name and a closing parenthesis.
KEY must be followed by a SINGLE SPACE then the key name then a space then open parenthesis with the field name then a closed parenthesis.
private
function
index_test_001() {
global
$wpdb
;
$table_name
=
$wpdb
->prefix .
'dbdelta_test_001'
;
$wpdb_collate
=
$wpdb
->collate;
$sql
=
"CREATE TABLE {
$table_name
} (
id mediumint(8) unsigned NOT NULL auto_increment ,
first varchar(255) NULL,
PRIMARY KEY (id),
KEY first (first)
)
COLLATE {
$wpdb_collate
}";
require_once
(ABSPATH .
'wp-admin/includes/upgrade.php'
);
dbDelta(
$sql
);
}
Expand full source code
Be careful not to put a COMMENT on field or key; the preg_match code doesn’t handle it. The following code is wrong (thanks to Store Locator Plus’ code).
private
function
index_test_001() {
global
$wpdb
;
$table_name
=
$wpdb
->prefix .
'dbdelta_test_001'
;
$wpdb_collate
=
$wpdb
->collate;
$sql
=
"CREATE TABLE {
$table_name
} (
id mediumint(8) unsigned NOT NULL auto_increment ,
first varchar(255) NULL,
PRIMARY KEY (id),
KEY first (first) COMMENT
'First name'
)
COLLATE {
$wpdb_collate
}";
require_once
(ABSPATH .
'wp-admin/includes/upgrade.php'
);
dbDelta(
$sql
);
}
Expand full source code
Note: If you change the name of a field, an empty column with the new name will be created, but the old column is not removed!
If you need to change the structure of a table, is better to use
$wpdb
rather than this method because is not guaranteed it works for updating any table structure.(I post here a corrected version of my previous note. Several typographical mistakes have slipped into the original version.)
As a side-note, the dbDelta function cannot be used to drop a table from the wp_ database . A function such as the one below can be used instead (don’t forget to replace
my_theme
with your own theme name):function
my_theme_drop_table (
$table_name
=
'the_name_without_any_prefix'
){
global
$wpdb
;
$table_name_prepared
=
$wpdb
->prefix .
$table_name
;
$the_removal_query
=
"DROP TABLE IF EXISTS {$table_name_prepared}"
;
$wpdb
->query(
$the_removal_query
);
}
See also https://developer.wordpress.org/plugins/the-basics/uninstall-methods/.