| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * WordPress Upgrade API 4 * 5 * Most of the functions are pluggable and can be overwritten. 6 * 7 * @package WordPress 8 * @subpackage Administration 9 */ 10 11 /** Include user installation customization script. */ 12 if ( file_exists( WP_CONTENT_DIR . '/install.php' ) ) { 13 require WP_CONTENT_DIR . '/install.php'; 14 } 15 16 /** WordPress Administration API */ 17 require_once ABSPATH . 'wp-admin/includes/admin.php'; 18 19 /** WordPress Schema API */ 20 require_once ABSPATH . 'wp-admin/includes/schema.php'; 21 22 if ( ! function_exists( 'wp_install' ) ) : 23 /** 24 * Installs the site. 25 * 26 * Runs the required functions to set up and populate the database, 27 * including primary admin user and initial options. 28 * 29 * @since 2.1.0 30 * 31 * @param string $blog_title Site title. 32 * @param string $user_name User's username. 33 * @param string $user_email User's email. 34 * @param bool $is_public Whether the site is public. 35 * @param string $deprecated Optional. Not used. 36 * @param string $user_password Optional. User's chosen password. Default empty (random password). 37 * @param string $language Optional. Language chosen. Default empty. 38 * @return array { 39 * Data for the newly installed site. 40 * 41 * @type string $url The URL of the site. 42 * @type int $user_id The ID of the site owner. 43 * @type string $password The password of the site owner, if their user account didn't already exist. 44 * @type string $password_message The explanatory message regarding the password. 45 * } 46 * 47 * @phpstan-param '' $deprecated 48 */ 49 function wp_install( 50 $blog_title, 51 $user_name, 52 $user_email, 53 $is_public, 54 $deprecated = '', 55 #[\SensitiveParameter] 56 $user_password = '', 57 $language = '' 58 ) { 59 if ( ! empty( $deprecated ) ) { 60 _deprecated_argument( __FUNCTION__, '2.6.0' ); 61 } 62 63 wp_check_mysql_version(); 64 wp_cache_flush(); 65 make_db_current_silent(); 66 67 /* 68 * Ensure update checks are delayed after installation. 69 * 70 * This prevents users being presented with a maintenance mode screen 71 * immediately after installation. 72 */ 73 wp_unschedule_hook( 'wp_version_check' ); 74 wp_unschedule_hook( 'wp_update_plugins' ); 75 wp_unschedule_hook( 'wp_update_themes' ); 76 77 wp_schedule_event( time() + HOUR_IN_SECONDS, 'twicedaily', 'wp_version_check' ); 78 wp_schedule_event( time() + ( 1.5 * HOUR_IN_SECONDS ), 'twicedaily', 'wp_update_plugins' ); 79 wp_schedule_event( time() + ( 2 * HOUR_IN_SECONDS ), 'twicedaily', 'wp_update_themes' ); 80 81 populate_options(); 82 populate_roles(); 83 84 update_option( 'blogname', $blog_title ); 85 update_option( 'admin_email', $user_email ); 86 update_option( 'blog_public', $is_public ); 87 88 // Freshness of site - in the future, this could get more specific about actions taken, perhaps. 89 update_option( 'fresh_site', 1, false ); 90 91 if ( $language ) { 92 update_option( 'WPLANG', $language ); 93 } 94 95 $guessurl = wp_guess_url(); 96 97 update_option( 'siteurl', $guessurl ); 98 99 // If not a public site, don't ping. 100 if ( ! $is_public ) { 101 update_option( 'default_pingback_flag', 0 ); 102 } 103 104 /* 105 * Create default user. If the user already exists, the user tables are 106 * being shared among sites. Just set the role in that case. 107 */ 108 $user_id = username_exists( $user_name ); 109 $user_password = trim( $user_password ); 110 $email_password = false; 111 $user_created = false; 112 113 if ( ! $user_id && empty( $user_password ) ) { 114 $user_password = wp_generate_password( 12, false ); 115 $message = __( '<strong><em>Note that password</em></strong> carefully! It is a <em>random</em> password that was generated just for you.' ); 116 $user_id = wp_create_user( $user_name, $user_password, $user_email ); 117 update_user_meta( $user_id, 'default_password_nag', true ); 118 $email_password = true; 119 $user_created = true; 120 } elseif ( ! $user_id ) { 121 // Password has been provided. 122 $message = '<em>' . __( 'Your chosen password.' ) . '</em>'; 123 $user_id = wp_create_user( $user_name, $user_password, $user_email ); 124 $user_created = true; 125 } else { 126 $message = __( 'User already exists. Password inherited.' ); 127 } 128 129 $user = new WP_User( $user_id ); 130 $user->set_role( 'administrator' ); 131 132 if ( $user_created ) { 133 $user->user_url = $guessurl; 134 wp_update_user( $user ); 135 } 136 137 wp_install_defaults( $user_id ); 138 139 wp_install_maybe_enable_pretty_permalinks(); 140 141 flush_rewrite_rules(); 142 143 wp_new_blog_notification( $blog_title, $guessurl, $user_id, ( $email_password ? $user_password : __( 'The password you chose during installation.' ) ) ); 144 145 wp_cache_flush(); 146 147 /** 148 * Fires after a site is fully installed. 149 * 150 * @since 3.9.0 151 * 152 * @param WP_User $user The site owner. 153 */ 154 do_action( 'wp_install', $user ); 155 156 return array( 157 'url' => $guessurl, 158 'user_id' => $user_id, 159 'password' => $user_password, 160 'password_message' => $message, 161 ); 162 } 163 endif; 164 165 if ( ! function_exists( 'wp_install_defaults' ) ) : 166 /** 167 * Creates the initial content for a newly-installed site. 168 * 169 * Adds the default "Uncategorized" category, the first post (with comment), 170 * first page, and default widgets for default theme for the current version. 171 * 172 * @since 2.1.0 173 * 174 * @global wpdb $wpdb WordPress database abstraction object. 175 * @global WP_Rewrite $wp_rewrite WordPress rewrite component. 176 * @global string $table_prefix The database table prefix. 177 * 178 * @param int $user_id User ID. 179 */ 180 function wp_install_defaults( $user_id ) { 181 global $wpdb, $wp_rewrite, $table_prefix; 182 183 // Default category. 184 $cat_name = __( 'Uncategorized' ); 185 /* translators: Default category slug. */ 186 $cat_slug = sanitize_title( _x( 'Uncategorized', 'Default category slug' ) ); 187 188 $cat_id = 1; 189 190 $wpdb->insert( 191 $wpdb->terms, 192 array( 193 'term_id' => $cat_id, 194 'name' => $cat_name, 195 'slug' => $cat_slug, 196 'term_group' => 0, 197 ) 198 ); 199 $wpdb->insert( 200 $wpdb->term_taxonomy, 201 array( 202 'term_id' => $cat_id, 203 'taxonomy' => 'category', 204 'description' => '', 205 'parent' => 0, 206 'count' => 1, 207 ) 208 ); 209 $cat_tt_id = $wpdb->insert_id; 210 211 // First post. 212 $now = current_time( 'mysql' ); 213 $now_gmt = current_time( 'mysql', true ); 214 $first_post_guid = get_option( 'home' ) . '/?p=1'; 215 216 if ( is_multisite() ) { 217 $first_post = get_site_option( 'first_post' ); 218 219 if ( ! $first_post ) { 220 $first_post = "<!-- wp:paragraph -->\n<p>" . 221 /* translators: First post content. %s: Site link. */ 222 __( 'Welcome to %s. This is your first post. Edit or delete it, then start writing!' ) . 223 "</p>\n<!-- /wp:paragraph -->"; 224 } 225 226 $first_post = sprintf( 227 $first_post, 228 sprintf( '<a href="%s">%s</a>', esc_url( network_home_url() ), get_network()->site_name ) 229 ); 230 231 // Back-compat for pre-4.4. 232 $first_post = str_replace( 'SITE_URL', esc_url( network_home_url() ), $first_post ); 233 $first_post = str_replace( 'SITE_NAME', get_network()->site_name, $first_post ); 234 } else { 235 $first_post = "<!-- wp:paragraph -->\n<p>" . 236 /* translators: First post content. %s: Site link. */ 237 __( 'Welcome to WordPress. This is your first post. Edit or delete it, then start writing!' ) . 238 "</p>\n<!-- /wp:paragraph -->"; 239 } 240 241 $wpdb->insert( 242 $wpdb->posts, 243 array( 244 'post_author' => $user_id, 245 'post_date' => $now, 246 'post_date_gmt' => $now_gmt, 247 'post_content' => $first_post, 248 'post_excerpt' => '', 249 'post_title' => __( 'Hello world!' ), 250 /* translators: Default post slug. */ 251 'post_name' => sanitize_title( _x( 'hello-world', 'Default post slug' ) ), 252 'post_modified' => $now, 253 'post_modified_gmt' => $now_gmt, 254 'guid' => $first_post_guid, 255 'comment_count' => 1, 256 'to_ping' => '', 257 'pinged' => '', 258 'post_content_filtered' => '', 259 ) 260 ); 261 262 if ( is_multisite() ) { 263 update_posts_count(); 264 } 265 266 $wpdb->insert( 267 $wpdb->term_relationships, 268 array( 269 'term_taxonomy_id' => $cat_tt_id, 270 'object_id' => 1, 271 ) 272 ); 273 274 // Default comment. 275 if ( is_multisite() ) { 276 $first_comment_author = get_site_option( 'first_comment_author' ); 277 $first_comment_email = get_site_option( 'first_comment_email' ); 278 $first_comment_url = get_site_option( 'first_comment_url', network_home_url() ); 279 $first_comment = get_site_option( 'first_comment' ); 280 } 281 282 $first_comment_author = ! empty( $first_comment_author ) ? $first_comment_author : __( 'A WordPress Commenter' ); 283 $first_comment_email = ! empty( $first_comment_email ) ? $first_comment_email : 'wapuu@wordpress.example'; 284 $first_comment_url = ! empty( $first_comment_url ) ? $first_comment_url : esc_url( __( 'https://wordpress.org/' ) ); 285 $first_comment = ! empty( $first_comment ) ? $first_comment : sprintf( 286 /* translators: %s: Gravatar URL. */ 287 __( 288 'Hi, this is a comment. 289 To get started with moderating, editing, and deleting comments, please visit the Comments screen in the dashboard. 290 Commenter avatars come from <a href="%s">Gravatar</a>.' 291 ), 292 /* translators: The localized Gravatar URL. */ 293 esc_url( __( 'https://gravatar.com/' ) ) 294 ); 295 $wpdb->insert( 296 $wpdb->comments, 297 array( 298 'comment_post_ID' => 1, 299 'comment_author' => $first_comment_author, 300 'comment_author_email' => $first_comment_email, 301 'comment_author_url' => $first_comment_url, 302 'comment_date' => $now, 303 'comment_date_gmt' => $now_gmt, 304 'comment_content' => $first_comment, 305 'comment_type' => 'comment', 306 ) 307 ); 308 309 // First page. 310 if ( is_multisite() ) { 311 $first_page = get_site_option( 'first_page' ); 312 } 313 314 if ( empty( $first_page ) ) { 315 $first_page = "<!-- wp:paragraph -->\n<p>"; 316 /* translators: First page content. */ 317 $first_page .= __( "This is an example page. It's different from a blog post because it will stay in one place and will show up in your site navigation (in most themes). Most people start with an About page that introduces them to potential site visitors. It might say something like this:" ); 318 $first_page .= "</p>\n<!-- /wp:paragraph -->\n\n"; 319 320 $first_page .= "<!-- wp:quote -->\n<blockquote class=\"wp-block-quote\">\n<!-- wp:paragraph -->\n<p>"; 321 /* translators: First page content. */ 322 $first_page .= __( "Hi there! I'm a bike messenger by day, aspiring actor by night, and this is my website. I live in Los Angeles, have a great dog named Jack, and I like piña coladas. (And gettin' caught in the rain.)" ); 323 $first_page .= "</p>\n<!-- /wp:paragraph -->\n</blockquote>\n<!-- /wp:quote -->\n\n"; 324 325 $first_page .= "<!-- wp:paragraph -->\n<p>"; 326 /* translators: First page content. */ 327 $first_page .= __( '...or something like this:' ); 328 $first_page .= "</p>\n<!-- /wp:paragraph -->\n\n"; 329 330 $first_page .= "<!-- wp:quote -->\n<blockquote class=\"wp-block-quote\">\n<!-- wp:paragraph -->\n<p>"; 331 /* translators: First page content. */ 332 $first_page .= __( 'The XYZ Doohickey Company was founded in 1971, and has been providing quality doohickeys to the public ever since. Located in Gotham City, XYZ employs over 2,000 people and does all kinds of awesome things for the Gotham community.' ); 333 $first_page .= "</p>\n<!-- /wp:paragraph -->\n</blockquote>\n<!-- /wp:quote -->\n\n"; 334 335 $first_page .= "<!-- wp:paragraph -->\n<p>"; 336 $first_page .= sprintf( 337 /* translators: First page content. %s: Site admin URL. */ 338 __( 'As a new WordPress user, you should go to <a href="%s">your dashboard</a> to delete this page and create new pages for your content. Have fun!' ), 339 admin_url() 340 ); 341 $first_page .= "</p>\n<!-- /wp:paragraph -->"; 342 } 343 344 $first_post_guid = get_option( 'home' ) . '/?page_id=2'; 345 $wpdb->insert( 346 $wpdb->posts, 347 array( 348 'post_author' => $user_id, 349 'post_date' => $now, 350 'post_date_gmt' => $now_gmt, 351 'post_content' => $first_page, 352 'post_excerpt' => '', 353 'comment_status' => 'closed', 354 'post_title' => __( 'Sample Page' ), 355 /* translators: Default page slug. */ 356 'post_name' => __( 'sample-page' ), 357 'post_modified' => $now, 358 'post_modified_gmt' => $now_gmt, 359 'guid' => $first_post_guid, 360 'post_type' => 'page', 361 'to_ping' => '', 362 'pinged' => '', 363 'post_content_filtered' => '', 364 ) 365 ); 366 $wpdb->insert( 367 $wpdb->postmeta, 368 array( 369 'post_id' => 2, 370 'meta_key' => '_wp_page_template', 371 'meta_value' => 'default', 372 ) 373 ); 374 375 // Privacy Policy page. 376 if ( is_multisite() ) { 377 // Disable by default unless the suggested content is provided. 378 $privacy_policy_content = get_site_option( 'default_privacy_policy_content' ); 379 } else { 380 if ( ! class_exists( 'WP_Privacy_Policy_Content' ) ) { 381 require_once ABSPATH . 'wp-admin/includes/class-wp-privacy-policy-content.php'; 382 } 383 384 $privacy_policy_content = WP_Privacy_Policy_Content::get_default_content(); 385 } 386 387 if ( ! empty( $privacy_policy_content ) ) { 388 $privacy_policy_guid = get_option( 'home' ) . '/?page_id=3'; 389 390 $wpdb->insert( 391 $wpdb->posts, 392 array( 393 'post_author' => $user_id, 394 'post_date' => $now, 395 'post_date_gmt' => $now_gmt, 396 'post_content' => $privacy_policy_content, 397 'post_excerpt' => '', 398 'comment_status' => 'closed', 399 'post_title' => __( 'Privacy Policy' ), 400 /* translators: Privacy Policy page slug. */ 401 'post_name' => __( 'privacy-policy' ), 402 'post_modified' => $now, 403 'post_modified_gmt' => $now_gmt, 404 'guid' => $privacy_policy_guid, 405 'post_type' => 'page', 406 'post_status' => 'draft', 407 'to_ping' => '', 408 'pinged' => '', 409 'post_content_filtered' => '', 410 ) 411 ); 412 $wpdb->insert( 413 $wpdb->postmeta, 414 array( 415 'post_id' => 3, 416 'meta_key' => '_wp_page_template', 417 'meta_value' => 'default', 418 ) 419 ); 420 update_option( 'wp_page_for_privacy_policy', 3 ); 421 } 422 423 // Set up default widgets for default theme. 424 update_option( 425 'widget_block', 426 array( 427 2 => array( 'content' => '<!-- wp:search /-->' ), 428 3 => array( 'content' => '<!-- wp:group --><div class="wp-block-group"><!-- wp:heading --><h2>' . __( 'Recent Posts' ) . '</h2><!-- /wp:heading --><!-- wp:latest-posts /--></div><!-- /wp:group -->' ), 429 4 => array( 'content' => '<!-- wp:group --><div class="wp-block-group"><!-- wp:heading --><h2>' . __( 'Recent Comments' ) . '</h2><!-- /wp:heading --><!-- wp:latest-comments {"displayAvatar":false,"displayDate":false,"displayExcerpt":false} /--></div><!-- /wp:group -->' ), 430 5 => array( 'content' => '<!-- wp:group --><div class="wp-block-group"><!-- wp:heading --><h2>' . __( 'Archives' ) . '</h2><!-- /wp:heading --><!-- wp:archives /--></div><!-- /wp:group -->' ), 431 6 => array( 'content' => '<!-- wp:group --><div class="wp-block-group"><!-- wp:heading --><h2>' . __( 'Categories' ) . '</h2><!-- /wp:heading --><!-- wp:categories /--></div><!-- /wp:group -->' ), 432 '_multiwidget' => 1, 433 ) 434 ); 435 update_option( 436 'sidebars_widgets', 437 array( 438 'wp_inactive_widgets' => array(), 439 'sidebar-1' => array( 440 0 => 'block-2', 441 1 => 'block-3', 442 2 => 'block-4', 443 ), 444 'sidebar-2' => array( 445 0 => 'block-5', 446 1 => 'block-6', 447 ), 448 'array_version' => 3, 449 ) 450 ); 451 452 if ( ! is_multisite() ) { 453 update_user_meta( $user_id, 'show_welcome_panel', 1 ); 454 } elseif ( ! is_super_admin( $user_id ) && ! metadata_exists( 'user', $user_id, 'show_welcome_panel' ) ) { 455 update_user_meta( $user_id, 'show_welcome_panel', 2 ); 456 } 457 458 if ( is_multisite() ) { 459 // Flush rules to pick up the new page. 460 $wp_rewrite->init(); 461 $wp_rewrite->flush_rules(); 462 463 $user = new WP_User( $user_id ); 464 $wpdb->update( $wpdb->options, array( 'option_value' => $user->user_email ), array( 'option_name' => 'admin_email' ) ); 465 466 // Remove all perms except for the login user. 467 $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->usermeta WHERE user_id != %d AND meta_key = %s", $user_id, $table_prefix . 'user_level' ) ); 468 $wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->usermeta WHERE user_id != %d AND meta_key = %s", $user_id, $table_prefix . 'capabilities' ) ); 469 470 /* 471 * Delete any caps that snuck into the previously active blog. (Hardcoded to blog 1 for now.) 472 * TODO: Get previous_blog_id. 473 */ 474 if ( ! is_super_admin( $user_id ) && 1 !== $user_id ) { 475 $wpdb->delete( 476 $wpdb->usermeta, 477 array( 478 'user_id' => $user_id, 479 'meta_key' => $wpdb->base_prefix . '1_capabilities', 480 ) 481 ); 482 } 483 } 484 } 485 endif; 486 487 /** 488 * Maybe enable pretty permalinks on installation. 489 * 490 * If after enabling pretty permalinks don't work, fallback to query-string permalinks. 491 * 492 * @since 4.2.0 493 * 494 * @global WP_Rewrite $wp_rewrite WordPress rewrite component. 495 * 496 * @return bool Whether pretty permalinks are enabled. False otherwise. 497 */ 498 function wp_install_maybe_enable_pretty_permalinks() { 499 global $wp_rewrite; 500 501 // Bail if a permalink structure is already enabled. 502 if ( get_option( 'permalink_structure' ) ) { 503 return true; 504 } 505 506 /* 507 * The Permalink structures to attempt. 508 * 509 * The first is designed for mod_rewrite or nginx rewriting. 510 * 511 * The second is PATHINFO-based permalinks for web server configurations 512 * without a true rewrite module enabled. 513 */ 514 $permalink_structures = array( 515 '/%year%/%monthnum%/%day%/%postname%/', 516 '/index.php/%year%/%monthnum%/%day%/%postname%/', 517 ); 518 519 foreach ( (array) $permalink_structures as $permalink_structure ) { 520 $wp_rewrite->set_permalink_structure( $permalink_structure ); 521 522 /* 523 * Flush rules with the hard option to force refresh of the web-server's 524 * rewrite config file (e.g. .htaccess or web.config). 525 */ 526 $wp_rewrite->flush_rules( true ); 527 528 $test_url = ''; 529 530 // Test against a real WordPress post. 531 $first_post = get_page_by_path( sanitize_title( _x( 'hello-world', 'Default post slug' ) ), OBJECT, 'post' ); 532 if ( $first_post ) { 533 $test_url = get_permalink( $first_post->ID ); 534 } 535 536 /* 537 * Send a request to the site, and check whether 538 * the 'X-Pingback' header is returned as expected. 539 * 540 * Uses wp_remote_get() instead of wp_remote_head() because web servers 541 * can block head requests. 542 */ 543 $response = wp_remote_get( $test_url, array( 'timeout' => 5 ) ); 544 $x_pingback_header = wp_remote_retrieve_header( $response, 'X-Pingback' ); 545 $pretty_permalinks = $x_pingback_header && get_bloginfo( 'pingback_url' ) === $x_pingback_header; 546 547 if ( $pretty_permalinks ) { 548 return true; 549 } 550 } 551 552 /* 553 * If it makes it this far, pretty permalinks failed. 554 * Fallback to query-string permalinks. 555 */ 556 $wp_rewrite->set_permalink_structure( '' ); 557 $wp_rewrite->flush_rules( true ); 558 559 return false; 560 } 561 562 if ( ! function_exists( 'wp_new_blog_notification' ) ) : 563 /** 564 * Notifies the site admin that the installation of WordPress is complete. 565 * 566 * Sends an email to the new administrator that the installation is complete 567 * and provides them with a record of their login credentials. 568 * 569 * @since 2.1.0 570 * 571 * @param string $blog_title Site title. 572 * @param string $blog_url Site URL. 573 * @param int $user_id Administrator's user ID. 574 * @param string $password Administrator's password. Note that a placeholder message is 575 * usually passed instead of the actual password. 576 */ 577 function wp_new_blog_notification( 578 $blog_title, 579 $blog_url, 580 $user_id, 581 #[\SensitiveParameter] 582 $password 583 ) { 584 $user = new WP_User( $user_id ); 585 $email = $user->user_email; 586 $name = $user->user_login; 587 $login_url = wp_login_url(); 588 589 $message = sprintf( 590 /* translators: New site notification email. 1: New site URL, 2: User login, 3: User password or password reset link, 4: Login URL. */ 591 __( 592 'Your new WordPress site has been successfully set up at: 593 594 %1$s 595 596 You can log in to the administrator account with the following information: 597 598 Username: %2$s 599 Password: %3$s 600 Log in here: %4$s 601 602 We hope you enjoy your new site. Thanks! 603 604 --The WordPress Team 605 https://wordpress.org/ 606 ' 607 ), 608 $blog_url, 609 $name, 610 $password, 611 $login_url 612 ); 613 614 $installed_email = array( 615 'to' => $email, 616 'subject' => __( 'New WordPress Site' ), 617 'message' => $message, 618 'headers' => '', 619 ); 620 621 /** 622 * Filters the contents of the email sent to the site administrator when WordPress is installed. 623 * 624 * @since 5.6.0 625 * 626 * @param array $installed_email { 627 * Used to build wp_mail(). 628 * 629 * @type string $to The email address of the recipient. 630 * @type string $subject The subject of the email. 631 * @type string $message The content of the email. 632 * @type string $headers Headers. 633 * } 634 * @param WP_User $user The site administrator user object. 635 * @param string $blog_title The site title. 636 * @param string $blog_url The site URL. 637 * @param string $password The site administrator's password. Note that a placeholder message 638 * is usually passed instead of the user's actual password. 639 */ 640 $installed_email = apply_filters( 'wp_installed_email', $installed_email, $user, $blog_title, $blog_url, $password ); 641 642 wp_mail( 643 $installed_email['to'], 644 $installed_email['subject'], 645 $installed_email['message'], 646 $installed_email['headers'] 647 ); 648 } 649 endif; 650 651 if ( ! function_exists( 'wp_upgrade' ) ) : 652 /** 653 * Runs WordPress Upgrade functions. 654 * 655 * Upgrades the database if needed during a site update. 656 * 657 * @since 2.1.0 658 * 659 * @global int $wp_current_db_version The old (current) database version. 660 * @global int $wp_db_version The new database version. 661 */ 662 function wp_upgrade() { 663 global $wp_current_db_version, $wp_db_version; 664 665 $wp_current_db_version = (int) __get_option( 'db_version' ); 666 667 // We are up to date. Nothing to do. 668 if ( $wp_db_version === $wp_current_db_version ) { 669 return; 670 } 671 672 if ( ! is_blog_installed() ) { 673 return; 674 } 675 676 wp_check_mysql_version(); 677 wp_cache_flush(); 678 pre_schema_upgrade(); 679 make_db_current_silent(); 680 upgrade_all(); 681 if ( is_multisite() && is_main_site() ) { 682 upgrade_network(); 683 } 684 wp_cache_flush(); 685 686 if ( is_multisite() ) { 687 update_site_meta( get_current_blog_id(), 'db_version', $wp_db_version ); 688 update_site_meta( get_current_blog_id(), 'db_last_updated', microtime() ); 689 } 690 691 delete_transient( 'wp_core_block_css_files' ); 692 693 /** 694 * Fires after a site is fully upgraded. 695 * 696 * @since 3.9.0 697 * 698 * @param int $wp_db_version The new $wp_db_version. 699 * @param int $wp_current_db_version The old (current) $wp_db_version. 700 */ 701 do_action( 'wp_upgrade', $wp_db_version, $wp_current_db_version ); 702 } 703 endif; 704 705 /** 706 * Functions to be called in installation and upgrade scripts. 707 * 708 * Contains conditional checks to determine which upgrade scripts to run, 709 * based on database version and WP version being updated-to. 710 * 711 * @ignore 712 * @since 1.0.1 713 * 714 * @global int $wp_current_db_version The old (current) database version. 715 * @global int $wp_db_version The new database version. 716 */ 717 function upgrade_all() { 718 global $wp_current_db_version, $wp_db_version; 719 720 $wp_current_db_version = (int) __get_option( 'db_version' ); 721 722 // We are up to date. Nothing to do. 723 if ( $wp_db_version === $wp_current_db_version ) { 724 return; 725 } 726 727 // If the version is not set in the DB, try to guess the version. 728 if ( empty( $wp_current_db_version ) ) { 729 $wp_current_db_version = 0; 730 731 // If the template option exists, we have 1.5. 732 $template = __get_option( 'template' ); 733 if ( ! empty( $template ) ) { 734 $wp_current_db_version = 2541; 735 } 736 } 737 738 if ( $wp_current_db_version < 6039 ) { 739 upgrade_230_options_table(); 740 } 741 742 populate_options(); 743 744 if ( $wp_current_db_version < 2541 ) { 745 upgrade_100(); 746 upgrade_101(); 747 upgrade_110(); 748 upgrade_130(); 749 } 750 751 if ( $wp_current_db_version < 3308 ) { 752 upgrade_160(); 753 } 754 755 if ( $wp_current_db_version < 4772 ) { 756 upgrade_210(); 757 } 758 759 if ( $wp_current_db_version < 4351 ) { 760 upgrade_old_slugs(); 761 } 762 763 if ( $wp_current_db_version < 5539 ) { 764 upgrade_230(); 765 } 766 767 if ( $wp_current_db_version < 6124 ) { 768 upgrade_230_old_tables(); 769 } 770 771 if ( $wp_current_db_version < 7499 ) { 772 upgrade_250(); 773 } 774 775 if ( $wp_current_db_version < 7935 ) { 776 upgrade_252(); 777 } 778 779 if ( $wp_current_db_version < 8201 ) { 780 upgrade_260(); 781 } 782 783 if ( $wp_current_db_version < 8989 ) { 784 upgrade_270(); 785 } 786 787 if ( $wp_current_db_version < 10360 ) { 788 upgrade_280(); 789 } 790 791 if ( $wp_current_db_version < 11958 ) { 792 upgrade_290(); 793 } 794 795 if ( $wp_current_db_version < 15260 ) { 796 upgrade_300(); 797 } 798 799 if ( $wp_current_db_version < 19389 ) { 800 upgrade_330(); 801 } 802 803 if ( $wp_current_db_version < 20080 ) { 804 upgrade_340(); 805 } 806 807 if ( $wp_current_db_version < 22422 ) { 808 upgrade_350(); 809 } 810 811 if ( $wp_current_db_version < 25824 ) { 812 upgrade_370(); 813 } 814 815 if ( $wp_current_db_version < 26148 ) { 816 upgrade_372(); 817 } 818 819 if ( $wp_current_db_version < 26691 ) { 820 upgrade_380(); 821 } 822 823 if ( $wp_current_db_version < 29630 ) { 824 upgrade_400(); 825 } 826 827 if ( $wp_current_db_version < 33055 ) { 828 upgrade_430(); 829 } 830 831 if ( $wp_current_db_version < 33056 ) { 832 upgrade_431(); 833 } 834 835 if ( $wp_current_db_version < 35700 ) { 836 upgrade_440(); 837 } 838 839 if ( $wp_current_db_version < 36686 ) { 840 upgrade_450(); 841 } 842 843 if ( $wp_current_db_version < 37965 ) { 844 upgrade_460(); 845 } 846 847 if ( $wp_current_db_version < 44719 ) { 848 upgrade_510(); 849 } 850 851 if ( $wp_current_db_version < 45744 ) { 852 upgrade_530(); 853 } 854 855 if ( $wp_current_db_version < 48575 ) { 856 upgrade_550(); 857 } 858 859 if ( $wp_current_db_version < 49752 ) { 860 upgrade_560(); 861 } 862 863 if ( $wp_current_db_version < 51917 ) { 864 upgrade_590(); 865 } 866 867 if ( $wp_current_db_version < 53011 ) { 868 upgrade_600(); 869 } 870 871 if ( $wp_current_db_version < 55853 ) { 872 upgrade_630(); 873 } 874 875 if ( $wp_current_db_version < 56657 ) { 876 upgrade_640(); 877 } 878 879 if ( $wp_current_db_version < 57155 ) { 880 upgrade_650(); 881 } 882 883 if ( $wp_current_db_version < 58975 ) { 884 upgrade_670(); 885 } 886 887 if ( $wp_current_db_version < 60421 ) { 888 upgrade_682(); 889 } 890 891 if ( $wp_current_db_version < 61644 ) { 892 upgrade_700(); 893 } 894 895 maybe_disable_link_manager(); 896 897 maybe_disable_automattic_widgets(); 898 899 update_option( 'db_version', $wp_db_version ); 900 update_option( 'db_upgraded', true ); 901 } 902 903 /** 904 * Execute changes made in WordPress 1.0. 905 * 906 * @ignore 907 * @since 1.0.0 908 * 909 * @global wpdb $wpdb WordPress database abstraction object. 910 */ 911 function upgrade_100() { 912 global $wpdb; 913 914 // Get the title and ID of every post, post_name to check if it already has a value. 915 $posts = $wpdb->get_results( "SELECT ID, post_title, post_name FROM $wpdb->posts WHERE post_name = ''" ); 916 if ( $posts ) { 917 foreach ( $posts as $post ) { 918 if ( '' === $post->post_name ) { 919 $newtitle = sanitize_title( $post->post_title ); 920 $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET post_name = %s WHERE ID = %d", $newtitle, $post->ID ) ); 921 } 922 } 923 } 924 925 $categories = $wpdb->get_results( "SELECT cat_ID, cat_name, category_nicename FROM $wpdb->categories" ); 926 foreach ( $categories as $category ) { 927 if ( '' === $category->category_nicename ) { 928 $newtitle = sanitize_title( $category->cat_name ); 929 $wpdb->update( $wpdb->categories, array( 'category_nicename' => $newtitle ), array( 'cat_ID' => $category->cat_ID ) ); 930 } 931 } 932 933 $sql = "UPDATE $wpdb->options 934 SET option_value = REPLACE(option_value, 'wp-links/links-images/', 'wp-images/links/') 935 WHERE option_name LIKE %s 936 AND option_value LIKE %s"; 937 $wpdb->query( $wpdb->prepare( $sql, $wpdb->esc_like( 'links_rating_image' ) . '%', $wpdb->esc_like( 'wp-links/links-images/' ) . '%' ) ); 938 939 $done_ids = $wpdb->get_results( "SELECT DISTINCT post_id FROM $wpdb->post2cat" ); 940 if ( $done_ids ) : 941 $done_posts = array(); 942 foreach ( $done_ids as $done_id ) : 943 $done_posts[] = $done_id->post_id; 944 endforeach; 945 $catwhere = ' AND ID NOT IN (' . implode( ',', $done_posts ) . ')'; 946 else : 947 $catwhere = ''; 948 endif; 949 950 $allposts = $wpdb->get_results( "SELECT ID, post_category FROM $wpdb->posts WHERE post_category != '0' $catwhere" ); 951 if ( $allposts ) : 952 foreach ( $allposts as $post ) { 953 // Check to see if it's already been imported. 954 $cat = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->post2cat WHERE post_id = %d AND category_id = %d", $post->ID, $post->post_category ) ); 955 if ( ! $cat && 0 !== (int) $post->post_category ) { // If there's no result. 956 $wpdb->insert( 957 $wpdb->post2cat, 958 array( 959 'post_id' => $post->ID, 960 'category_id' => $post->post_category, 961 ) 962 ); 963 } 964 } 965 endif; 966 } 967 968 /** 969 * Execute changes made in WordPress 1.0.1. 970 * 971 * @ignore 972 * @since 1.0.1 973 * 974 * @global wpdb $wpdb WordPress database abstraction object. 975 */ 976 function upgrade_101() { 977 global $wpdb; 978 979 // Clean up indices, add a few. 980 add_clean_index( $wpdb->posts, 'post_name' ); 981 add_clean_index( $wpdb->posts, 'post_status' ); 982 add_clean_index( $wpdb->categories, 'category_nicename' ); 983 add_clean_index( $wpdb->comments, 'comment_approved' ); 984 add_clean_index( $wpdb->comments, 'comment_post_ID' ); 985 add_clean_index( $wpdb->links, 'link_category' ); 986 add_clean_index( $wpdb->links, 'link_visible' ); 987 } 988 989 /** 990 * Execute changes made in WordPress 1.2. 991 * 992 * @ignore 993 * @since 1.2.0 994 * @since 6.8.0 User passwords are no longer hashed with md5. 995 * 996 * @global wpdb $wpdb WordPress database abstraction object. 997 */ 998 function upgrade_110() { 999 global $wpdb; 1000 1001 // Set user_nicename. 1002 $users = $wpdb->get_results( "SELECT ID, user_nickname, user_nicename FROM $wpdb->users" ); 1003 foreach ( $users as $user ) { 1004 if ( '' === $user->user_nicename ) { 1005 $newname = sanitize_title( $user->user_nickname ); 1006 $wpdb->update( $wpdb->users, array( 'user_nicename' => $newname ), array( 'ID' => $user->ID ) ); 1007 } 1008 } 1009 1010 // Get the GMT offset, we'll use that later on. 1011 $all_options = get_alloptions_110(); 1012 1013 $time_difference = $all_options->time_difference; 1014 1015 $server_time = time() + (int) gmdate( 'Z' ); 1016 $weblogger_time = $server_time + $time_difference * HOUR_IN_SECONDS; 1017 $gmt_time = time(); 1018 1019 $diff_gmt_server = ( $gmt_time - $server_time ) / HOUR_IN_SECONDS; 1020 $diff_weblogger_server = ( $weblogger_time - $server_time ) / HOUR_IN_SECONDS; 1021 $diff_gmt_weblogger = $diff_gmt_server - $diff_weblogger_server; 1022 $gmt_offset = -$diff_gmt_weblogger; 1023 1024 // Add a gmt_offset option, with value $gmt_offset. 1025 add_option( 'gmt_offset', $gmt_offset ); 1026 1027 /* 1028 * Check if we already set the GMT fields. If we did, then 1029 * MAX(post_date_gmt) can't be '0000-00-00 00:00:00'. 1030 * <michel_v> I just slapped myself silly for not thinking about it earlier. 1031 */ 1032 $got_gmt_fields = ( '0000-00-00 00:00:00' !== $wpdb->get_var( "SELECT MAX(post_date_gmt) FROM $wpdb->posts" ) ); 1033 1034 if ( ! $got_gmt_fields ) { 1035 1036 // Add or subtract time to all dates, to get GMT dates. 1037 $add_hours = (int) $diff_gmt_weblogger; 1038 $add_minutes = (int) ( 60 * ( $diff_gmt_weblogger - $add_hours ) ); 1039 $wpdb->query( "UPDATE $wpdb->posts SET post_date_gmt = DATE_ADD(post_date, INTERVAL '$add_hours:$add_minutes' HOUR_MINUTE)" ); 1040 $wpdb->query( "UPDATE $wpdb->posts SET post_modified = post_date" ); 1041 $wpdb->query( "UPDATE $wpdb->posts SET post_modified_gmt = DATE_ADD(post_modified, INTERVAL '$add_hours:$add_minutes' HOUR_MINUTE) WHERE post_modified != '0000-00-00 00:00:00'" ); 1042 $wpdb->query( "UPDATE $wpdb->comments SET comment_date_gmt = DATE_ADD(comment_date, INTERVAL '$add_hours:$add_minutes' HOUR_MINUTE)" ); 1043 $wpdb->query( "UPDATE $wpdb->users SET user_registered = DATE_ADD(user_registered, INTERVAL '$add_hours:$add_minutes' HOUR_MINUTE)" ); 1044 } 1045 } 1046 1047 /** 1048 * Execute changes made in WordPress 1.5. 1049 * 1050 * @ignore 1051 * @since 1.5.0 1052 * 1053 * @global wpdb $wpdb WordPress database abstraction object. 1054 */ 1055 function upgrade_130() { 1056 global $wpdb; 1057 1058 // Remove extraneous backslashes. 1059 $posts = $wpdb->get_results( "SELECT ID, post_title, post_content, post_excerpt, guid, post_date, post_name, post_status, post_author FROM $wpdb->posts" ); 1060 if ( $posts ) { 1061 foreach ( $posts as $post ) { 1062 $post_content = addslashes( deslash( $post->post_content ) ); 1063 $post_title = addslashes( deslash( $post->post_title ) ); 1064 $post_excerpt = addslashes( deslash( $post->post_excerpt ) ); 1065 if ( empty( $post->guid ) ) { 1066 $guid = get_permalink( $post->ID ); 1067 } else { 1068 $guid = $post->guid; 1069 } 1070 1071 $wpdb->update( $wpdb->posts, compact( 'post_title', 'post_content', 'post_excerpt', 'guid' ), array( 'ID' => $post->ID ) ); 1072 1073 } 1074 } 1075 1076 // Remove extraneous backslashes. 1077 $comments = $wpdb->get_results( "SELECT comment_ID, comment_author, comment_content FROM $wpdb->comments" ); 1078 if ( $comments ) { 1079 foreach ( $comments as $comment ) { 1080 $comment_content = deslash( $comment->comment_content ); 1081 $comment_author = deslash( $comment->comment_author ); 1082 1083 $wpdb->update( $wpdb->comments, compact( 'comment_content', 'comment_author' ), array( 'comment_ID' => $comment->comment_ID ) ); 1084 } 1085 } 1086 1087 // Remove extraneous backslashes. 1088 $links = $wpdb->get_results( "SELECT link_id, link_name, link_description FROM $wpdb->links" ); 1089 if ( $links ) { 1090 foreach ( $links as $link ) { 1091 $link_name = deslash( $link->link_name ); 1092 $link_description = deslash( $link->link_description ); 1093 1094 $wpdb->update( $wpdb->links, compact( 'link_name', 'link_description' ), array( 'link_id' => $link->link_id ) ); 1095 } 1096 } 1097 1098 $active_plugins = __get_option( 'active_plugins' ); 1099 1100 /* 1101 * If plugins are not stored in an array, they're stored in the old 1102 * newline separated format. Convert to new format. 1103 */ 1104 if ( ! is_array( $active_plugins ) ) { 1105 $active_plugins = explode( "\n", trim( $active_plugins ) ); 1106 update_option( 'active_plugins', $active_plugins ); 1107 } 1108 1109 // Obsolete tables. 1110 $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'optionvalues' ); 1111 $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'optiontypes' ); 1112 $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'optiongroups' ); 1113 $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'optiongroup_options' ); 1114 1115 // Update comments table to use comment_type. 1116 $wpdb->query( "UPDATE $wpdb->comments SET comment_type='trackback', comment_content = REPLACE(comment_content, '<trackback />', '') WHERE comment_content LIKE '<trackback />%'" ); 1117 $wpdb->query( "UPDATE $wpdb->comments SET comment_type='pingback', comment_content = REPLACE(comment_content, '<pingback />', '') WHERE comment_content LIKE '<pingback />%'" ); 1118 1119 // Some versions have multiple duplicate option_name rows with the same values. 1120 $options = $wpdb->get_results( "SELECT option_name, COUNT(option_name) AS dupes FROM `$wpdb->options` GROUP BY option_name" ); 1121 foreach ( $options as $option ) { 1122 if ( $option->dupes > 1 ) { // Could this be done in the query? 1123 $limit = $option->dupes - 1; 1124 $dupe_ids = $wpdb->get_col( $wpdb->prepare( "SELECT option_id FROM $wpdb->options WHERE option_name = %s LIMIT %d", $option->option_name, $limit ) ); 1125 if ( $dupe_ids ) { 1126 $dupe_ids = implode( ',', $dupe_ids ); 1127 $wpdb->query( "DELETE FROM $wpdb->options WHERE option_id IN ($dupe_ids)" ); 1128 } 1129 } 1130 } 1131 1132 make_site_theme(); 1133 } 1134 1135 /** 1136 * Execute changes made in WordPress 2.0. 1137 * 1138 * @ignore 1139 * @since 2.0.0 1140 * 1141 * @global wpdb $wpdb WordPress database abstraction object. 1142 * @global int $wp_current_db_version The old (current) database version. 1143 */ 1144 function upgrade_160() { 1145 global $wpdb, $wp_current_db_version; 1146 1147 populate_roles_160(); 1148 1149 $users = $wpdb->get_results( "SELECT * FROM $wpdb->users" ); 1150 foreach ( $users as $user ) : 1151 if ( ! empty( $user->user_firstname ) ) { 1152 update_user_meta( $user->ID, 'first_name', wp_slash( $user->user_firstname ) ); 1153 } 1154 if ( ! empty( $user->user_lastname ) ) { 1155 update_user_meta( $user->ID, 'last_name', wp_slash( $user->user_lastname ) ); 1156 } 1157 if ( ! empty( $user->user_nickname ) ) { 1158 update_user_meta( $user->ID, 'nickname', wp_slash( $user->user_nickname ) ); 1159 } 1160 if ( ! empty( $user->user_level ) ) { 1161 update_user_meta( $user->ID, $wpdb->prefix . 'user_level', $user->user_level ); 1162 } 1163 if ( ! empty( $user->user_icq ) ) { 1164 update_user_meta( $user->ID, 'icq', wp_slash( $user->user_icq ) ); 1165 } 1166 if ( ! empty( $user->user_aim ) ) { 1167 update_user_meta( $user->ID, 'aim', wp_slash( $user->user_aim ) ); 1168 } 1169 if ( ! empty( $user->user_msn ) ) { 1170 update_user_meta( $user->ID, 'msn', wp_slash( $user->user_msn ) ); 1171 } 1172 if ( ! empty( $user->user_yim ) ) { 1173 update_user_meta( $user->ID, 'yim', wp_slash( $user->user_icq ) ); 1174 } 1175 if ( ! empty( $user->user_description ) ) { 1176 update_user_meta( $user->ID, 'description', wp_slash( $user->user_description ) ); 1177 } 1178 1179 if ( isset( $user->user_idmode ) ) : 1180 $idmode = $user->user_idmode; 1181 if ( 'nickname' === $idmode ) { 1182 $id = $user->user_nickname; 1183 } 1184 if ( 'login' === $idmode ) { 1185 $id = $user->user_login; 1186 } 1187 if ( 'firstname' === $idmode ) { 1188 $id = $user->user_firstname; 1189 } 1190 if ( 'lastname' === $idmode ) { 1191 $id = $user->user_lastname; 1192 } 1193 if ( 'namefl' === $idmode ) { 1194 $id = $user->user_firstname . ' ' . $user->user_lastname; 1195 } 1196 if ( 'namelf' === $idmode ) { 1197 $id = $user->user_lastname . ' ' . $user->user_firstname; 1198 } 1199 if ( ! $idmode ) { 1200 $id = $user->user_nickname; 1201 } 1202 $wpdb->update( $wpdb->users, array( 'display_name' => $id ), array( 'ID' => $user->ID ) ); 1203 endif; 1204 1205 // FIXME: RESET_CAPS is temporary code to reset roles and caps if flag is set. 1206 $caps = get_user_meta( $user->ID, $wpdb->prefix . 'capabilities' ); 1207 if ( empty( $caps ) || defined( 'RESET_CAPS' ) ) { 1208 $level = get_user_meta( $user->ID, $wpdb->prefix . 'user_level', true ); 1209 $role = translate_level_to_role( $level ); 1210 update_user_meta( $user->ID, $wpdb->prefix . 'capabilities', array( $role => true ) ); 1211 } 1212 1213 endforeach; 1214 $old_user_fields = array( 'user_firstname', 'user_lastname', 'user_icq', 'user_aim', 'user_msn', 'user_yim', 'user_idmode', 'user_ip', 'user_domain', 'user_browser', 'user_description', 'user_nickname', 'user_level' ); 1215 $wpdb->hide_errors(); 1216 foreach ( $old_user_fields as $old ) { 1217 $wpdb->query( "ALTER TABLE $wpdb->users DROP $old" ); 1218 } 1219 $wpdb->show_errors(); 1220 1221 // Populate comment_count field of posts table. 1222 $comments = $wpdb->get_results( "SELECT comment_post_ID, COUNT(*) as c FROM $wpdb->comments WHERE comment_approved = '1' GROUP BY comment_post_ID" ); 1223 if ( is_array( $comments ) ) { 1224 foreach ( $comments as $comment ) { 1225 $wpdb->update( $wpdb->posts, array( 'comment_count' => $comment->c ), array( 'ID' => $comment->comment_post_ID ) ); 1226 } 1227 } 1228 1229 /* 1230 * Some alpha versions used a post status of object instead of attachment 1231 * and put the mime type in post_type instead of post_mime_type. 1232 */ 1233 if ( $wp_current_db_version > 2541 && $wp_current_db_version <= 3091 ) { 1234 $objects = $wpdb->get_results( "SELECT ID, post_type FROM $wpdb->posts WHERE post_status = 'object'" ); 1235 foreach ( $objects as $object ) { 1236 $wpdb->update( 1237 $wpdb->posts, 1238 array( 1239 'post_status' => 'attachment', 1240 'post_mime_type' => $object->post_type, 1241 'post_type' => '', 1242 ), 1243 array( 'ID' => $object->ID ) 1244 ); 1245 1246 $meta = get_post_meta( $object->ID, 'imagedata', true ); 1247 if ( ! empty( $meta['file'] ) ) { 1248 update_attached_file( $object->ID, $meta['file'] ); 1249 } 1250 } 1251 } 1252 } 1253 1254 /** 1255 * Execute changes made in WordPress 2.1. 1256 * 1257 * @ignore 1258 * @since 2.1.0 1259 * 1260 * @global int $wp_current_db_version The old (current) database version. 1261 * @global wpdb $wpdb WordPress database abstraction object. 1262 */ 1263 function upgrade_210() { 1264 global $wp_current_db_version, $wpdb; 1265 1266 if ( $wp_current_db_version < 3506 ) { 1267 // Update status and type. 1268 $posts = $wpdb->get_results( "SELECT ID, post_status FROM $wpdb->posts" ); 1269 1270 if ( ! empty( $posts ) ) { 1271 foreach ( $posts as $post ) { 1272 $status = $post->post_status; 1273 $type = 'post'; 1274 1275 if ( 'static' === $status ) { 1276 $status = 'publish'; 1277 $type = 'page'; 1278 } elseif ( 'attachment' === $status ) { 1279 $status = 'inherit'; 1280 $type = 'attachment'; 1281 } 1282 1283 $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET post_status = %s, post_type = %s WHERE ID = %d", $status, $type, $post->ID ) ); 1284 } 1285 } 1286 } 1287 1288 if ( $wp_current_db_version < 3845 ) { 1289 populate_roles_210(); 1290 } 1291 1292 if ( $wp_current_db_version < 3531 ) { 1293 // Give future posts a post_status of future. 1294 $now = gmdate( 'Y-m-d H:i:59' ); 1295 $wpdb->query( "UPDATE $wpdb->posts SET post_status = 'future' WHERE post_status = 'publish' AND post_date_gmt > '$now'" ); 1296 1297 $posts = $wpdb->get_results( "SELECT ID, post_date FROM $wpdb->posts WHERE post_status ='future'" ); 1298 if ( ! empty( $posts ) ) { 1299 foreach ( $posts as $post ) { 1300 wp_schedule_single_event( mysql2date( 'U', $post->post_date, false ), 'publish_future_post', array( $post->ID ) ); 1301 } 1302 } 1303 } 1304 } 1305 1306 /** 1307 * Execute changes made in WordPress 2.3. 1308 * 1309 * @ignore 1310 * @since 2.3.0 1311 * 1312 * @global int $wp_current_db_version The old (current) database version. 1313 * @global wpdb $wpdb WordPress database abstraction object. 1314 */ 1315 function upgrade_230() { 1316 global $wp_current_db_version, $wpdb; 1317 1318 if ( $wp_current_db_version < 5200 ) { 1319 populate_roles_230(); 1320 } 1321 1322 // Convert categories to terms. 1323 $tt_ids = array(); 1324 $have_tags = false; 1325 $categories = $wpdb->get_results( "SELECT * FROM $wpdb->categories ORDER BY cat_ID" ); 1326 foreach ( $categories as $category ) { 1327 $term_id = (int) $category->cat_ID; 1328 $name = $category->cat_name; 1329 $description = $category->category_description; 1330 $slug = $category->category_nicename; 1331 $parent = $category->category_parent; 1332 $term_group = 0; 1333 1334 // Associate terms with the same slug in a term group and make slugs unique. 1335 $exists = $wpdb->get_results( $wpdb->prepare( "SELECT term_id, term_group FROM $wpdb->terms WHERE slug = %s", $slug ) ); 1336 if ( $exists ) { 1337 $term_group = $exists[0]->term_group; 1338 $id = $exists[0]->term_id; 1339 $num = 2; 1340 do { 1341 $alt_slug = $slug . "-$num"; 1342 ++$num; 1343 $slug_check = $wpdb->get_var( $wpdb->prepare( "SELECT slug FROM $wpdb->terms WHERE slug = %s", $alt_slug ) ); 1344 } while ( $slug_check ); 1345 1346 $slug = $alt_slug; 1347 1348 if ( empty( $term_group ) ) { 1349 $term_group = $wpdb->get_var( "SELECT MAX(term_group) FROM $wpdb->terms GROUP BY term_group" ) + 1; 1350 $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->terms SET term_group = %d WHERE term_id = %d", $term_group, $id ) ); 1351 } 1352 } 1353 1354 $wpdb->query( 1355 $wpdb->prepare( 1356 "INSERT INTO $wpdb->terms (term_id, name, slug, term_group) VALUES 1357 (%d, %s, %s, %d)", 1358 $term_id, 1359 $name, 1360 $slug, 1361 $term_group 1362 ) 1363 ); 1364 1365 $count = 0; 1366 if ( ! empty( $category->category_count ) ) { 1367 $count = (int) $category->category_count; 1368 $taxonomy = 'category'; 1369 $wpdb->query( $wpdb->prepare( "INSERT INTO $wpdb->term_taxonomy (term_id, taxonomy, description, parent, count) VALUES ( %d, %s, %s, %d, %d)", $term_id, $taxonomy, $description, $parent, $count ) ); 1370 $tt_ids[ $term_id ][ $taxonomy ] = (int) $wpdb->insert_id; 1371 } 1372 1373 if ( ! empty( $category->link_count ) ) { 1374 $count = (int) $category->link_count; 1375 $taxonomy = 'link_category'; 1376 $wpdb->query( $wpdb->prepare( "INSERT INTO $wpdb->term_taxonomy (term_id, taxonomy, description, parent, count) VALUES ( %d, %s, %s, %d, %d)", $term_id, $taxonomy, $description, $parent, $count ) ); 1377 $tt_ids[ $term_id ][ $taxonomy ] = (int) $wpdb->insert_id; 1378 } 1379 1380 if ( ! empty( $category->tag_count ) ) { 1381 $have_tags = true; 1382 $count = (int) $category->tag_count; 1383 $taxonomy = 'post_tag'; 1384 $wpdb->insert( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent', 'count' ) ); 1385 $tt_ids[ $term_id ][ $taxonomy ] = (int) $wpdb->insert_id; 1386 } 1387 1388 if ( empty( $count ) ) { 1389 $count = 0; 1390 $taxonomy = 'category'; 1391 $wpdb->insert( $wpdb->term_taxonomy, compact( 'term_id', 'taxonomy', 'description', 'parent', 'count' ) ); 1392 $tt_ids[ $term_id ][ $taxonomy ] = (int) $wpdb->insert_id; 1393 } 1394 } 1395 1396 $select = 'post_id, category_id'; 1397 if ( $have_tags ) { 1398 $select .= ', rel_type'; 1399 } 1400 1401 $posts = $wpdb->get_results( "SELECT $select FROM $wpdb->post2cat GROUP BY post_id, category_id" ); 1402 foreach ( $posts as $post ) { 1403 $post_id = (int) $post->post_id; 1404 $term_id = (int) $post->category_id; 1405 $taxonomy = 'category'; 1406 if ( ! empty( $post->rel_type ) && 'tag' === $post->rel_type ) { 1407 $taxonomy = 'tag'; 1408 } 1409 $tt_id = $tt_ids[ $term_id ][ $taxonomy ]; 1410 if ( empty( $tt_id ) ) { 1411 continue; 1412 } 1413 1414 $wpdb->insert( 1415 $wpdb->term_relationships, 1416 array( 1417 'object_id' => $post_id, 1418 'term_taxonomy_id' => $tt_id, 1419 ) 1420 ); 1421 } 1422 1423 // < 3570 we used linkcategories. >= 3570 we used categories and link2cat. 1424 if ( $wp_current_db_version < 3570 ) { 1425 /* 1426 * Create link_category terms for link categories. Create a map of link 1427 * category IDs to link_category terms. 1428 */ 1429 $link_cat_id_map = array(); 1430 $default_link_cat = 0; 1431 $tt_ids = array(); 1432 $link_cats = $wpdb->get_results( 'SELECT cat_id, cat_name FROM ' . $wpdb->prefix . 'linkcategories' ); 1433 foreach ( $link_cats as $category ) { 1434 $cat_id = (int) $category->cat_id; 1435 $term_id = 0; 1436 $name = wp_slash( $category->cat_name ); 1437 $slug = sanitize_title( $name ); 1438 $term_group = 0; 1439 1440 // Associate terms with the same slug in a term group and make slugs unique. 1441 $exists = $wpdb->get_results( $wpdb->prepare( "SELECT term_id, term_group FROM $wpdb->terms WHERE slug = %s", $slug ) ); 1442 if ( $exists ) { 1443 $term_group = $exists[0]->term_group; 1444 $term_id = $exists[0]->term_id; 1445 } 1446 1447 if ( empty( $term_id ) ) { 1448 $wpdb->insert( $wpdb->terms, compact( 'name', 'slug', 'term_group' ) ); 1449 $term_id = (int) $wpdb->insert_id; 1450 } 1451 1452 $link_cat_id_map[ $cat_id ] = $term_id; 1453 $default_link_cat = $term_id; 1454 1455 $wpdb->insert( 1456 $wpdb->term_taxonomy, 1457 array( 1458 'term_id' => $term_id, 1459 'taxonomy' => 'link_category', 1460 'description' => '', 1461 'parent' => 0, 1462 'count' => 0, 1463 ) 1464 ); 1465 $tt_ids[ $term_id ] = (int) $wpdb->insert_id; 1466 } 1467 1468 // Associate links to categories. 1469 $links = $wpdb->get_results( "SELECT link_id, link_category FROM $wpdb->links" ); 1470 if ( ! empty( $links ) ) { 1471 foreach ( $links as $link ) { 1472 if ( 0 === (int) $link->link_category ) { 1473 continue; 1474 } 1475 if ( ! isset( $link_cat_id_map[ $link->link_category ] ) ) { 1476 continue; 1477 } 1478 $term_id = $link_cat_id_map[ $link->link_category ]; 1479 $tt_id = $tt_ids[ $term_id ]; 1480 if ( empty( $tt_id ) ) { 1481 continue; 1482 } 1483 1484 $wpdb->insert( 1485 $wpdb->term_relationships, 1486 array( 1487 'object_id' => $link->link_id, 1488 'term_taxonomy_id' => $tt_id, 1489 ) 1490 ); 1491 } 1492 } 1493 1494 // Set default to the last category we grabbed during the upgrade loop. 1495 update_option( 'default_link_category', $default_link_cat ); 1496 } else { 1497 $links = $wpdb->get_results( "SELECT link_id, category_id FROM $wpdb->link2cat GROUP BY link_id, category_id" ); 1498 foreach ( $links as $link ) { 1499 $link_id = (int) $link->link_id; 1500 $term_id = (int) $link->category_id; 1501 $taxonomy = 'link_category'; 1502 $tt_id = $tt_ids[ $term_id ][ $taxonomy ]; 1503 if ( empty( $tt_id ) ) { 1504 continue; 1505 } 1506 $wpdb->insert( 1507 $wpdb->term_relationships, 1508 array( 1509 'object_id' => $link_id, 1510 'term_taxonomy_id' => $tt_id, 1511 ) 1512 ); 1513 } 1514 } 1515 1516 if ( $wp_current_db_version < 4772 ) { 1517 // Obsolete linkcategories table. 1518 $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'linkcategories' ); 1519 } 1520 1521 // Recalculate all counts. 1522 $terms = $wpdb->get_results( "SELECT term_taxonomy_id, taxonomy FROM $wpdb->term_taxonomy" ); 1523 foreach ( (array) $terms as $term ) { 1524 if ( 'post_tag' === $term->taxonomy || 'category' === $term->taxonomy ) { 1525 $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships, $wpdb->posts WHERE $wpdb->posts.ID = $wpdb->term_relationships.object_id AND post_status = 'publish' AND post_type = 'post' AND term_taxonomy_id = %d", $term->term_taxonomy_id ) ); 1526 } else { 1527 $count = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->term_relationships WHERE term_taxonomy_id = %d", $term->term_taxonomy_id ) ); 1528 } 1529 $wpdb->update( $wpdb->term_taxonomy, array( 'count' => $count ), array( 'term_taxonomy_id' => $term->term_taxonomy_id ) ); 1530 } 1531 } 1532 1533 /** 1534 * Remove old options from the database. 1535 * 1536 * @ignore 1537 * @since 2.3.0 1538 * 1539 * @global wpdb $wpdb WordPress database abstraction object. 1540 */ 1541 function upgrade_230_options_table() { 1542 global $wpdb; 1543 $old_options_fields = array( 'option_can_override', 'option_type', 'option_width', 'option_height', 'option_description', 'option_admin_level' ); 1544 $wpdb->hide_errors(); 1545 foreach ( $old_options_fields as $old ) { 1546 $wpdb->query( "ALTER TABLE $wpdb->options DROP $old" ); 1547 } 1548 $wpdb->show_errors(); 1549 } 1550 1551 /** 1552 * Remove old categories, link2cat, and post2cat database tables. 1553 * 1554 * @ignore 1555 * @since 2.3.0 1556 * 1557 * @global wpdb $wpdb WordPress database abstraction object. 1558 */ 1559 function upgrade_230_old_tables() { 1560 global $wpdb; 1561 $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'categories' ); 1562 $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'link2cat' ); 1563 $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'post2cat' ); 1564 } 1565 1566 /** 1567 * Upgrade old slugs made in version 2.2. 1568 * 1569 * @ignore 1570 * @since 2.2.0 1571 * 1572 * @global wpdb $wpdb WordPress database abstraction object. 1573 */ 1574 function upgrade_old_slugs() { 1575 // Upgrade people who were using the Redirect Old Slugs plugin. 1576 global $wpdb; 1577 $wpdb->query( "UPDATE $wpdb->postmeta SET meta_key = '_wp_old_slug' WHERE meta_key = 'old_slug'" ); 1578 } 1579 1580 /** 1581 * Execute changes made in WordPress 2.5.0. 1582 * 1583 * @ignore 1584 * @since 2.5.0 1585 * 1586 * @global int $wp_current_db_version The old (current) database version. 1587 */ 1588 function upgrade_250() { 1589 global $wp_current_db_version; 1590 1591 if ( $wp_current_db_version < 6689 ) { 1592 populate_roles_250(); 1593 } 1594 } 1595 1596 /** 1597 * Execute changes made in WordPress 2.5.2. 1598 * 1599 * @ignore 1600 * @since 2.5.2 1601 * 1602 * @global wpdb $wpdb WordPress database abstraction object. 1603 */ 1604 function upgrade_252() { 1605 global $wpdb; 1606 1607 $wpdb->query( "UPDATE $wpdb->users SET user_activation_key = ''" ); 1608 } 1609 1610 /** 1611 * Execute changes made in WordPress 2.6. 1612 * 1613 * @ignore 1614 * @since 2.6.0 1615 * 1616 * @global int $wp_current_db_version The old (current) database version. 1617 */ 1618 function upgrade_260() { 1619 global $wp_current_db_version; 1620 1621 if ( $wp_current_db_version < 8000 ) { 1622 populate_roles_260(); 1623 } 1624 } 1625 1626 /** 1627 * Execute changes made in WordPress 2.7. 1628 * 1629 * @ignore 1630 * @since 2.7.0 1631 * 1632 * @global int $wp_current_db_version The old (current) database version. 1633 * @global wpdb $wpdb WordPress database abstraction object. 1634 */ 1635 function upgrade_270() { 1636 global $wp_current_db_version, $wpdb; 1637 1638 if ( $wp_current_db_version < 8980 ) { 1639 populate_roles_270(); 1640 } 1641 1642 // Update post_date for unpublished posts with empty timestamp. 1643 if ( $wp_current_db_version < 8921 ) { 1644 $wpdb->query( "UPDATE $wpdb->posts SET post_date = post_modified WHERE post_date = '0000-00-00 00:00:00'" ); 1645 } 1646 } 1647 1648 /** 1649 * Execute changes made in WordPress 2.8. 1650 * 1651 * @ignore 1652 * @since 2.8.0 1653 * 1654 * @global int $wp_current_db_version The old (current) database version. 1655 * @global wpdb $wpdb WordPress database abstraction object. 1656 */ 1657 function upgrade_280() { 1658 global $wp_current_db_version, $wpdb; 1659 1660 if ( $wp_current_db_version < 10360 ) { 1661 populate_roles_280(); 1662 } 1663 if ( is_multisite() ) { 1664 $start = 0; 1665 while ( $rows = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options ORDER BY option_id LIMIT $start, 20" ) ) { 1666 foreach ( $rows as $row ) { 1667 $value = maybe_unserialize( $row->option_value ); 1668 if ( $value === $row->option_value ) { 1669 $value = stripslashes( $value ); 1670 } 1671 if ( $value !== $row->option_value ) { 1672 update_option( $row->option_name, $value ); 1673 } 1674 } 1675 $start += 20; 1676 } 1677 clean_blog_cache( get_current_blog_id() ); 1678 } 1679 } 1680 1681 /** 1682 * Execute changes made in WordPress 2.9. 1683 * 1684 * @ignore 1685 * @since 2.9.0 1686 * 1687 * @global int $wp_current_db_version The old (current) database version. 1688 */ 1689 function upgrade_290() { 1690 global $wp_current_db_version; 1691 1692 if ( $wp_current_db_version < 11958 ) { 1693 /* 1694 * Previously, setting depth to 1 would redundantly disable threading, 1695 * but now 2 is the minimum depth to avoid confusion. 1696 */ 1697 if ( 1 === (int) get_option( 'thread_comments_depth' ) ) { 1698 update_option( 'thread_comments_depth', 2 ); 1699 update_option( 'thread_comments', 0 ); 1700 } 1701 } 1702 } 1703 1704 /** 1705 * Execute changes made in WordPress 3.0. 1706 * 1707 * @ignore 1708 * @since 3.0.0 1709 * 1710 * @global int $wp_current_db_version The old (current) database version. 1711 * @global wpdb $wpdb WordPress database abstraction object. 1712 */ 1713 function upgrade_300() { 1714 global $wp_current_db_version, $wpdb; 1715 1716 if ( $wp_current_db_version < 15093 ) { 1717 populate_roles_300(); 1718 } 1719 1720 if ( $wp_current_db_version < 14139 && is_multisite() && is_main_site() && ! defined( 'MULTISITE' ) && get_site_option( 'siteurl' ) === false ) { 1721 add_site_option( 'siteurl', '' ); 1722 } 1723 1724 // 3.0 screen options key name changes. 1725 if ( wp_should_upgrade_global_tables() ) { 1726 $sql = "DELETE FROM $wpdb->usermeta 1727 WHERE meta_key LIKE %s 1728 OR meta_key LIKE %s 1729 OR meta_key LIKE %s 1730 OR meta_key LIKE %s 1731 OR meta_key LIKE %s 1732 OR meta_key LIKE %s 1733 OR meta_key = 'manageedittagscolumnshidden' 1734 OR meta_key = 'managecategoriescolumnshidden' 1735 OR meta_key = 'manageedit-tagscolumnshidden' 1736 OR meta_key = 'manageeditcolumnshidden' 1737 OR meta_key = 'categories_per_page' 1738 OR meta_key = 'edit_tags_per_page'"; 1739 $prefix = $wpdb->esc_like( $wpdb->base_prefix ); 1740 $wpdb->query( 1741 $wpdb->prepare( 1742 $sql, 1743 $prefix . '%' . $wpdb->esc_like( 'meta-box-hidden' ) . '%', 1744 $prefix . '%' . $wpdb->esc_like( 'closedpostboxes' ) . '%', 1745 $prefix . '%' . $wpdb->esc_like( 'manage-' ) . '%' . $wpdb->esc_like( '-columns-hidden' ) . '%', 1746 $prefix . '%' . $wpdb->esc_like( 'meta-box-order' ) . '%', 1747 $prefix . '%' . $wpdb->esc_like( 'metaboxorder' ) . '%', 1748 $prefix . '%' . $wpdb->esc_like( 'screen_layout' ) . '%' 1749 ) 1750 ); 1751 } 1752 } 1753 1754 /** 1755 * Execute changes made in WordPress 3.3. 1756 * 1757 * @ignore 1758 * @since 3.3.0 1759 * 1760 * @global int $wp_current_db_version The old (current) database version. 1761 * @global wpdb $wpdb WordPress database abstraction object. 1762 * @global array $wp_registered_widgets 1763 * @global array $sidebars_widgets 1764 */ 1765 function upgrade_330() { 1766 global $wp_current_db_version, $wpdb, $wp_registered_widgets, $sidebars_widgets; 1767 1768 if ( $wp_current_db_version < 19061 && wp_should_upgrade_global_tables() ) { 1769 $wpdb->query( "DELETE FROM $wpdb->usermeta WHERE meta_key IN ('show_admin_bar_admin', 'plugins_last_view')" ); 1770 } 1771 1772 if ( $wp_current_db_version >= 11548 ) { 1773 return; 1774 } 1775 1776 $sidebars_widgets = get_option( 'sidebars_widgets', array() ); 1777 $_sidebars_widgets = array(); 1778 1779 if ( isset( $sidebars_widgets['wp_inactive_widgets'] ) || empty( $sidebars_widgets ) ) { 1780 $sidebars_widgets['array_version'] = 3; 1781 } elseif ( ! isset( $sidebars_widgets['array_version'] ) ) { 1782 $sidebars_widgets['array_version'] = 1; 1783 } 1784 1785 switch ( $sidebars_widgets['array_version'] ) { 1786 case 1: 1787 foreach ( (array) $sidebars_widgets as $index => $sidebar ) { 1788 if ( is_array( $sidebar ) ) { 1789 foreach ( (array) $sidebar as $i => $name ) { 1790 $id = strtolower( $name ); 1791 if ( isset( $wp_registered_widgets[ $id ] ) ) { 1792 $_sidebars_widgets[ $index ][ $i ] = $id; 1793 continue; 1794 } 1795 1796 $id = sanitize_title( $name ); 1797 if ( isset( $wp_registered_widgets[ $id ] ) ) { 1798 $_sidebars_widgets[ $index ][ $i ] = $id; 1799 continue; 1800 } 1801 1802 $found = false; 1803 1804 foreach ( $wp_registered_widgets as $widget_id => $widget ) { 1805 if ( strtolower( $widget['name'] ) === strtolower( $name ) ) { 1806 $_sidebars_widgets[ $index ][ $i ] = $widget['id']; 1807 1808 $found = true; 1809 break; 1810 } elseif ( sanitize_title( $widget['name'] ) === sanitize_title( $name ) ) { 1811 $_sidebars_widgets[ $index ][ $i ] = $widget['id']; 1812 1813 $found = true; 1814 break; 1815 } 1816 } 1817 1818 if ( $found ) { 1819 continue; 1820 } 1821 1822 unset( $_sidebars_widgets[ $index ][ $i ] ); 1823 } 1824 } 1825 } 1826 $_sidebars_widgets['array_version'] = 2; 1827 $sidebars_widgets = $_sidebars_widgets; 1828 unset( $_sidebars_widgets ); 1829 1830 // Intentional fall-through to upgrade to the next version. 1831 case 2: 1832 $sidebars_widgets = retrieve_widgets(); 1833 $sidebars_widgets['array_version'] = 3; 1834 update_option( 'sidebars_widgets', $sidebars_widgets ); 1835 } 1836 } 1837 1838 /** 1839 * Execute changes made in WordPress 3.4. 1840 * 1841 * @ignore 1842 * @since 3.4.0 1843 * 1844 * @global int $wp_current_db_version The old (current) database version. 1845 * @global wpdb $wpdb WordPress database abstraction object. 1846 */ 1847 function upgrade_340() { 1848 global $wp_current_db_version, $wpdb; 1849 1850 if ( $wp_current_db_version < 19798 ) { 1851 $wpdb->hide_errors(); 1852 $wpdb->query( "ALTER TABLE $wpdb->options DROP COLUMN blog_id" ); 1853 $wpdb->show_errors(); 1854 } 1855 1856 if ( $wp_current_db_version < 19799 ) { 1857 $wpdb->hide_errors(); 1858 $wpdb->query( "ALTER TABLE $wpdb->comments DROP INDEX comment_approved" ); 1859 $wpdb->show_errors(); 1860 } 1861 1862 if ( $wp_current_db_version < 20022 && wp_should_upgrade_global_tables() ) { 1863 $wpdb->query( "DELETE FROM $wpdb->usermeta WHERE meta_key = 'themes_last_view'" ); 1864 } 1865 1866 if ( $wp_current_db_version < 20080 ) { 1867 if ( 'yes' === $wpdb->get_var( "SELECT autoload FROM $wpdb->options WHERE option_name = 'uninstall_plugins'" ) ) { 1868 $uninstall_plugins = get_option( 'uninstall_plugins' ); 1869 delete_option( 'uninstall_plugins' ); 1870 add_option( 'uninstall_plugins', $uninstall_plugins, '', false ); 1871 } 1872 } 1873 } 1874 1875 /** 1876 * Execute changes made in WordPress 3.5. 1877 * 1878 * @ignore 1879 * @since 3.5.0 1880 * 1881 * @global int $wp_current_db_version The old (current) database version. 1882 * @global wpdb $wpdb WordPress database abstraction object. 1883 */ 1884 function upgrade_350() { 1885 global $wp_current_db_version, $wpdb; 1886 1887 if ( $wp_current_db_version < 22006 && $wpdb->get_var( "SELECT link_id FROM $wpdb->links LIMIT 1" ) ) { 1888 update_option( 'link_manager_enabled', 1 ); // Previously set to 0 by populate_options(). 1889 } 1890 1891 if ( $wp_current_db_version < 21811 && wp_should_upgrade_global_tables() ) { 1892 $meta_keys = array(); 1893 foreach ( array_merge( get_post_types(), get_taxonomies() ) as $name ) { 1894 if ( str_contains( $name, '-' ) ) { 1895 $meta_keys[] = 'edit_' . str_replace( '-', '_', $name ) . '_per_page'; 1896 } 1897 } 1898 if ( $meta_keys ) { 1899 $meta_keys = implode( "', '", $meta_keys ); 1900 $wpdb->query( "DELETE FROM $wpdb->usermeta WHERE meta_key IN ('$meta_keys')" ); 1901 } 1902 } 1903 1904 if ( $wp_current_db_version < 22422 ) { 1905 $term = get_term_by( 'slug', 'post-format-standard', 'post_format' ); 1906 if ( $term ) { 1907 wp_delete_term( $term->term_id, 'post_format' ); 1908 } 1909 } 1910 } 1911 1912 /** 1913 * Execute changes made in WordPress 3.7. 1914 * 1915 * @ignore 1916 * @since 3.7.0 1917 * 1918 * @global int $wp_current_db_version The old (current) database version. 1919 */ 1920 function upgrade_370() { 1921 global $wp_current_db_version; 1922 1923 if ( $wp_current_db_version < 25824 ) { 1924 wp_clear_scheduled_hook( 'wp_auto_updates_maybe_update' ); 1925 } 1926 } 1927 1928 /** 1929 * Execute changes made in WordPress 3.7.2. 1930 * 1931 * @ignore 1932 * @since 3.7.2 1933 * 1934 * @global int $wp_current_db_version The old (current) database version. 1935 */ 1936 function upgrade_372() { 1937 global $wp_current_db_version; 1938 1939 if ( $wp_current_db_version < 26148 ) { 1940 wp_clear_scheduled_hook( 'wp_maybe_auto_update' ); 1941 } 1942 } 1943 1944 /** 1945 * Execute changes made in WordPress 3.8.0. 1946 * 1947 * @ignore 1948 * @since 3.8.0 1949 * 1950 * @global int $wp_current_db_version The old (current) database version. 1951 */ 1952 function upgrade_380() { 1953 global $wp_current_db_version; 1954 1955 if ( $wp_current_db_version < 26691 ) { 1956 deactivate_plugins( array( 'mp6/mp6.php' ), true ); 1957 } 1958 } 1959 1960 /** 1961 * Execute changes made in WordPress 4.0.0. 1962 * 1963 * @ignore 1964 * @since 4.0.0 1965 * 1966 * @global int $wp_current_db_version The old (current) database version. 1967 */ 1968 function upgrade_400() { 1969 global $wp_current_db_version; 1970 1971 if ( $wp_current_db_version < 29630 ) { 1972 if ( ! is_multisite() && false === get_option( 'WPLANG' ) ) { 1973 if ( defined( 'WPLANG' ) && ( '' !== WPLANG ) && in_array( WPLANG, get_available_languages(), true ) ) { 1974 update_option( 'WPLANG', WPLANG ); 1975 } else { 1976 update_option( 'WPLANG', '' ); 1977 } 1978 } 1979 } 1980 } 1981 1982 /** 1983 * Execute changes made in WordPress 4.2.0. 1984 * 1985 * @ignore 1986 * @since 4.2.0 1987 */ 1988 function upgrade_420() {} 1989 1990 /** 1991 * Executes changes made in WordPress 4.3.0. 1992 * 1993 * @ignore 1994 * @since 4.3.0 1995 * 1996 * @global int $wp_current_db_version The old (current) database version. 1997 * @global wpdb $wpdb WordPress database abstraction object. 1998 */ 1999 function upgrade_430() { 2000 global $wp_current_db_version, $wpdb; 2001 2002 if ( $wp_current_db_version < 32364 ) { 2003 upgrade_430_fix_comments(); 2004 } 2005 2006 // Shared terms are split in a separate process. 2007 if ( $wp_current_db_version < 32814 ) { 2008 update_option( 'finished_splitting_shared_terms', 0 ); 2009 wp_schedule_single_event( time() + ( 1 * MINUTE_IN_SECONDS ), 'wp_split_shared_term_batch' ); 2010 } 2011 2012 if ( $wp_current_db_version < 33055 && 'utf8mb4' === $wpdb->charset ) { 2013 if ( is_multisite() ) { 2014 $tables = $wpdb->tables( 'blog' ); 2015 } else { 2016 $tables = $wpdb->tables( 'all' ); 2017 if ( ! wp_should_upgrade_global_tables() ) { 2018 $global_tables = $wpdb->tables( 'global' ); 2019 $tables = array_diff_assoc( $tables, $global_tables ); 2020 } 2021 } 2022 2023 foreach ( $tables as $table ) { 2024 maybe_convert_table_to_utf8mb4( $table ); 2025 } 2026 } 2027 } 2028 2029 /** 2030 * Executes comments changes made in WordPress 4.3.0. 2031 * 2032 * @ignore 2033 * @since 4.3.0 2034 * 2035 * @global wpdb $wpdb WordPress database abstraction object. 2036 */ 2037 function upgrade_430_fix_comments() { 2038 global $wpdb; 2039 2040 $content_length = $wpdb->get_col_length( $wpdb->comments, 'comment_content' ); 2041 2042 if ( false === $content_length ) { 2043 $content_length = array( 2044 'type' => 'byte', 2045 'length' => 65535, 2046 ); 2047 } 2048 2049 if ( ! is_array( $content_length ) || 'byte' !== $content_length['type'] || 0 === $content_length['length'] ) { 2050 // Sites with malformed DB schemas are on their own. 2051 return; 2052 } 2053 2054 $allowed_length = (int) $content_length['length'] - 10; 2055 2056 $comments = $wpdb->get_results( 2057 "SELECT `comment_ID` FROM `{$wpdb->comments}` 2058 WHERE `comment_date_gmt` > '2015-04-26' 2059 AND LENGTH( `comment_content` ) >= {$allowed_length} 2060 AND ( `comment_content` LIKE '%<%' OR `comment_content` LIKE '%>%' )" 2061 ); 2062 2063 foreach ( $comments as $comment ) { 2064 wp_delete_comment( $comment->comment_ID, true ); 2065 } 2066 } 2067 2068 /** 2069 * Executes changes made in WordPress 4.3.1. 2070 * 2071 * @ignore 2072 * @since 4.3.1 2073 */ 2074 function upgrade_431() { 2075 // Fix incorrect cron entries for term splitting. 2076 $cron_array = _get_cron_array(); 2077 if ( isset( $cron_array['wp_batch_split_terms'] ) ) { 2078 unset( $cron_array['wp_batch_split_terms'] ); 2079 _set_cron_array( $cron_array ); 2080 } 2081 } 2082 2083 /** 2084 * Executes changes made in WordPress 4.4.0. 2085 * 2086 * @ignore 2087 * @since 4.4.0 2088 * 2089 * @global int $wp_current_db_version The old (current) database version. 2090 * @global wpdb $wpdb WordPress database abstraction object. 2091 */ 2092 function upgrade_440() { 2093 global $wp_current_db_version, $wpdb; 2094 2095 if ( $wp_current_db_version < 34030 ) { 2096 $wpdb->query( "ALTER TABLE {$wpdb->options} MODIFY option_name VARCHAR(191)" ); 2097 } 2098 2099 // Remove the unused 'add_users' role. 2100 $roles = wp_roles(); 2101 foreach ( $roles->role_objects as $role ) { 2102 if ( $role->has_cap( 'add_users' ) ) { 2103 $role->remove_cap( 'add_users' ); 2104 } 2105 } 2106 } 2107 2108 /** 2109 * Executes changes made in WordPress 4.5.0. 2110 * 2111 * @ignore 2112 * @since 4.5.0 2113 * 2114 * @global int $wp_current_db_version The old (current) database version. 2115 * @global wpdb $wpdb WordPress database abstraction object. 2116 */ 2117 function upgrade_450() { 2118 global $wp_current_db_version, $wpdb; 2119 2120 if ( $wp_current_db_version < 36180 ) { 2121 wp_clear_scheduled_hook( 'wp_maybe_auto_update' ); 2122 } 2123 2124 // Remove unused email confirmation options, moved to usermeta. 2125 if ( $wp_current_db_version < 36679 && is_multisite() ) { 2126 $wpdb->query( "DELETE FROM $wpdb->options WHERE option_name REGEXP '^[0-9]+_new_email$'" ); 2127 } 2128 2129 // Remove unused user setting for wpLink. 2130 delete_user_setting( 'wplink' ); 2131 } 2132 2133 /** 2134 * Executes changes made in WordPress 4.6.0. 2135 * 2136 * @ignore 2137 * @since 4.6.0 2138 * 2139 * @global int $wp_current_db_version The old (current) database version. 2140 */ 2141 function upgrade_460() { 2142 global $wp_current_db_version; 2143 2144 // Remove unused post meta. 2145 if ( $wp_current_db_version < 37854 ) { 2146 delete_post_meta_by_key( '_post_restored_from' ); 2147 } 2148 2149 // Remove plugins with callback as an array object/method as the uninstall hook, see #13786. 2150 if ( $wp_current_db_version < 37965 ) { 2151 $uninstall_plugins = get_option( 'uninstall_plugins', array() ); 2152 2153 if ( ! empty( $uninstall_plugins ) ) { 2154 foreach ( $uninstall_plugins as $basename => $callback ) { 2155 if ( is_array( $callback ) && is_object( $callback[0] ) ) { 2156 unset( $uninstall_plugins[ $basename ] ); 2157 } 2158 } 2159 2160 update_option( 'uninstall_plugins', $uninstall_plugins ); 2161 } 2162 } 2163 } 2164 2165 /** 2166 * Executes changes made in WordPress 5.0.0. 2167 * 2168 * @ignore 2169 * @since 5.0.0 2170 * @deprecated 5.1.0 2171 */ 2172 function upgrade_500() { 2173 } 2174 2175 /** 2176 * Executes changes made in WordPress 5.1.0. 2177 * 2178 * @ignore 2179 * @since 5.1.0 2180 */ 2181 function upgrade_510() { 2182 delete_site_option( 'upgrade_500_was_gutenberg_active' ); 2183 } 2184 2185 /** 2186 * Executes changes made in WordPress 5.3.0. 2187 * 2188 * @ignore 2189 * @since 5.3.0 2190 */ 2191 function upgrade_530() { 2192 /* 2193 * The `admin_email_lifespan` option may have been set by an admin that just logged in, 2194 * saw the verification screen, clicked on a button there, and is now upgrading the db, 2195 * or by populate_options() that is called earlier in upgrade_all(). 2196 * In the second case `admin_email_lifespan` should be reset so the verification screen 2197 * is shown next time an admin logs in. 2198 */ 2199 if ( function_exists( 'current_user_can' ) && ! current_user_can( 'manage_options' ) ) { 2200 update_option( 'admin_email_lifespan', 0 ); 2201 } 2202 } 2203 2204 /** 2205 * Executes changes made in WordPress 5.5.0. 2206 * 2207 * @ignore 2208 * @since 5.5.0 2209 * 2210 * @global int $wp_current_db_version The old (current) database version. 2211 */ 2212 function upgrade_550() { 2213 global $wp_current_db_version; 2214 2215 if ( $wp_current_db_version < 48121 ) { 2216 $comment_previously_approved = get_option( 'comment_whitelist', '' ); 2217 update_option( 'comment_previously_approved', $comment_previously_approved ); 2218 delete_option( 'comment_whitelist' ); 2219 } 2220 2221 if ( $wp_current_db_version < 48575 ) { 2222 // Use more clear and inclusive language. 2223 $disallowed_list = get_option( 'blacklist_keys' ); 2224 2225 /* 2226 * This option key was briefly renamed `blocklist_keys`. 2227 * Account for sites that have this key present when the original key does not exist. 2228 */ 2229 if ( false === $disallowed_list ) { 2230 $disallowed_list = get_option( 'blocklist_keys' ); 2231 } 2232 2233 update_option( 'disallowed_keys', $disallowed_list ); 2234 delete_option( 'blacklist_keys' ); 2235 delete_option( 'blocklist_keys' ); 2236 } 2237 2238 if ( $wp_current_db_version < 48748 ) { 2239 update_option( 'finished_updating_comment_type', 0 ); 2240 wp_schedule_single_event( time() + ( 1 * MINUTE_IN_SECONDS ), 'wp_update_comment_type_batch' ); 2241 } 2242 } 2243 2244 /** 2245 * Executes changes made in WordPress 5.6.0. 2246 * 2247 * @ignore 2248 * @since 5.6.0 2249 * 2250 * @global int $wp_current_db_version The old (current) database version. 2251 * @global wpdb $wpdb WordPress database abstraction object. 2252 */ 2253 function upgrade_560() { 2254 global $wp_current_db_version, $wpdb; 2255 2256 if ( $wp_current_db_version < 49572 ) { 2257 /* 2258 * Clean up the `post_category` column removed from schema in version 2.8.0. 2259 * Its presence may conflict with `WP_Post::__get()`. 2260 */ 2261 $post_category_exists = $wpdb->get_var( "SHOW COLUMNS FROM $wpdb->posts LIKE 'post_category'" ); 2262 if ( ! is_null( $post_category_exists ) ) { 2263 $wpdb->query( "ALTER TABLE $wpdb->posts DROP COLUMN `post_category`" ); 2264 } 2265 2266 /* 2267 * When upgrading from WP < 5.6.0 set the core major auto-updates option to `unset` by default. 2268 * This overrides the same option from populate_options() that is intended for new installs. 2269 * See https://core.trac.wordpress.org/ticket/51742. 2270 */ 2271 update_option( 'auto_update_core_major', 'unset' ); 2272 } 2273 2274 if ( $wp_current_db_version < 49632 ) { 2275 /* 2276 * Regenerate the .htaccess file to add the `HTTP_AUTHORIZATION` rewrite rule. 2277 * See https://core.trac.wordpress.org/ticket/51723. 2278 */ 2279 save_mod_rewrite_rules(); 2280 } 2281 2282 if ( $wp_current_db_version < 49735 ) { 2283 delete_transient( 'dirsize_cache' ); 2284 } 2285 2286 if ( $wp_current_db_version < 49752 ) { 2287 $results = $wpdb->get_results( 2288 $wpdb->prepare( 2289 "SELECT 1 FROM {$wpdb->usermeta} WHERE meta_key = %s LIMIT 1", 2290 WP_Application_Passwords::USERMETA_KEY_APPLICATION_PASSWORDS 2291 ) 2292 ); 2293 2294 if ( ! empty( $results ) ) { 2295 $network_id = get_main_network_id(); 2296 update_network_option( $network_id, WP_Application_Passwords::OPTION_KEY_IN_USE, 1 ); 2297 } 2298 } 2299 } 2300 2301 /** 2302 * Executes changes made in WordPress 5.9.0. 2303 * 2304 * @ignore 2305 * @since 5.9.0 2306 * 2307 * @global int $wp_current_db_version The old (current) database version. 2308 */ 2309 function upgrade_590() { 2310 global $wp_current_db_version; 2311 2312 if ( $wp_current_db_version < 51917 ) { 2313 $crons = _get_cron_array(); 2314 2315 if ( $crons && is_array( $crons ) ) { 2316 // Remove errant `false` values, see #53950, #54906. 2317 $crons = array_filter( $crons ); 2318 _set_cron_array( $crons ); 2319 } 2320 } 2321 } 2322 2323 /** 2324 * Executes changes made in WordPress 6.0.0. 2325 * 2326 * @ignore 2327 * @since 6.0.0 2328 * 2329 * @global int $wp_current_db_version The old (current) database version. 2330 */ 2331 function upgrade_600() { 2332 global $wp_current_db_version; 2333 2334 if ( $wp_current_db_version < 53011 ) { 2335 wp_update_user_counts(); 2336 } 2337 } 2338 2339 /** 2340 * Executes changes made in WordPress 6.3.0. 2341 * 2342 * @ignore 2343 * @since 6.3.0 2344 * 2345 * @global int $wp_current_db_version The old (current) database version. 2346 */ 2347 function upgrade_630() { 2348 global $wp_current_db_version; 2349 2350 if ( $wp_current_db_version < 55853 ) { 2351 if ( ! is_multisite() ) { 2352 // Replace non-autoload option can_compress_scripts with autoload option, see #55270 2353 $can_compress_scripts = get_option( 'can_compress_scripts', false ); 2354 if ( false !== $can_compress_scripts ) { 2355 delete_option( 'can_compress_scripts' ); 2356 add_option( 'can_compress_scripts', $can_compress_scripts, '', true ); 2357 } 2358 } 2359 } 2360 } 2361 2362 /** 2363 * Executes changes made in WordPress 6.4.0. 2364 * 2365 * @ignore 2366 * @since 6.4.0 2367 * 2368 * @global int $wp_current_db_version The old (current) database version. 2369 */ 2370 function upgrade_640() { 2371 global $wp_current_db_version; 2372 2373 if ( $wp_current_db_version < 56657 ) { 2374 // Enable attachment pages. 2375 update_option( 'wp_attachment_pages_enabled', 1 ); 2376 2377 // Remove the wp_https_detection cron. Https status is checked directly in an async Site Health check. 2378 $scheduled = wp_get_scheduled_event( 'wp_https_detection' ); 2379 if ( $scheduled ) { 2380 wp_clear_scheduled_hook( 'wp_https_detection' ); 2381 } 2382 } 2383 } 2384 2385 /** 2386 * Executes changes made in WordPress 6.5.0. 2387 * 2388 * @ignore 2389 * @since 6.5.0 2390 * 2391 * @global int $wp_current_db_version The old (current) database version. 2392 * @global wpdb $wpdb WordPress database abstraction object. 2393 */ 2394 function upgrade_650() { 2395 global $wp_current_db_version, $wpdb; 2396 2397 if ( $wp_current_db_version < 57155 ) { 2398 $stylesheet = get_stylesheet(); 2399 2400 // Set autoload=no for all themes except the current one. 2401 $theme_mods_options = $wpdb->get_col( 2402 $wpdb->prepare( 2403 "SELECT option_name FROM $wpdb->options WHERE autoload = 'yes' AND option_name != %s AND option_name LIKE %s", 2404 "theme_mods_$stylesheet", 2405 $wpdb->esc_like( 'theme_mods_' ) . '%' 2406 ) 2407 ); 2408 2409 $autoload = array_fill_keys( $theme_mods_options, false ); 2410 wp_set_option_autoload_values( $autoload ); 2411 } 2412 } 2413 2414 /** 2415 * Executes changes made in WordPress 6.7.0. 2416 * 2417 * @ignore 2418 * @since 6.7.0 2419 * 2420 * @global int $wp_current_db_version The old (current) database version. 2421 */ 2422 function upgrade_670() { 2423 global $wp_current_db_version; 2424 2425 if ( $wp_current_db_version < 58975 ) { 2426 $options = array( 2427 'recently_activated', 2428 '_wp_suggested_policy_text_has_changed', 2429 'dashboard_widget_options', 2430 'ftp_credentials', 2431 'adminhash', 2432 'nav_menu_options', 2433 'wp_force_deactivated_plugins', 2434 'delete_blog_hash', 2435 'allowedthemes', 2436 'recovery_keys', 2437 'https_detection_errors', 2438 'fresh_site', 2439 ); 2440 2441 wp_set_options_autoload( $options, false ); 2442 } 2443 } 2444 2445 /** 2446 * Executes changes made in WordPress 6.8.2. 2447 * 2448 * @ignore 2449 * @since 6.8.2 2450 * 2451 * @global int $wp_current_db_version The old (current) database version. 2452 */ 2453 function upgrade_682() { 2454 global $wp_current_db_version; 2455 2456 if ( $wp_current_db_version < 60421 ) { 2457 // Upgrade Ping-O-Matic and Twingly to use HTTPS. 2458 $ping_sites_value = get_option( 'ping_sites' ); 2459 $ping_sites_value = explode( "\n", $ping_sites_value ); 2460 $ping_sites_value = array_map( 2461 function ( $url ) { 2462 $url = trim( $url ); 2463 $url = sanitize_url( $url ); 2464 if ( 2465 str_ends_with( trailingslashit( $url ), '://rpc.pingomatic.com/' ) 2466 || str_ends_with( trailingslashit( $url ), '://rpc.twingly.com/' ) 2467 ) { 2468 $url = set_url_scheme( $url, 'https' ); 2469 } 2470 return $url; 2471 }, 2472 $ping_sites_value 2473 ); 2474 $ping_sites_value = array_filter( $ping_sites_value ); 2475 $ping_sites_value = implode( "\n", $ping_sites_value ); 2476 update_option( 'ping_sites', $ping_sites_value ); 2477 } 2478 } 2479 2480 /** 2481 * Executes changes made in WordPress 7.0. 2482 * 2483 * @ignore 2484 * @since 7.0.0 2485 * 2486 * @global int $wp_current_db_version The old (current) database version. 2487 * @global wpdb $wpdb WordPress database abstraction object. 2488 */ 2489 function upgrade_700() { 2490 global $wp_current_db_version, $wpdb; 2491 2492 // Migrate users with 'fresh' admin color to 'modern'. 2493 if ( $wp_current_db_version < 61644 ) { 2494 $wpdb->update( 2495 $wpdb->usermeta, 2496 array( 'meta_value' => 'modern' ), 2497 array( 2498 'meta_key' => 'admin_color', 2499 'meta_value' => 'fresh', 2500 ) 2501 ); 2502 } 2503 } 2504 2505 /** 2506 * Executes network-level upgrade routines. 2507 * 2508 * @since 3.0.0 2509 * 2510 * @global int $wp_current_db_version The old (current) database version. 2511 * @global wpdb $wpdb WordPress database abstraction object. 2512 */ 2513 function upgrade_network() { 2514 global $wp_current_db_version, $wpdb; 2515 2516 // Always clear expired transients. 2517 delete_expired_transients( true ); 2518 2519 // 2.8.0 2520 if ( $wp_current_db_version < 11549 ) { 2521 $wpmu_sitewide_plugins = get_site_option( 'wpmu_sitewide_plugins' ); 2522 $active_sitewide_plugins = get_site_option( 'active_sitewide_plugins' ); 2523 if ( $wpmu_sitewide_plugins ) { 2524 if ( ! $active_sitewide_plugins ) { 2525 $sitewide_plugins = (array) $wpmu_sitewide_plugins; 2526 } else { 2527 $sitewide_plugins = array_merge( (array) $active_sitewide_plugins, (array) $wpmu_sitewide_plugins ); 2528 } 2529 2530 update_site_option( 'active_sitewide_plugins', $sitewide_plugins ); 2531 } 2532 delete_site_option( 'wpmu_sitewide_plugins' ); 2533 delete_site_option( 'deactivated_sitewide_plugins' ); 2534 2535 $start = 0; 2536 while ( $rows = $wpdb->get_results( "SELECT meta_key, meta_value FROM {$wpdb->sitemeta} ORDER BY meta_id LIMIT $start, 20" ) ) { 2537 foreach ( $rows as $row ) { 2538 $value = $row->meta_value; 2539 if ( ! @unserialize( $value ) ) { 2540 $value = stripslashes( $value ); 2541 } 2542 if ( $value !== $row->meta_value ) { 2543 update_site_option( $row->meta_key, $value ); 2544 } 2545 } 2546 $start += 20; 2547 } 2548 } 2549 2550 // 3.0.0 2551 if ( $wp_current_db_version < 13576 ) { 2552 update_site_option( 'global_terms_enabled', '1' ); 2553 } 2554 2555 // 3.3.0 2556 if ( $wp_current_db_version < 19390 ) { 2557 update_site_option( 'initial_db_version', $wp_current_db_version ); 2558 } 2559 2560 if ( $wp_current_db_version < 19470 ) { 2561 if ( false === get_site_option( 'active_sitewide_plugins' ) ) { 2562 update_site_option( 'active_sitewide_plugins', array() ); 2563 } 2564 } 2565 2566 // 3.4.0 2567 if ( $wp_current_db_version < 20148 ) { 2568 // 'allowedthemes' keys things by stylesheet. 'allowed_themes' keyed things by name. 2569 $allowedthemes = get_site_option( 'allowedthemes' ); 2570 $allowed_themes = get_site_option( 'allowed_themes' ); 2571 if ( false === $allowedthemes && is_array( $allowed_themes ) && $allowed_themes ) { 2572 $converted = array(); 2573 $themes = wp_get_themes(); 2574 foreach ( $themes as $stylesheet => $theme_data ) { 2575 if ( isset( $allowed_themes[ $theme_data->get( 'Name' ) ] ) ) { 2576 $converted[ $stylesheet ] = true; 2577 } 2578 } 2579 update_site_option( 'allowedthemes', $converted ); 2580 delete_site_option( 'allowed_themes' ); 2581 } 2582 } 2583 2584 // 3.5.0 2585 if ( $wp_current_db_version < 21823 ) { 2586 update_site_option( 'ms_files_rewriting', '1' ); 2587 } 2588 2589 // 3.5.2 2590 if ( $wp_current_db_version < 24448 ) { 2591 $illegal_names = get_site_option( 'illegal_names' ); 2592 if ( is_array( $illegal_names ) && count( $illegal_names ) === 1 ) { 2593 $illegal_name = reset( $illegal_names ); 2594 $illegal_names = explode( ' ', $illegal_name ); 2595 update_site_option( 'illegal_names', $illegal_names ); 2596 } 2597 } 2598 2599 // 4.2.0 2600 if ( $wp_current_db_version < 31351 && 'utf8mb4' === $wpdb->charset ) { 2601 if ( wp_should_upgrade_global_tables() ) { 2602 $wpdb->query( "ALTER TABLE $wpdb->usermeta DROP INDEX meta_key, ADD INDEX meta_key(meta_key(191))" ); 2603 $wpdb->query( "ALTER TABLE $wpdb->site DROP INDEX domain, ADD INDEX domain(domain(140),path(51))" ); 2604 $wpdb->query( "ALTER TABLE $wpdb->sitemeta DROP INDEX meta_key, ADD INDEX meta_key(meta_key(191))" ); 2605 $wpdb->query( "ALTER TABLE $wpdb->signups DROP INDEX domain_path, ADD INDEX domain_path(domain(140),path(51))" ); 2606 2607 $tables = $wpdb->tables( 'global' ); 2608 2609 // sitecategories may not exist. 2610 if ( ! $wpdb->get_var( "SHOW TABLES LIKE '{$tables['sitecategories']}'" ) ) { 2611 unset( $tables['sitecategories'] ); 2612 } 2613 2614 foreach ( $tables as $table ) { 2615 maybe_convert_table_to_utf8mb4( $table ); 2616 } 2617 } 2618 } 2619 2620 // 4.3.0 2621 if ( $wp_current_db_version < 33055 && 'utf8mb4' === $wpdb->charset ) { 2622 if ( wp_should_upgrade_global_tables() ) { 2623 $upgrade = false; 2624 $indexes = $wpdb->get_results( "SHOW INDEXES FROM $wpdb->signups" ); 2625 foreach ( $indexes as $index ) { 2626 if ( 'domain_path' === $index->Key_name && 'domain' === $index->Column_name && '140' !== $index->Sub_part ) { 2627 $upgrade = true; 2628 break; 2629 } 2630 } 2631 2632 if ( $upgrade ) { 2633 $wpdb->query( "ALTER TABLE $wpdb->signups DROP INDEX domain_path, ADD INDEX domain_path(domain(140),path(51))" ); 2634 } 2635 2636 $tables = $wpdb->tables( 'global' ); 2637 2638 // sitecategories may not exist. 2639 if ( ! $wpdb->get_var( "SHOW TABLES LIKE '{$tables['sitecategories']}'" ) ) { 2640 unset( $tables['sitecategories'] ); 2641 } 2642 2643 foreach ( $tables as $table ) { 2644 maybe_convert_table_to_utf8mb4( $table ); 2645 } 2646 } 2647 } 2648 2649 // 5.1.0 2650 if ( $wp_current_db_version < 44467 ) { 2651 $network_id = get_main_network_id(); 2652 delete_network_option( $network_id, 'site_meta_supported' ); 2653 is_site_meta_supported(); 2654 } 2655 } 2656 2657 // 2658 // General functions we use to actually do stuff. 2659 // 2660 2661 /** 2662 * Creates a table in the database, if it doesn't already exist. 2663 * 2664 * This method checks for an existing database table and creates a new one if it's not 2665 * already present. It doesn't rely on MySQL's "IF NOT EXISTS" statement, but chooses 2666 * to query all tables first and then run the SQL statement creating the table. 2667 * 2668 * @since 1.0.0 2669 * 2670 * @global wpdb $wpdb WordPress database abstraction object. 2671 * 2672 * @param string $table_name Database table name. 2673 * @param string $create_ddl SQL statement to create table. 2674 * @return bool True on success or if the table already exists. False on failure. 2675 */ 2676 function maybe_create_table( $table_name, $create_ddl ) { 2677 global $wpdb; 2678 2679 $query = $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $table_name ) ); 2680 2681 if ( $wpdb->get_var( $query ) === $table_name ) { 2682 return true; 2683 } 2684 2685 // Didn't find it, so try to create it. 2686 $wpdb->query( $create_ddl ); 2687 2688 // We cannot directly tell that whether this succeeded! 2689 if ( $wpdb->get_var( $query ) === $table_name ) { 2690 return true; 2691 } 2692 2693 return false; 2694 } 2695 2696 /** 2697 * Drops a specified index from a table. 2698 * 2699 * @since 1.0.1 2700 * 2701 * @global wpdb $wpdb WordPress database abstraction object. 2702 * 2703 * @param string $table Database table name. 2704 * @param string $index Index name to drop. 2705 * @return true True, when finished. 2706 */ 2707 function drop_index( $table, $index ) { 2708 global $wpdb; 2709 2710 $wpdb->hide_errors(); 2711 2712 $wpdb->query( "ALTER TABLE `$table` DROP INDEX `$index`" ); 2713 2714 // Now we need to take out all the extra ones we may have created. 2715 for ( $i = 0; $i < 25; $i++ ) { 2716 $wpdb->query( "ALTER TABLE `$table` DROP INDEX `{$index}_$i`" ); 2717 } 2718 2719 $wpdb->show_errors(); 2720 2721 return true; 2722 } 2723 2724 /** 2725 * Adds an index to a specified table. 2726 * 2727 * @since 1.0.1 2728 * 2729 * @global wpdb $wpdb WordPress database abstraction object. 2730 * 2731 * @param string $table Database table name. 2732 * @param string $index Database table index column. 2733 * @return true True, when done with execution. 2734 */ 2735 function add_clean_index( $table, $index ) { 2736 global $wpdb; 2737 2738 drop_index( $table, $index ); 2739 $wpdb->query( "ALTER TABLE `$table` ADD INDEX ( `$index` )" ); 2740 2741 return true; 2742 } 2743 2744 /** 2745 * Adds column to a database table, if it doesn't already exist. 2746 * 2747 * @since 1.3.0 2748 * 2749 * @global wpdb $wpdb WordPress database abstraction object. 2750 * 2751 * @param string $table_name Database table name. 2752 * @param string $column_name Table column name. 2753 * @param string $create_ddl SQL statement to add column. 2754 * @return bool True on success or if the column already exists. False on failure. 2755 */ 2756 function maybe_add_column( $table_name, $column_name, $create_ddl ) { 2757 global $wpdb; 2758 2759 foreach ( $wpdb->get_col( "DESC $table_name", 0 ) as $column ) { 2760 if ( $column === $column_name ) { 2761 return true; 2762 } 2763 } 2764 2765 // Didn't find it, so try to create it. 2766 $wpdb->query( $create_ddl ); 2767 2768 // We cannot directly tell that whether this succeeded! 2769 foreach ( $wpdb->get_col( "DESC $table_name", 0 ) as $column ) { 2770 if ( $column === $column_name ) { 2771 return true; 2772 } 2773 } 2774 2775 return false; 2776 } 2777 2778 /** 2779 * If a table only contains utf8 or utf8mb4 columns, convert it to utf8mb4. 2780 * 2781 * @since 4.2.0 2782 * 2783 * @global wpdb $wpdb WordPress database abstraction object. 2784 * 2785 * @param string $table The table to convert. 2786 * @return bool True if the table was converted, false if it wasn't. 2787 */ 2788 function maybe_convert_table_to_utf8mb4( $table ) { 2789 global $wpdb; 2790 2791 $results = $wpdb->get_results( "SHOW FULL COLUMNS FROM `$table`" ); 2792 if ( ! $results ) { 2793 return false; 2794 } 2795 2796 foreach ( $results as $column ) { 2797 if ( $column->Collation ) { 2798 list( $charset ) = explode( '_', $column->Collation ); 2799 $charset = strtolower( $charset ); 2800 if ( 'utf8' !== $charset && 'utf8mb4' !== $charset ) { 2801 // Don't upgrade tables that have non-utf8 columns. 2802 return false; 2803 } 2804 } 2805 } 2806 2807 $table_details = $wpdb->get_row( "SHOW TABLE STATUS LIKE '$table'" ); 2808 if ( ! $table_details ) { 2809 return false; 2810 } 2811 2812 list( $table_charset ) = explode( '_', $table_details->Collation ); 2813 $table_charset = strtolower( $table_charset ); 2814 if ( 'utf8mb4' === $table_charset ) { 2815 return true; 2816 } 2817 2818 return $wpdb->query( "ALTER TABLE $table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci" ); 2819 } 2820 2821 /** 2822 * Retrieve all options as it was for 1.2. 2823 * 2824 * @since 1.2.0 2825 * 2826 * @global wpdb $wpdb WordPress database abstraction object. 2827 * 2828 * @return stdClass List of options. 2829 */ 2830 function get_alloptions_110() { 2831 global $wpdb; 2832 $all_options = new stdClass(); 2833 $options = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options" ); 2834 if ( $options ) { 2835 foreach ( $options as $option ) { 2836 if ( 'siteurl' === $option->option_name || 'home' === $option->option_name || 'category_base' === $option->option_name ) { 2837 $option->option_value = untrailingslashit( $option->option_value ); 2838 } 2839 $all_options->{$option->option_name} = stripslashes( $option->option_value ); 2840 } 2841 } 2842 return $all_options; 2843 } 2844 2845 /** 2846 * Utility version of get_option that is private to installation/upgrade. 2847 * 2848 * @ignore 2849 * @since 1.5.1 2850 * @access private 2851 * 2852 * @global wpdb $wpdb WordPress database abstraction object. 2853 * 2854 * @param string $setting Option name. 2855 * @return mixed Option value. 2856 */ 2857 function __get_option( $setting ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionDoubleUnderscore,PHPCompatibility.FunctionNameRestrictions.ReservedFunctionNames.FunctionDoubleUnderscore 2858 global $wpdb; 2859 2860 if ( 'home' === $setting && defined( 'WP_HOME' ) ) { 2861 return untrailingslashit( WP_HOME ); 2862 } 2863 2864 if ( 'siteurl' === $setting && defined( 'WP_SITEURL' ) ) { 2865 return untrailingslashit( WP_SITEURL ); 2866 } 2867 2868 $option = $wpdb->get_var( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s", $setting ) ); 2869 2870 if ( 'home' === $setting && ! $option ) { 2871 return __get_option( 'siteurl' ); 2872 } 2873 2874 if ( in_array( $setting, array( 'siteurl', 'home', 'category_base', 'tag_base' ), true ) ) { 2875 $option = untrailingslashit( $option ); 2876 } 2877 2878 return maybe_unserialize( $option ); 2879 } 2880 2881 /** 2882 * Filters for content to remove unnecessary slashes. 2883 * 2884 * @since 1.5.0 2885 * 2886 * @param string $content The content to modify. 2887 * @return string The de-slashed content. 2888 */ 2889 function deslash( $content ) { 2890 // Note: \\\ inside a regex denotes a single backslash. 2891 2892 /* 2893 * Replace one or more backslashes followed by a single quote with 2894 * a single quote. 2895 */ 2896 $content = preg_replace( "/\\\+'/", "'", $content ); 2897 2898 /* 2899 * Replace one or more backslashes followed by a double quote with 2900 * a double quote. 2901 */ 2902 $content = preg_replace( '/\\\+"/', '"', $content ); 2903 2904 // Replace one or more backslashes with one backslash. 2905 $content = preg_replace( '/\\\+/', '\\', $content ); 2906 2907 return $content; 2908 } 2909 2910 /** 2911 * Modifies the database based on specified SQL statements. 2912 * 2913 * Useful for creating new tables and updating existing tables to a new structure. 2914 * 2915 * @since 1.5.0 2916 * @since 6.1.0 Ignores display width for integer data types on MySQL 8.0.17 or later, 2917 * to match MySQL behavior. Note: This does not affect MariaDB. 2918 * 2919 * @global wpdb $wpdb WordPress database abstraction object. 2920 * 2921 * @param string[]|string $queries Optional. The query to run. Can be multiple queries 2922 * in an array, or a string of queries separated by 2923 * semicolons. Default empty string. 2924 * @param bool $execute Optional. Whether or not to execute the query right away. 2925 * Default true. 2926 * @return string[] Strings containing the results of the various update queries. 2927 */ 2928 function dbDelta( $queries = '', $execute = true ) { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid 2929 global $wpdb; 2930 2931 if ( in_array( $queries, array( '', 'all', 'blog', 'global', 'ms_global' ), true ) ) { 2932 $queries = wp_get_db_schema( $queries ); 2933 } 2934 2935 // Separate individual queries into an array. 2936 if ( ! is_array( $queries ) ) { 2937 $queries = explode( ';', $queries ); 2938 $queries = array_filter( $queries ); 2939 } 2940 2941 /** 2942 * Filters the dbDelta SQL queries. 2943 * 2944 * @since 3.3.0 2945 * 2946 * @param string[] $queries An array of dbDelta SQL queries. 2947 */ 2948 $queries = apply_filters( 'dbdelta_queries', $queries ); 2949 2950 $cqueries = array(); // Creation queries. 2951 $iqueries = array(); // Insertion queries. 2952 $for_update = array(); 2953 2954 // Create a tablename index for an array ($cqueries) of recognized query types. 2955 foreach ( $queries as $qry ) { 2956 if ( preg_match( '|CREATE TABLE ([^ ]*)|', $qry, $matches ) ) { 2957 $table_name = trim( $matches[1], '`' ); 2958 2959 $cqueries[ $table_name ] = $qry; 2960 $for_update[ $table_name ] = 'Created table ' . $matches[1]; 2961 continue; 2962 } 2963 2964 if ( preg_match( '|CREATE DATABASE ([^ ]*)|', $qry, $matches ) ) { 2965 array_unshift( $cqueries, $qry ); 2966 continue; 2967 } 2968 2969 if ( preg_match( '|INSERT INTO ([^ ]*)|', $qry, $matches ) ) { 2970 $iqueries[] = $qry; 2971 continue; 2972 } 2973 2974 if ( preg_match( '|UPDATE ([^ ]*)|', $qry, $matches ) ) { 2975 $iqueries[] = $qry; 2976 continue; 2977 } 2978 } 2979 2980 /** 2981 * Filters the dbDelta SQL queries for creating tables and/or databases. 2982 * 2983 * Queries filterable via this hook contain "CREATE TABLE" or "CREATE DATABASE". 2984 * 2985 * @since 3.3.0 2986 * 2987 * @param string[] $cqueries An array of dbDelta create SQL queries. 2988 */ 2989 $cqueries = apply_filters( 'dbdelta_create_queries', $cqueries ); 2990 2991 /** 2992 * Filters the dbDelta SQL queries for inserting or updating. 2993 * 2994 * Queries filterable via this hook contain "INSERT INTO" or "UPDATE". 2995 * 2996 * @since 3.3.0 2997 * 2998 * @param string[] $iqueries An array of dbDelta insert or update SQL queries. 2999 */ 3000 $iqueries = apply_filters( 'dbdelta_insert_queries', $iqueries ); 3001 3002 $text_fields = array( 'tinytext', 'text', 'mediumtext', 'longtext' ); 3003 $blob_fields = array( 'tinyblob', 'blob', 'mediumblob', 'longblob' ); 3004 $int_fields = array( 'tinyint', 'smallint', 'mediumint', 'int', 'integer', 'bigint' ); 3005 3006 $global_tables = $wpdb->tables( 'global' ); 3007 $db_version = $wpdb->db_version(); 3008 $db_server_info = $wpdb->db_server_info(); 3009 3010 foreach ( $cqueries as $table => $qry ) { 3011 // Upgrade global tables only for the main site. Don't upgrade at all if conditions are not optimal. 3012 if ( in_array( $table, $global_tables, true ) && ! wp_should_upgrade_global_tables() ) { 3013 unset( $cqueries[ $table ], $for_update[ $table ] ); 3014 continue; 3015 } 3016 3017 // Fetch the table column structure from the database. 3018 $suppress = $wpdb->suppress_errors(); 3019 $tablefields = $wpdb->get_results( "DESCRIBE {$table};" ); 3020 $wpdb->suppress_errors( $suppress ); 3021 3022 if ( ! $tablefields ) { 3023 continue; 3024 } 3025 3026 // Clear the field and index arrays. 3027 $cfields = array(); 3028 $indices = array(); 3029 $indices_without_subparts = array(); 3030 3031 // Get all of the field names in the query from between the parentheses. 3032 preg_match( '|\((.*)\)|ms', $qry, $match2 ); 3033 $qryline = trim( $match2[1] ); 3034 3035 // Separate field lines into an array. 3036 $flds = explode( "\n", $qryline ); 3037 3038 // For every field line specified in the query. 3039 foreach ( $flds as $fld ) { 3040 $fld = trim( $fld, " \t\n\r\0\x0B," ); // Default trim characters, plus ','. 3041 3042 // Extract the field name. 3043 preg_match( '|^([^ ]*)|', $fld, $fvals ); 3044 $fieldname = trim( $fvals[1], '`' ); 3045 $fieldname_lowercased = strtolower( $fieldname ); 3046 3047 // Verify the found field name. 3048 $validfield = true; 3049 switch ( $fieldname_lowercased ) { 3050 case '': 3051 case 'primary': 3052 case 'index': 3053 case 'fulltext': 3054 case 'unique': 3055 case 'key': 3056 case 'spatial': 3057 $validfield = false; 3058 3059 /* 3060 * Normalize the index definition. 3061 * 3062 * This is done so the definition can be compared against the result of a 3063 * `SHOW INDEX FROM $table_name` query which returns the current table 3064 * index information. 3065 */ 3066 3067 // Extract type, name and columns from the definition. 3068 preg_match( 3069 '/^ 3070 (?P<index_type> # 1) Type of the index. 3071 PRIMARY\s+KEY|(?:UNIQUE|FULLTEXT|SPATIAL)\s+(?:KEY|INDEX)|KEY|INDEX 3072 ) 3073 \s+ # Followed by at least one white space character. 3074 (?: # Name of the index. Optional if type is PRIMARY KEY. 3075 `? # Name can be escaped with a backtick. 3076 (?P<index_name> # 2) Name of the index. 3077 (?:[0-9a-zA-Z$_-]|[\xC2-\xDF][\x80-\xBF])+ 3078 ) 3079 `? # Name can be escaped with a backtick. 3080 \s+ # Followed by at least one white space character. 3081 )* 3082 \( # Opening bracket for the columns. 3083 (?P<index_columns> 3084 .+? # 3) Column names, index prefixes, and orders. 3085 ) 3086 \) # Closing bracket for the columns. 3087 $/imx', 3088 $fld, 3089 $index_matches 3090 ); 3091 3092 // Uppercase the index type and normalize space characters. 3093 $index_type = strtoupper( preg_replace( '/\s+/', ' ', trim( $index_matches['index_type'] ) ) ); 3094 3095 // 'INDEX' is a synonym for 'KEY', standardize on 'KEY'. 3096 $index_type = str_replace( 'INDEX', 'KEY', $index_type ); 3097 3098 // Escape the index name with backticks. An index for a primary key has no name. 3099 $index_name = ( 'PRIMARY KEY' === $index_type ) ? '' : '`' . strtolower( $index_matches['index_name'] ) . '`'; 3100 3101 // Parse the columns. Multiple columns are separated by a comma. 3102 $index_columns = array_map( 'trim', explode( ',', $index_matches['index_columns'] ) ); 3103 $index_columns_without_subparts = $index_columns; 3104 3105 // Normalize columns. 3106 foreach ( $index_columns as $id => &$index_column ) { 3107 // Extract column name and number of indexed characters (sub_part). 3108 preg_match( 3109 '/ 3110 `? # Name can be escaped with a backtick. 3111 (?P<column_name> # 1) Name of the column. 3112 (?:[0-9a-zA-Z$_-]|[\xC2-\xDF][\x80-\xBF])+ 3113 ) 3114 `? # Name can be escaped with a backtick. 3115 (?: # Optional sub part. 3116 \s* # Optional white space character between name and opening bracket. 3117 \( # Opening bracket for the sub part. 3118 \s* # Optional white space character after opening bracket. 3119 (?P<sub_part> 3120 \d+ # 2) Number of indexed characters. 3121 ) 3122 \s* # Optional white space character before closing bracket. 3123 \) # Closing bracket for the sub part. 3124 )? 3125 /x', 3126 $index_column, 3127 $index_column_matches 3128 ); 3129 3130 // Escape the column name with backticks. 3131 $index_column = '`' . $index_column_matches['column_name'] . '`'; 3132 3133 // We don't need to add the subpart to $index_columns_without_subparts 3134 $index_columns_without_subparts[ $id ] = $index_column; 3135 3136 // Append the optional sup part with the number of indexed characters. 3137 if ( isset( $index_column_matches['sub_part'] ) ) { 3138 $index_column .= '(' . $index_column_matches['sub_part'] . ')'; 3139 } 3140 } 3141 3142 // Build the normalized index definition and add it to the list of indices. 3143 $indices[] = "{$index_type} {$index_name} (" . implode( ',', $index_columns ) . ')'; 3144 $indices_without_subparts[] = "{$index_type} {$index_name} (" . implode( ',', $index_columns_without_subparts ) . ')'; 3145 3146 // Destroy no longer needed variables. 3147 unset( $index_column, $index_column_matches, $index_matches, $index_type, $index_name, $index_columns, $index_columns_without_subparts ); 3148 3149 break; 3150 } 3151 3152 // If it's a valid field, add it to the field array. 3153 if ( $validfield ) { 3154 $cfields[ $fieldname_lowercased ] = $fld; 3155 } 3156 } 3157 3158 // For every field in the table. 3159 foreach ( $tablefields as $tablefield ) { 3160 $tablefield_field_lowercased = strtolower( $tablefield->Field ); 3161 $tablefield_type_lowercased = strtolower( $tablefield->Type ); 3162 3163 $tablefield_type_without_parentheses = preg_replace( 3164 '/' 3165 . '(.+)' // Field type, e.g. `int`. 3166 . '\(\d*\)' // Display width. 3167 . '(.*)' // Optional attributes, e.g. `unsigned`. 3168 . '/', 3169 '$1$2', 3170 $tablefield_type_lowercased 3171 ); 3172 3173 // Get the type without attributes, e.g. `int`. 3174 $tablefield_type_base = strtok( $tablefield_type_without_parentheses, ' ' ); 3175 3176 // If the table field exists in the field array... 3177 if ( array_key_exists( $tablefield_field_lowercased, $cfields ) ) { 3178 3179 // Get the field type from the query. 3180 preg_match( '|`?' . $tablefield->Field . '`? ([^ ]*( unsigned)?)|i', $cfields[ $tablefield_field_lowercased ], $matches ); 3181 $fieldtype = $matches[1]; 3182 $fieldtype_lowercased = strtolower( $fieldtype ); 3183 3184 $fieldtype_without_parentheses = preg_replace( 3185 '/' 3186 . '(.+)' // Field type, e.g. `int`. 3187 . '\(\d*\)' // Display width. 3188 . '(.*)' // Optional attributes, e.g. `unsigned`. 3189 . '/', 3190 '$1$2', 3191 $fieldtype_lowercased 3192 ); 3193 3194 // Get the type without attributes, e.g. `int`. 3195 $fieldtype_base = strtok( $fieldtype_without_parentheses, ' ' ); 3196 3197 // Is actual field type different from the field type in query? 3198 if ( $tablefield->Type !== $fieldtype_lowercased ) { 3199 $do_change = true; 3200 if ( in_array( $fieldtype_lowercased, $text_fields, true ) && in_array( $tablefield_type_lowercased, $text_fields, true ) ) { 3201 if ( array_search( $fieldtype_lowercased, $text_fields, true ) < array_search( $tablefield_type_lowercased, $text_fields, true ) ) { 3202 $do_change = false; 3203 } 3204 } 3205 3206 if ( in_array( $fieldtype_lowercased, $blob_fields, true ) && in_array( $tablefield_type_lowercased, $blob_fields, true ) ) { 3207 if ( array_search( $fieldtype_lowercased, $blob_fields, true ) < array_search( $tablefield_type_lowercased, $blob_fields, true ) ) { 3208 $do_change = false; 3209 } 3210 } 3211 3212 if ( in_array( $fieldtype_base, $int_fields, true ) && in_array( $tablefield_type_base, $int_fields, true ) 3213 && $fieldtype_without_parentheses === $tablefield_type_without_parentheses 3214 ) { 3215 /* 3216 * MySQL 8.0.17 or later does not support display width for integer data types, 3217 * so if display width is the only difference, it can be safely ignored. 3218 * Note: This is specific to MySQL and does not affect MariaDB. 3219 */ 3220 if ( version_compare( $db_version, '8.0.17', '>=' ) 3221 && ! str_contains( $db_server_info, 'MariaDB' ) 3222 ) { 3223 $do_change = false; 3224 } 3225 } 3226 3227 if ( $do_change ) { 3228 // Add a query to change the column type. 3229 $cqueries[] = "ALTER TABLE {$table} CHANGE COLUMN `{$tablefield->Field}` " . $cfields[ $tablefield_field_lowercased ]; 3230 3231 $for_update[ $table . '.' . $tablefield->Field ] = "Changed type of {$table}.{$tablefield->Field} from {$tablefield->Type} to {$fieldtype}"; 3232 } 3233 } 3234 3235 // Get the default value from the array. 3236 if ( preg_match( "| DEFAULT '(.*?)'|i", $cfields[ $tablefield_field_lowercased ], $matches ) ) { 3237 $default_value = $matches[1]; 3238 if ( $tablefield->Default !== $default_value ) { 3239 // Add a query to change the column's default value 3240 $cqueries[] = "ALTER TABLE {$table} ALTER COLUMN `{$tablefield->Field}` SET DEFAULT '{$default_value}'"; 3241 3242 $for_update[ $table . '.' . $tablefield->Field ] = "Changed default value of {$table}.{$tablefield->Field} from {$tablefield->Default} to {$default_value}"; 3243 } 3244 } 3245 3246 // Remove the field from the array (so it's not added). 3247 unset( $cfields[ $tablefield_field_lowercased ] ); 3248 } else { 3249 // This field exists in the table, but not in the creation queries? 3250 } 3251 } 3252 3253 // For every remaining field specified for the table. 3254 foreach ( $cfields as $fieldname => $fielddef ) { 3255 // Push a query line into $cqueries that adds the field to that table. 3256 $cqueries[] = "ALTER TABLE {$table} ADD COLUMN $fielddef"; 3257 3258 $for_update[ $table . '.' . $fieldname ] = 'Added column ' . $table . '.' . $fieldname; 3259 } 3260 3261 // Index stuff goes here. Fetch the table index structure from the database. 3262 $tableindices = $wpdb->get_results( "SHOW INDEX FROM {$table};" ); 3263 3264 if ( $tableindices ) { 3265 // Clear the index array. 3266 $index_ary = array(); 3267 3268 // For every index in the table. 3269 foreach ( $tableindices as $tableindex ) { 3270 $keyname = strtolower( $tableindex->Key_name ); 3271 3272 // Add the index to the index data array. 3273 $index_ary[ $keyname ]['columns'][] = array( 3274 'fieldname' => $tableindex->Column_name, 3275 'subpart' => $tableindex->Sub_part, 3276 ); 3277 $index_ary[ $keyname ]['unique'] = '0' === (string) $tableindex->Non_unique; 3278 $index_ary[ $keyname ]['index_type'] = $tableindex->Index_type; 3279 } 3280 3281 // For each actual index in the index array. 3282 foreach ( $index_ary as $index_name => $index_data ) { 3283 3284 // Build a create string to compare to the query. 3285 $index_string = ''; 3286 if ( 'primary' === $index_name ) { 3287 $index_string .= 'PRIMARY '; 3288 } elseif ( $index_data['unique'] ) { 3289 $index_string .= 'UNIQUE '; 3290 } 3291 3292 if ( 'FULLTEXT' === strtoupper( $index_data['index_type'] ) ) { 3293 $index_string .= 'FULLTEXT '; 3294 } 3295 3296 if ( 'SPATIAL' === strtoupper( $index_data['index_type'] ) ) { 3297 $index_string .= 'SPATIAL '; 3298 } 3299 3300 $index_string .= 'KEY '; 3301 if ( 'primary' !== $index_name ) { 3302 $index_string .= '`' . $index_name . '`'; 3303 } 3304 3305 $index_columns = ''; 3306 3307 // For each column in the index. 3308 foreach ( $index_data['columns'] as $column_data ) { 3309 if ( '' !== $index_columns ) { 3310 $index_columns .= ','; 3311 } 3312 3313 // Add the field to the column list string. 3314 $index_columns .= '`' . $column_data['fieldname'] . '`'; 3315 } 3316 3317 // Add the column list to the index create string. 3318 $index_string .= " ($index_columns)"; 3319 3320 // Check if the index definition exists, ignoring subparts. 3321 $aindex = array_search( $index_string, $indices_without_subparts, true ); 3322 if ( false !== $aindex ) { 3323 // If the index already exists (even with different subparts), we don't need to create it. 3324 unset( $indices_without_subparts[ $aindex ] ); 3325 unset( $indices[ $aindex ] ); 3326 } 3327 } 3328 } 3329 3330 // For every remaining index specified for the table. 3331 foreach ( (array) $indices as $index ) { 3332 // Push a query line into $cqueries that adds the index to that table. 3333 $cqueries[] = "ALTER TABLE {$table} ADD $index"; 3334 3335 $for_update[] = 'Added index ' . $table . ' ' . $index; 3336 } 3337 3338 // Remove the original table creation query from processing. 3339 unset( $cqueries[ $table ], $for_update[ $table ] ); 3340 } 3341 3342 $allqueries = array_merge( $cqueries, $iqueries ); 3343 if ( $execute ) { 3344 foreach ( $allqueries as $query ) { 3345 $wpdb->query( $query ); 3346 } 3347 } 3348 3349 return $for_update; 3350 } 3351 3352 /** 3353 * Updates the database tables to a new schema. 3354 * 3355 * By default, updates all the tables to use the latest defined schema, but can also 3356 * be used to update a specific set of tables in wp_get_db_schema(). 3357 * 3358 * @since 1.5.0 3359 * 3360 * @uses dbDelta 3361 * 3362 * @param string $tables Optional. Which set of tables to update. Default is 'all'. 3363 */ 3364 function make_db_current( $tables = 'all' ) { 3365 $alterations = dbDelta( $tables ); 3366 echo "<ol>\n"; 3367 foreach ( $alterations as $alteration ) { 3368 echo "<li>$alteration</li>\n"; 3369 } 3370 echo "</ol>\n"; 3371 } 3372 3373 /** 3374 * Updates the database tables to a new schema, but without displaying results. 3375 * 3376 * By default, updates all the tables to use the latest defined schema, but can 3377 * also be used to update a specific set of tables in wp_get_db_schema(). 3378 * 3379 * @since 1.5.0 3380 * 3381 * @see make_db_current() 3382 * 3383 * @param string $tables Optional. Which set of tables to update. Default is 'all'. 3384 */ 3385 function make_db_current_silent( $tables = 'all' ) { 3386 dbDelta( $tables ); 3387 } 3388 3389 /** 3390 * Creates a site theme from an existing theme. 3391 * 3392 * {@internal Missing Long Description}} 3393 * 3394 * @since 1.5.0 3395 * 3396 * @param string $theme_name The name of the theme. 3397 * @param string $template The directory name of the theme. 3398 * @return bool True on success, false on failure. 3399 */ 3400 function make_site_theme_from_oldschool( $theme_name, $template ) { 3401 $home_path = get_home_path(); 3402 $site_dir = WP_CONTENT_DIR . "/themes/$template"; 3403 $default_dir = WP_CONTENT_DIR . '/themes/' . WP_DEFAULT_THEME; 3404 3405 if ( ! file_exists( "$home_path/index.php" ) ) { 3406 return false; 3407 } 3408 3409 /* 3410 * Copy files from the old locations to the site theme. 3411 * TODO: This does not copy arbitrary include dependencies. Only the standard WP files are copied. 3412 */ 3413 $files = array( 3414 'index.php' => 'index.php', 3415 'wp-layout.css' => 'style.css', 3416 'wp-comments.php' => 'comments.php', 3417 'wp-comments-popup.php' => 'comments-popup.php', 3418 ); 3419 3420 foreach ( $files as $oldfile => $newfile ) { 3421 if ( 'index.php' === $oldfile ) { 3422 $oldpath = $home_path; 3423 } else { 3424 $oldpath = ABSPATH; 3425 } 3426 3427 // Check to make sure it's not a new index. 3428 if ( 'index.php' === $oldfile ) { 3429 $index = implode( '', file( "$oldpath/$oldfile" ) ); 3430 if ( str_contains( $index, 'WP_USE_THEMES' ) ) { 3431 if ( ! copy( "$default_dir/$oldfile", "$site_dir/$newfile" ) ) { 3432 return false; 3433 } 3434 3435 // Don't copy anything. 3436 continue; 3437 } 3438 } 3439 3440 if ( ! copy( "$oldpath/$oldfile", "$site_dir/$newfile" ) ) { 3441 return false; 3442 } 3443 3444 chmod( "$site_dir/$newfile", 0777 ); 3445 3446 // Update the blog header include in each file. 3447 $lines = explode( "\n", implode( '', file( "$site_dir/$newfile" ) ) ); 3448 if ( $lines ) { 3449 $f = fopen( "$site_dir/$newfile", 'w' ); 3450 3451 foreach ( $lines as $line ) { 3452 if ( preg_match( '/require.*wp-blog-header/', $line ) ) { 3453 $line = '//' . $line; 3454 } 3455 3456 // Update stylesheet references. 3457 $line = str_replace( 3458 "<?php echo __get_option('siteurl'); ?>/wp-layout.css", 3459 "<?php bloginfo('stylesheet_url'); ?>", 3460 $line 3461 ); 3462 3463 // Update comments template inclusion. 3464 $line = str_replace( 3465 "<?php include(ABSPATH . 'wp-comments.php'); ?>", 3466 '<?php comments_template(); ?>', 3467 $line 3468 ); 3469 3470 fwrite( $f, "{$line}\n" ); 3471 } 3472 fclose( $f ); 3473 } 3474 } 3475 3476 // Add a theme header. 3477 $header = "/*\n" . 3478 "Theme Name: $theme_name\n" . 3479 'Theme URI: ' . __get_option( 'siteurl' ) . "\n" . 3480 "Description: A theme automatically created by the update.\n" . 3481 "Version: 1.0\n" . 3482 "Author: Moi\n" . 3483 "*/\n"; 3484 3485 $stylelines = file_get_contents( "$site_dir/style.css" ); 3486 if ( $stylelines ) { 3487 $f = fopen( "$site_dir/style.css", 'w' ); 3488 3489 fwrite( $f, $header ); 3490 fwrite( $f, $stylelines ); 3491 fclose( $f ); 3492 } 3493 3494 return true; 3495 } 3496 3497 /** 3498 * Creates a site theme from the default theme. 3499 * 3500 * {@internal Missing Long Description}} 3501 * 3502 * @since 1.5.0 3503 * 3504 * @param string $theme_name The name of the theme. 3505 * @param string $template The directory name of the theme. 3506 * @return void|false 3507 */ 3508 function make_site_theme_from_default( $theme_name, $template ) { 3509 $site_dir = WP_CONTENT_DIR . "/themes/$template"; 3510 $default_dir = WP_CONTENT_DIR . '/themes/' . WP_DEFAULT_THEME; 3511 3512 /* 3513 * Copy files from the default theme to the site theme. 3514 * $files = array( 'index.php', 'comments.php', 'comments-popup.php', 'footer.php', 'header.php', 'sidebar.php', 'style.css' ); 3515 */ 3516 3517 $theme_dir = @opendir( $default_dir ); 3518 if ( $theme_dir ) { 3519 while ( ( $theme_file = readdir( $theme_dir ) ) !== false ) { 3520 if ( is_dir( "$default_dir/$theme_file" ) ) { 3521 continue; 3522 } 3523 3524 if ( ! copy( "$default_dir/$theme_file", "$site_dir/$theme_file" ) ) { 3525 return; 3526 } 3527 3528 chmod( "$site_dir/$theme_file", 0777 ); 3529 } 3530 3531 closedir( $theme_dir ); 3532 } 3533 3534 // Rewrite the theme header. 3535 $stylelines = explode( "\n", implode( '', file( "$site_dir/style.css" ) ) ); 3536 if ( $stylelines ) { 3537 $f = fopen( "$site_dir/style.css", 'w' ); 3538 3539 $headers = array( 3540 'Theme Name:' => $theme_name, 3541 'Theme URI:' => __get_option( 'url' ), 3542 'Description:' => 'Your theme.', 3543 'Version:' => '1', 3544 'Author:' => 'You', 3545 ); 3546 3547 foreach ( $stylelines as $line ) { 3548 foreach ( $headers as $header => $value ) { 3549 if ( str_contains( $line, $header ) ) { 3550 $line = $header . ' ' . $value; 3551 break; 3552 } 3553 } 3554 3555 fwrite( $f, $line . "\n" ); 3556 } 3557 3558 fclose( $f ); 3559 } 3560 3561 // Copy the images. 3562 umask( 0 ); 3563 if ( ! mkdir( "$site_dir/images", 0777 ) ) { 3564 return false; 3565 } 3566 3567 $images_dir = @opendir( "$default_dir/images" ); 3568 if ( $images_dir ) { 3569 while ( ( $image = readdir( $images_dir ) ) !== false ) { 3570 if ( is_dir( "$default_dir/images/$image" ) ) { 3571 continue; 3572 } 3573 3574 if ( ! copy( "$default_dir/images/$image", "$site_dir/images/$image" ) ) { 3575 return; 3576 } 3577 3578 chmod( "$site_dir/images/$image", 0777 ); 3579 } 3580 3581 closedir( $images_dir ); 3582 } 3583 } 3584 3585 /** 3586 * Creates a site theme. 3587 * 3588 * {@internal Missing Long Description}} 3589 * 3590 * @since 1.5.0 3591 * 3592 * @return string|false 3593 */ 3594 function make_site_theme() { 3595 // Name the theme after the blog. 3596 $theme_name = __get_option( 'blogname' ); 3597 $template = sanitize_title( $theme_name ); 3598 $site_dir = WP_CONTENT_DIR . "/themes/$template"; 3599 3600 // If the theme already exists, nothing to do. 3601 if ( is_dir( $site_dir ) ) { 3602 return false; 3603 } 3604 3605 // We must be able to write to the themes dir. 3606 if ( ! is_writable( WP_CONTENT_DIR . '/themes' ) ) { 3607 return false; 3608 } 3609 3610 umask( 0 ); 3611 if ( ! mkdir( $site_dir, 0777 ) ) { 3612 return false; 3613 } 3614 3615 if ( file_exists( ABSPATH . 'wp-layout.css' ) ) { 3616 if ( ! make_site_theme_from_oldschool( $theme_name, $template ) ) { 3617 // TODO: rm -rf the site theme directory. 3618 return false; 3619 } 3620 } else { 3621 if ( ! make_site_theme_from_default( $theme_name, $template ) ) { 3622 // TODO: rm -rf the site theme directory. 3623 return false; 3624 } 3625 } 3626 3627 // Make the new site theme active. 3628 $current_template = __get_option( 'template' ); 3629 if ( WP_DEFAULT_THEME === $current_template ) { 3630 update_option( 'template', $template ); 3631 update_option( 'stylesheet', $template ); 3632 } 3633 return $template; 3634 } 3635 3636 /** 3637 * Translate user level to user role name. 3638 * 3639 * @since 2.0.0 3640 * 3641 * @param int $level User level. 3642 * @return string User role name. 3643 */ 3644 function translate_level_to_role( $level ) { 3645 switch ( $level ) { 3646 case 10: 3647 case 9: 3648 case 8: 3649 return 'administrator'; 3650 case 7: 3651 case 6: 3652 case 5: 3653 return 'editor'; 3654 case 4: 3655 case 3: 3656 case 2: 3657 return 'author'; 3658 case 1: 3659 return 'contributor'; 3660 case 0: 3661 default: 3662 return 'subscriber'; 3663 } 3664 } 3665 3666 /** 3667 * Checks the version of the installed MySQL binary. 3668 * 3669 * @since 2.1.0 3670 * 3671 * @global wpdb $wpdb WordPress database abstraction object. 3672 */ 3673 function wp_check_mysql_version() { 3674 global $wpdb; 3675 $result = $wpdb->check_database_version(); 3676 if ( is_wp_error( $result ) ) { 3677 wp_die( $result ); 3678 } 3679 } 3680 3681 /** 3682 * Disables the Automattic widgets plugin, which was merged into core. 3683 * 3684 * @since 2.2.0 3685 */ 3686 function maybe_disable_automattic_widgets() { 3687 $plugins = __get_option( 'active_plugins' ); 3688 3689 foreach ( (array) $plugins as $plugin ) { 3690 if ( 'widgets.php' === basename( $plugin ) ) { 3691 array_splice( $plugins, array_search( $plugin, $plugins, true ), 1 ); 3692 update_option( 'active_plugins', $plugins ); 3693 break; 3694 } 3695 } 3696 } 3697 3698 /** 3699 * Disables the Link Manager on upgrade if, at the time of upgrade, no links exist in the DB. 3700 * 3701 * @since 3.5.0 3702 * 3703 * @global int $wp_current_db_version The old (current) database version. 3704 * @global wpdb $wpdb WordPress database abstraction object. 3705 */ 3706 function maybe_disable_link_manager() { 3707 global $wp_current_db_version, $wpdb; 3708 3709 if ( $wp_current_db_version >= 22006 && get_option( 'link_manager_enabled' ) && ! $wpdb->get_var( "SELECT link_id FROM $wpdb->links LIMIT 1" ) ) { 3710 update_option( 'link_manager_enabled', 0 ); 3711 } 3712 } 3713 3714 /** 3715 * Runs before the schema is upgraded. 3716 * 3717 * @since 2.9.0 3718 * 3719 * @global int $wp_current_db_version The old (current) database version. 3720 * @global wpdb $wpdb WordPress database abstraction object. 3721 */ 3722 function pre_schema_upgrade() { 3723 global $wp_current_db_version, $wpdb; 3724 3725 // Upgrade versions prior to 2.9. 3726 if ( $wp_current_db_version < 11557 ) { 3727 // Delete duplicate options. Keep the option with the highest option_id. 3728 $wpdb->query( "DELETE o1 FROM $wpdb->options AS o1 JOIN $wpdb->options AS o2 USING (`option_name`) WHERE o2.option_id > o1.option_id" ); 3729 3730 // Drop the old primary key and add the new. 3731 $wpdb->query( "ALTER TABLE $wpdb->options DROP PRIMARY KEY, ADD PRIMARY KEY(option_id)" ); 3732 3733 // Drop the old option_name index. dbDelta() doesn't do the drop. 3734 $wpdb->query( "ALTER TABLE $wpdb->options DROP INDEX option_name" ); 3735 } 3736 3737 // Multisite schema upgrades. 3738 if ( $wp_current_db_version < 60497 && is_multisite() && wp_should_upgrade_global_tables() ) { 3739 3740 // Upgrade versions prior to 3.7. 3741 if ( $wp_current_db_version < 25179 ) { 3742 // New primary key for signups. 3743 $wpdb->query( "ALTER TABLE $wpdb->signups ADD signup_id BIGINT(20) NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST" ); 3744 $wpdb->query( "ALTER TABLE $wpdb->signups DROP INDEX domain" ); 3745 } 3746 3747 if ( $wp_current_db_version < 25448 ) { 3748 // Convert archived from enum to tinyint. 3749 $wpdb->query( "ALTER TABLE $wpdb->blogs CHANGE COLUMN archived archived varchar(1) NOT NULL default '0'" ); 3750 $wpdb->query( "ALTER TABLE $wpdb->blogs CHANGE COLUMN archived archived tinyint(2) NOT NULL default 0" ); 3751 } 3752 3753 // Upgrade versions prior to 6.9 3754 if ( $wp_current_db_version < 60497 ) { 3755 // Convert ID columns from signed to unsigned 3756 $wpdb->query( "ALTER TABLE $wpdb->blogs MODIFY blog_id bigint(20) unsigned NOT NULL auto_increment" ); 3757 $wpdb->query( "ALTER TABLE $wpdb->blogs MODIFY site_id bigint(20) unsigned NOT NULL default 0" ); 3758 $wpdb->query( "ALTER TABLE $wpdb->blogmeta MODIFY blog_id bigint(20) unsigned NOT NULL default 0" ); 3759 $wpdb->query( "ALTER TABLE $wpdb->registration_log MODIFY ID bigint(20) unsigned NOT NULL auto_increment" ); 3760 $wpdb->query( "ALTER TABLE $wpdb->registration_log MODIFY blog_id bigint(20) unsigned NOT NULL default 0" ); 3761 $wpdb->query( "ALTER TABLE $wpdb->site MODIFY id bigint(20) unsigned NOT NULL auto_increment" ); 3762 $wpdb->query( "ALTER TABLE $wpdb->sitemeta MODIFY meta_id bigint(20) unsigned NOT NULL auto_increment" ); 3763 $wpdb->query( "ALTER TABLE $wpdb->sitemeta MODIFY site_id bigint(20) unsigned NOT NULL default 0" ); 3764 $wpdb->query( "ALTER TABLE $wpdb->signups MODIFY signup_id bigint(20) unsigned NOT NULL auto_increment" ); 3765 } 3766 } 3767 3768 // Upgrade versions prior to 4.2. 3769 if ( $wp_current_db_version < 31351 ) { 3770 if ( ! is_multisite() && wp_should_upgrade_global_tables() ) { 3771 $wpdb->query( "ALTER TABLE $wpdb->usermeta DROP INDEX meta_key, ADD INDEX meta_key(meta_key(191))" ); 3772 } 3773 $wpdb->query( "ALTER TABLE $wpdb->terms DROP INDEX slug, ADD INDEX slug(slug(191))" ); 3774 $wpdb->query( "ALTER TABLE $wpdb->terms DROP INDEX name, ADD INDEX name(name(191))" ); 3775 $wpdb->query( "ALTER TABLE $wpdb->commentmeta DROP INDEX meta_key, ADD INDEX meta_key(meta_key(191))" ); 3776 $wpdb->query( "ALTER TABLE $wpdb->postmeta DROP INDEX meta_key, ADD INDEX meta_key(meta_key(191))" ); 3777 $wpdb->query( "ALTER TABLE $wpdb->posts DROP INDEX post_name, ADD INDEX post_name(post_name(191))" ); 3778 } 3779 3780 // Upgrade versions prior to 4.4. 3781 if ( $wp_current_db_version < 34978 ) { 3782 // If compatible termmeta table is found, use it, but enforce a proper index and update collation. 3783 if ( $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->termmeta}'" ) && $wpdb->get_results( "SHOW INDEX FROM {$wpdb->termmeta} WHERE Column_name = 'meta_key'" ) ) { 3784 $wpdb->query( "ALTER TABLE $wpdb->termmeta DROP INDEX meta_key, ADD INDEX meta_key(meta_key(191))" ); 3785 maybe_convert_table_to_utf8mb4( $wpdb->termmeta ); 3786 } 3787 } 3788 } 3789 3790 /** 3791 * Determine if global tables should be upgraded. 3792 * 3793 * This function performs a series of checks to ensure the environment allows 3794 * for the safe upgrading of global WordPress database tables. It is necessary 3795 * because global tables will commonly grow to millions of rows on large 3796 * installations, and the ability to control their upgrade routines can be 3797 * critical to the operation of large networks. 3798 * 3799 * In a future iteration, this function may use `wp_is_large_network()` to more- 3800 * intelligently prevent global table upgrades. Until then, we make sure 3801 * WordPress is on the main site of the main network, to avoid running queries 3802 * more than once in multi-site or multi-network environments. 3803 * 3804 * @since 4.3.0 3805 * 3806 * @return bool Whether to run the upgrade routines on global tables. 3807 */ 3808 function wp_should_upgrade_global_tables() { 3809 3810 // Return false early if explicitly not upgrading. 3811 if ( defined( 'DO_NOT_UPGRADE_GLOBAL_TABLES' ) ) { 3812 return false; 3813 } 3814 3815 // Assume global tables should be upgraded. 3816 $should_upgrade = true; 3817 3818 // Set to false if not on main network (does not matter if not multi-network). 3819 if ( ! is_main_network() ) { 3820 $should_upgrade = false; 3821 } 3822 3823 // Set to false if not on main site of current network (does not matter if not multi-site). 3824 if ( ! is_main_site() ) { 3825 $should_upgrade = false; 3826 } 3827 3828 /** 3829 * Filters if upgrade routines should be run on global tables. 3830 * 3831 * @since 4.3.0 3832 * 3833 * @param bool $should_upgrade Whether to run the upgrade routines on global tables. 3834 */ 3835 return apply_filters( 'wp_should_upgrade_global_tables', $should_upgrade ); 3836 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Tue Oct 13 08:20:33 2026 | Cross-referenced by PHPXref |