WordPress 4.5
[autoinstalls/wordpress.git] / wp-admin / includes / schema.php
1 <?php
2 /**
3  * WordPress Administration Scheme API
4  *
5  * Here we keep the DB structure and option values.
6  *
7  * @package WordPress
8  * @subpackage Administration
9  */
10
11 /**
12  * Declare these as global in case schema.php is included from a function.
13  *
14  * @global wpdb   $wpdb
15  * @global array  $wp_queries
16  * @global string $charset_collate
17  */
18 global $wpdb, $wp_queries, $charset_collate;
19
20 /**
21  * The database character collate.
22  */
23 $charset_collate = $wpdb->get_charset_collate();
24
25 /**
26  * Retrieve the SQL for creating database tables.
27  *
28  * @since 3.3.0
29  *
30  * @global wpdb $wpdb WordPress database abstraction object.
31  *
32  * @param string $scope Optional. The tables for which to retrieve SQL. Can be all, global, ms_global, or blog tables. Defaults to all.
33  * @param int $blog_id Optional. The site ID for which to retrieve SQL. Default is the current site ID.
34  * @return string The SQL needed to create the requested tables.
35  */
36 function wp_get_db_schema( $scope = 'all', $blog_id = null ) {
37         global $wpdb;
38
39         $charset_collate = '';
40
41         if ( ! empty($wpdb->charset) )
42                 $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
43         if ( ! empty($wpdb->collate) )
44                 $charset_collate .= " COLLATE $wpdb->collate";
45
46         if ( $blog_id && $blog_id != $wpdb->blogid )
47                 $old_blog_id = $wpdb->set_blog_id( $blog_id );
48
49         // Engage multisite if in the middle of turning it on from network.php.
50         $is_multisite = is_multisite() || ( defined( 'WP_INSTALLING_NETWORK' ) && WP_INSTALLING_NETWORK );
51
52         /*
53          * Indexes have a maximum size of 767 bytes. Historically, we haven't need to be concerned about that.
54          * As of 4.2, however, we moved to utf8mb4, which uses 4 bytes per character. This means that an index which
55          * used to have room for floor(767/3) = 255 characters, now only has room for floor(767/4) = 191 characters.
56          */
57         $max_index_length = 191;
58
59         // Blog specific tables.
60         $blog_tables = "CREATE TABLE $wpdb->termmeta (
61   meta_id bigint(20) unsigned NOT NULL auto_increment,
62   term_id bigint(20) unsigned NOT NULL default '0',
63   meta_key varchar(255) default NULL,
64   meta_value longtext,
65   PRIMARY KEY  (meta_id),
66   KEY term_id (term_id),
67   KEY meta_key (meta_key($max_index_length))
68 ) $charset_collate;
69 CREATE TABLE $wpdb->terms (
70  term_id bigint(20) unsigned NOT NULL auto_increment,
71  name varchar(200) NOT NULL default '',
72  slug varchar(200) NOT NULL default '',
73  term_group bigint(10) NOT NULL default 0,
74  PRIMARY KEY  (term_id),
75  KEY slug (slug($max_index_length)),
76  KEY name (name($max_index_length))
77 ) $charset_collate;
78 CREATE TABLE $wpdb->term_taxonomy (
79  term_taxonomy_id bigint(20) unsigned NOT NULL auto_increment,
80  term_id bigint(20) unsigned NOT NULL default 0,
81  taxonomy varchar(32) NOT NULL default '',
82  description longtext NOT NULL,
83  parent bigint(20) unsigned NOT NULL default 0,
84  count bigint(20) NOT NULL default 0,
85  PRIMARY KEY  (term_taxonomy_id),
86  UNIQUE KEY term_id_taxonomy (term_id,taxonomy),
87  KEY taxonomy (taxonomy)
88 ) $charset_collate;
89 CREATE TABLE $wpdb->term_relationships (
90  object_id bigint(20) unsigned NOT NULL default 0,
91  term_taxonomy_id bigint(20) unsigned NOT NULL default 0,
92  term_order int(11) NOT NULL default 0,
93  PRIMARY KEY  (object_id,term_taxonomy_id),
94  KEY term_taxonomy_id (term_taxonomy_id)
95 ) $charset_collate;
96 CREATE TABLE $wpdb->commentmeta (
97   meta_id bigint(20) unsigned NOT NULL auto_increment,
98   comment_id bigint(20) unsigned NOT NULL default '0',
99   meta_key varchar(255) default NULL,
100   meta_value longtext,
101   PRIMARY KEY  (meta_id),
102   KEY comment_id (comment_id),
103   KEY meta_key (meta_key($max_index_length))
104 ) $charset_collate;
105 CREATE TABLE $wpdb->comments (
106   comment_ID bigint(20) unsigned NOT NULL auto_increment,
107   comment_post_ID bigint(20) unsigned NOT NULL default '0',
108   comment_author tinytext NOT NULL,
109   comment_author_email varchar(100) NOT NULL default '',
110   comment_author_url varchar(200) NOT NULL default '',
111   comment_author_IP varchar(100) NOT NULL default '',
112   comment_date datetime NOT NULL default '0000-00-00 00:00:00',
113   comment_date_gmt datetime NOT NULL default '0000-00-00 00:00:00',
114   comment_content text NOT NULL,
115   comment_karma int(11) NOT NULL default '0',
116   comment_approved varchar(20) NOT NULL default '1',
117   comment_agent varchar(255) NOT NULL default '',
118   comment_type varchar(20) NOT NULL default '',
119   comment_parent bigint(20) unsigned NOT NULL default '0',
120   user_id bigint(20) unsigned NOT NULL default '0',
121   PRIMARY KEY  (comment_ID),
122   KEY comment_post_ID (comment_post_ID),
123   KEY comment_approved_date_gmt (comment_approved,comment_date_gmt),
124   KEY comment_date_gmt (comment_date_gmt),
125   KEY comment_parent (comment_parent),
126   KEY comment_author_email (comment_author_email(10))
127 ) $charset_collate;
128 CREATE TABLE $wpdb->links (
129   link_id bigint(20) unsigned NOT NULL auto_increment,
130   link_url varchar(255) NOT NULL default '',
131   link_name varchar(255) NOT NULL default '',
132   link_image varchar(255) NOT NULL default '',
133   link_target varchar(25) NOT NULL default '',
134   link_description varchar(255) NOT NULL default '',
135   link_visible varchar(20) NOT NULL default 'Y',
136   link_owner bigint(20) unsigned NOT NULL default '1',
137   link_rating int(11) NOT NULL default '0',
138   link_updated datetime NOT NULL default '0000-00-00 00:00:00',
139   link_rel varchar(255) NOT NULL default '',
140   link_notes mediumtext NOT NULL,
141   link_rss varchar(255) NOT NULL default '',
142   PRIMARY KEY  (link_id),
143   KEY link_visible (link_visible)
144 ) $charset_collate;
145 CREATE TABLE $wpdb->options (
146   option_id bigint(20) unsigned NOT NULL auto_increment,
147   option_name varchar(191) NOT NULL default '',
148   option_value longtext NOT NULL,
149   autoload varchar(20) NOT NULL default 'yes',
150   PRIMARY KEY  (option_id),
151   UNIQUE KEY option_name (option_name)
152 ) $charset_collate;
153 CREATE TABLE $wpdb->postmeta (
154   meta_id bigint(20) unsigned NOT NULL auto_increment,
155   post_id bigint(20) unsigned NOT NULL default '0',
156   meta_key varchar(255) default NULL,
157   meta_value longtext,
158   PRIMARY KEY  (meta_id),
159   KEY post_id (post_id),
160   KEY meta_key (meta_key($max_index_length))
161 ) $charset_collate;
162 CREATE TABLE $wpdb->posts (
163   ID bigint(20) unsigned NOT NULL auto_increment,
164   post_author bigint(20) unsigned NOT NULL default '0',
165   post_date datetime NOT NULL default '0000-00-00 00:00:00',
166   post_date_gmt datetime NOT NULL default '0000-00-00 00:00:00',
167   post_content longtext NOT NULL,
168   post_title text NOT NULL,
169   post_excerpt text NOT NULL,
170   post_status varchar(20) NOT NULL default 'publish',
171   comment_status varchar(20) NOT NULL default 'open',
172   ping_status varchar(20) NOT NULL default 'open',
173   post_password varchar(20) NOT NULL default '',
174   post_name varchar(200) NOT NULL default '',
175   to_ping text NOT NULL,
176   pinged text NOT NULL,
177   post_modified datetime NOT NULL default '0000-00-00 00:00:00',
178   post_modified_gmt datetime NOT NULL default '0000-00-00 00:00:00',
179   post_content_filtered longtext NOT NULL,
180   post_parent bigint(20) unsigned NOT NULL default '0',
181   guid varchar(255) NOT NULL default '',
182   menu_order int(11) NOT NULL default '0',
183   post_type varchar(20) NOT NULL default 'post',
184   post_mime_type varchar(100) NOT NULL default '',
185   comment_count bigint(20) NOT NULL default '0',
186   PRIMARY KEY  (ID),
187   KEY post_name (post_name($max_index_length)),
188   KEY type_status_date (post_type,post_status,post_date,ID),
189   KEY post_parent (post_parent),
190   KEY post_author (post_author)
191 ) $charset_collate;\n";
192
193         // Single site users table. The multisite flavor of the users table is handled below.
194         $users_single_table = "CREATE TABLE $wpdb->users (
195   ID bigint(20) unsigned NOT NULL auto_increment,
196   user_login varchar(60) NOT NULL default '',
197   user_pass varchar(255) NOT NULL default '',
198   user_nicename varchar(50) NOT NULL default '',
199   user_email varchar(100) NOT NULL default '',
200   user_url varchar(100) NOT NULL default '',
201   user_registered datetime NOT NULL default '0000-00-00 00:00:00',
202   user_activation_key varchar(255) NOT NULL default '',
203   user_status int(11) NOT NULL default '0',
204   display_name varchar(250) NOT NULL default '',
205   PRIMARY KEY  (ID),
206   KEY user_login_key (user_login),
207   KEY user_nicename (user_nicename),
208   KEY user_email (user_email)
209 ) $charset_collate;\n";
210
211         // Multisite users table
212         $users_multi_table = "CREATE TABLE $wpdb->users (
213   ID bigint(20) unsigned NOT NULL auto_increment,
214   user_login varchar(60) NOT NULL default '',
215   user_pass varchar(255) NOT NULL default '',
216   user_nicename varchar(50) NOT NULL default '',
217   user_email varchar(100) NOT NULL default '',
218   user_url varchar(100) NOT NULL default '',
219   user_registered datetime NOT NULL default '0000-00-00 00:00:00',
220   user_activation_key varchar(255) NOT NULL default '',
221   user_status int(11) NOT NULL default '0',
222   display_name varchar(250) NOT NULL default '',
223   spam tinyint(2) NOT NULL default '0',
224   deleted tinyint(2) NOT NULL default '0',
225   PRIMARY KEY  (ID),
226   KEY user_login_key (user_login),
227   KEY user_nicename (user_nicename),
228   KEY user_email (user_email)
229 ) $charset_collate;\n";
230
231         // Usermeta.
232         $usermeta_table = "CREATE TABLE $wpdb->usermeta (
233   umeta_id bigint(20) unsigned NOT NULL auto_increment,
234   user_id bigint(20) unsigned NOT NULL default '0',
235   meta_key varchar(255) default NULL,
236   meta_value longtext,
237   PRIMARY KEY  (umeta_id),
238   KEY user_id (user_id),
239   KEY meta_key (meta_key($max_index_length))
240 ) $charset_collate;\n";
241
242         // Global tables
243         if ( $is_multisite )
244                 $global_tables = $users_multi_table . $usermeta_table;
245         else
246                 $global_tables = $users_single_table . $usermeta_table;
247
248         // Multisite global tables.
249         $ms_global_tables = "CREATE TABLE $wpdb->blogs (
250   blog_id bigint(20) NOT NULL auto_increment,
251   site_id bigint(20) NOT NULL default '0',
252   domain varchar(200) NOT NULL default '',
253   path varchar(100) NOT NULL default '',
254   registered datetime NOT NULL default '0000-00-00 00:00:00',
255   last_updated datetime NOT NULL default '0000-00-00 00:00:00',
256   public tinyint(2) NOT NULL default '1',
257   archived tinyint(2) NOT NULL default '0',
258   mature tinyint(2) NOT NULL default '0',
259   spam tinyint(2) NOT NULL default '0',
260   deleted tinyint(2) NOT NULL default '0',
261   lang_id int(11) NOT NULL default '0',
262   PRIMARY KEY  (blog_id),
263   KEY domain (domain(50),path(5)),
264   KEY lang_id (lang_id)
265 ) $charset_collate;
266 CREATE TABLE $wpdb->blog_versions (
267   blog_id bigint(20) NOT NULL default '0',
268   db_version varchar(20) NOT NULL default '',
269   last_updated datetime NOT NULL default '0000-00-00 00:00:00',
270   PRIMARY KEY  (blog_id),
271   KEY db_version (db_version)
272 ) $charset_collate;
273 CREATE TABLE $wpdb->registration_log (
274   ID bigint(20) NOT NULL auto_increment,
275   email varchar(255) NOT NULL default '',
276   IP varchar(30) NOT NULL default '',
277   blog_id bigint(20) NOT NULL default '0',
278   date_registered datetime NOT NULL default '0000-00-00 00:00:00',
279   PRIMARY KEY  (ID),
280   KEY IP (IP)
281 ) $charset_collate;
282 CREATE TABLE $wpdb->site (
283   id bigint(20) NOT NULL auto_increment,
284   domain varchar(200) NOT NULL default '',
285   path varchar(100) NOT NULL default '',
286   PRIMARY KEY  (id),
287   KEY domain (domain(140),path(51))
288 ) $charset_collate;
289 CREATE TABLE $wpdb->sitemeta (
290   meta_id bigint(20) NOT NULL auto_increment,
291   site_id bigint(20) NOT NULL default '0',
292   meta_key varchar(255) default NULL,
293   meta_value longtext,
294   PRIMARY KEY  (meta_id),
295   KEY meta_key (meta_key($max_index_length)),
296   KEY site_id (site_id)
297 ) $charset_collate;
298 CREATE TABLE $wpdb->signups (
299   signup_id bigint(20) NOT NULL auto_increment,
300   domain varchar(200) NOT NULL default '',
301   path varchar(100) NOT NULL default '',
302   title longtext NOT NULL,
303   user_login varchar(60) NOT NULL default '',
304   user_email varchar(100) NOT NULL default '',
305   registered datetime NOT NULL default '0000-00-00 00:00:00',
306   activated datetime NOT NULL default '0000-00-00 00:00:00',
307   active tinyint(1) NOT NULL default '0',
308   activation_key varchar(50) NOT NULL default '',
309   meta longtext,
310   PRIMARY KEY  (signup_id),
311   KEY activation_key (activation_key),
312   KEY user_email (user_email),
313   KEY user_login_email (user_login,user_email),
314   KEY domain_path (domain(140),path(51))
315 ) $charset_collate;";
316
317         switch ( $scope ) {
318                 case 'blog' :
319                         $queries = $blog_tables;
320                         break;
321                 case 'global' :
322                         $queries = $global_tables;
323                         if ( $is_multisite )
324                                 $queries .= $ms_global_tables;
325                         break;
326                 case 'ms_global' :
327                         $queries = $ms_global_tables;
328                         break;
329                 case 'all' :
330                 default:
331                         $queries = $global_tables . $blog_tables;
332                         if ( $is_multisite )
333                                 $queries .= $ms_global_tables;
334                         break;
335         }
336
337         if ( isset( $old_blog_id ) )
338                 $wpdb->set_blog_id( $old_blog_id );
339
340         return $queries;
341 }
342
343 // Populate for back compat.
344 $wp_queries = wp_get_db_schema( 'all' );
345
346 /**
347  * Create WordPress options and set the default values.
348  *
349  * @since 1.5.0
350  *
351  * @global wpdb $wpdb WordPress database abstraction object.
352  * @global int  $wp_db_version
353  * @global int  $wp_current_db_version
354  */
355 function populate_options() {
356         global $wpdb, $wp_db_version, $wp_current_db_version;
357
358         $guessurl = wp_guess_url();
359         /**
360          * Fires before creating WordPress options and populating their default values.
361          *
362          * @since 2.6.0
363          */
364         do_action( 'populate_options' );
365
366         if ( ini_get('safe_mode') ) {
367                 // Safe mode can break mkdir() so use a flat structure by default.
368                 $uploads_use_yearmonth_folders = 0;
369         } else {
370                 $uploads_use_yearmonth_folders = 1;
371         }
372
373         // If WP_DEFAULT_THEME doesn't exist, fall back to the latest core default theme.
374         $stylesheet = $template = WP_DEFAULT_THEME;
375         $theme = wp_get_theme( WP_DEFAULT_THEME );
376         if ( ! $theme->exists() ) {
377                 $theme = WP_Theme::get_core_default_theme();
378         }
379
380         // If we can't find a core default theme, WP_DEFAULT_THEME is the best we can do.
381         if ( $theme ) {
382                 $stylesheet = $theme->get_stylesheet();
383                 $template   = $theme->get_template();
384         }
385
386         $timezone_string = '';
387         $gmt_offset = 0;
388         /* translators: default GMT offset or timezone string. Must be either a valid offset (-12 to 14)
389            or a valid timezone string (America/New_York). See http://us3.php.net/manual/en/timezones.php
390            for all timezone strings supported by PHP.
391         */
392         $offset_or_tz = _x( '0', 'default GMT offset or timezone string' );
393         if ( is_numeric( $offset_or_tz ) )
394                 $gmt_offset = $offset_or_tz;
395         elseif ( $offset_or_tz && in_array( $offset_or_tz, timezone_identifiers_list() ) )
396                         $timezone_string = $offset_or_tz;
397
398         $options = array(
399         'siteurl' => $guessurl,
400         'home' => $guessurl,
401         'blogname' => __('My Site'),
402         /* translators: site tagline */
403         'blogdescription' => __('Just another WordPress site'),
404         'users_can_register' => 0,
405         'admin_email' => 'you@example.com',
406         /* translators: default start of the week. 0 = Sunday, 1 = Monday */
407         'start_of_week' => _x( '1', 'start of week' ),
408         'use_balanceTags' => 0,
409         'use_smilies' => 1,
410         'require_name_email' => 1,
411         'comments_notify' => 1,
412         'posts_per_rss' => 10,
413         'rss_use_excerpt' => 0,
414         'mailserver_url' => 'mail.example.com',
415         'mailserver_login' => 'login@example.com',
416         'mailserver_pass' => 'password',
417         'mailserver_port' => 110,
418         'default_category' => 1,
419         'default_comment_status' => 'open',
420         'default_ping_status' => 'open',
421         'default_pingback_flag' => 1,
422         'posts_per_page' => 10,
423         /* translators: default date format, see http://php.net/date */
424         'date_format' => __('F j, Y'),
425         /* translators: default time format, see http://php.net/date */
426         'time_format' => __('g:i a'),
427         /* translators: links last updated date format, see http://php.net/date */
428         'links_updated_date_format' => __('F j, Y g:i a'),
429         'comment_moderation' => 0,
430         'moderation_notify' => 1,
431         'permalink_structure' => '',
432         'rewrite_rules' => '',
433         'hack_file' => 0,
434         'blog_charset' => 'UTF-8',
435         'moderation_keys' => '',
436         'active_plugins' => array(),
437         'category_base' => '',
438         'ping_sites' => 'http://rpc.pingomatic.com/',
439         'comment_max_links' => 2,
440         'gmt_offset' => $gmt_offset,
441
442         // 1.5
443         'default_email_category' => 1,
444         'recently_edited' => '',
445         'template' => $template,
446         'stylesheet' => $stylesheet,
447         'comment_whitelist' => 1,
448         'blacklist_keys' => '',
449         'comment_registration' => 0,
450         'html_type' => 'text/html',
451
452         // 1.5.1
453         'use_trackback' => 0,
454
455         // 2.0
456         'default_role' => 'subscriber',
457         'db_version' => $wp_db_version,
458
459         // 2.0.1
460         'uploads_use_yearmonth_folders' => $uploads_use_yearmonth_folders,
461         'upload_path' => '',
462
463         // 2.1
464         'blog_public' => '1',
465         'default_link_category' => 2,
466         'show_on_front' => 'posts',
467
468         // 2.2
469         'tag_base' => '',
470
471         // 2.5
472         'show_avatars' => '1',
473         'avatar_rating' => 'G',
474         'upload_url_path' => '',
475         'thumbnail_size_w' => 150,
476         'thumbnail_size_h' => 150,
477         'thumbnail_crop' => 1,
478         'medium_size_w' => 300,
479         'medium_size_h' => 300,
480
481         // 2.6
482         'avatar_default' => 'mystery',
483
484         // 2.7
485         'large_size_w' => 1024,
486         'large_size_h' => 1024,
487         'image_default_link_type' => 'none',
488         'image_default_size' => '',
489         'image_default_align' => '',
490         'close_comments_for_old_posts' => 0,
491         'close_comments_days_old' => 14,
492         'thread_comments' => 1,
493         'thread_comments_depth' => 5,
494         'page_comments' => 0,
495         'comments_per_page' => 50,
496         'default_comments_page' => 'newest',
497         'comment_order' => 'asc',
498         'sticky_posts' => array(),
499         'widget_categories' => array(),
500         'widget_text' => array(),
501         'widget_rss' => array(),
502         'uninstall_plugins' => array(),
503
504         // 2.8
505         'timezone_string' => $timezone_string,
506
507         // 3.0
508         'page_for_posts' => 0,
509         'page_on_front' => 0,
510
511         // 3.1
512         'default_post_format' => 0,
513
514         // 3.5
515         'link_manager_enabled' => 0,
516
517         // 4.3.0
518         'finished_splitting_shared_terms' => 1,
519         'site_icon' => 0,
520
521         // 4.4.0
522         'medium_large_size_w' => 768,
523         'medium_large_size_h' => 0,
524         );
525
526         // 3.3
527         if ( ! is_multisite() ) {
528                 $options['initial_db_version'] = ! empty( $wp_current_db_version ) && $wp_current_db_version < $wp_db_version
529                         ? $wp_current_db_version : $wp_db_version;
530         }
531
532         // 3.0 multisite
533         if ( is_multisite() ) {
534                 /* translators: site tagline */
535                 $options[ 'blogdescription' ] = sprintf(__('Just another %s site'), get_current_site()->site_name );
536                 $options[ 'permalink_structure' ] = '/%year%/%monthnum%/%day%/%postname%/';
537         }
538
539         // Set autoload to no for these options
540         $fat_options = array( 'moderation_keys', 'recently_edited', 'blacklist_keys', 'uninstall_plugins' );
541
542         $keys = "'" . implode( "', '", array_keys( $options ) ) . "'";
543         $existing_options = $wpdb->get_col( "SELECT option_name FROM $wpdb->options WHERE option_name in ( $keys )" );
544
545         $insert = '';
546         foreach ( $options as $option => $value ) {
547                 if ( in_array($option, $existing_options) )
548                         continue;
549                 if ( in_array($option, $fat_options) )
550                         $autoload = 'no';
551                 else
552                         $autoload = 'yes';
553
554                 if ( is_array($value) )
555                         $value = serialize($value);
556                 if ( !empty($insert) )
557                         $insert .= ', ';
558                 $insert .= $wpdb->prepare( "(%s, %s, %s)", $option, $value, $autoload );
559         }
560
561         if ( !empty($insert) )
562                 $wpdb->query("INSERT INTO $wpdb->options (option_name, option_value, autoload) VALUES " . $insert);
563
564         // In case it is set, but blank, update "home".
565         if ( !__get_option('home') ) update_option('home', $guessurl);
566
567         // Delete unused options.
568         $unusedoptions = array(
569                 'blodotgsping_url', 'bodyterminator', 'emailtestonly', 'phoneemail_separator', 'smilies_directory',
570                 'subjectprefix', 'use_bbcode', 'use_blodotgsping', 'use_phoneemail', 'use_quicktags', 'use_weblogsping',
571                 'weblogs_cache_file', 'use_preview', 'use_htmltrans', 'smilies_directory', 'fileupload_allowedusers',
572                 'use_phoneemail', 'default_post_status', 'default_post_category', 'archive_mode', 'time_difference',
573                 'links_minadminlevel', 'links_use_adminlevels', 'links_rating_type', 'links_rating_char',
574                 'links_rating_ignore_zero', 'links_rating_single_image', 'links_rating_image0', 'links_rating_image1',
575                 'links_rating_image2', 'links_rating_image3', 'links_rating_image4', 'links_rating_image5',
576                 'links_rating_image6', 'links_rating_image7', 'links_rating_image8', 'links_rating_image9',
577                 'links_recently_updated_time', 'links_recently_updated_prepend', 'links_recently_updated_append',
578                 'weblogs_cacheminutes', 'comment_allowed_tags', 'search_engine_friendly_urls', 'default_geourl_lat',
579                 'default_geourl_lon', 'use_default_geourl', 'weblogs_xml_url', 'new_users_can_blog', '_wpnonce',
580                 '_wp_http_referer', 'Update', 'action', 'rich_editing', 'autosave_interval', 'deactivated_plugins',
581                 'can_compress_scripts', 'page_uris', 'update_core', 'update_plugins', 'update_themes', 'doing_cron',
582                 'random_seed', 'rss_excerpt_length', 'secret', 'use_linksupdate', 'default_comment_status_page',
583                 'wporg_popular_tags', 'what_to_show', 'rss_language', 'language', 'enable_xmlrpc', 'enable_app',
584                 'embed_autourls', 'default_post_edit_rows', 'gzipcompression', 'advanced_edit'
585         );
586         foreach ( $unusedoptions as $option )
587                 delete_option($option);
588
589         // Delete obsolete magpie stuff.
590         $wpdb->query("DELETE FROM $wpdb->options WHERE option_name REGEXP '^rss_[0-9a-f]{32}(_ts)?$'");
591
592         /*
593          * Deletes all expired transients. The multi-table delete syntax is used
594          * to delete the transient record from table a, and the corresponding
595          * transient_timeout record from table b.
596          */
597         $time = time();
598         $sql = "DELETE a, b FROM $wpdb->options a, $wpdb->options b
599                 WHERE a.option_name LIKE %s
600                 AND a.option_name NOT LIKE %s
601                 AND b.option_name = CONCAT( '_transient_timeout_', SUBSTRING( a.option_name, 12 ) )
602                 AND b.option_value < %d";
603         $wpdb->query( $wpdb->prepare( $sql, $wpdb->esc_like( '_transient_' ) . '%', $wpdb->esc_like( '_transient_timeout_' ) . '%', $time ) );
604
605         if ( is_main_site() && is_main_network() ) {
606                 $sql = "DELETE a, b FROM $wpdb->options a, $wpdb->options b
607                         WHERE a.option_name LIKE %s
608                         AND a.option_name NOT LIKE %s
609                         AND b.option_name = CONCAT( '_site_transient_timeout_', SUBSTRING( a.option_name, 17 ) )
610                         AND b.option_value < %d";
611                 $wpdb->query( $wpdb->prepare( $sql, $wpdb->esc_like( '_site_transient_' ) . '%', $wpdb->esc_like( '_site_transient_timeout_' ) . '%', $time ) );
612         }
613 }
614
615 /**
616  * Execute WordPress role creation for the various WordPress versions.
617  *
618  * @since 2.0.0
619  */
620 function populate_roles() {
621         populate_roles_160();
622         populate_roles_210();
623         populate_roles_230();
624         populate_roles_250();
625         populate_roles_260();
626         populate_roles_270();
627         populate_roles_280();
628         populate_roles_300();
629 }
630
631 /**
632  * Create the roles for WordPress 2.0
633  *
634  * @since 2.0.0
635  */
636 function populate_roles_160() {
637         // Add roles
638
639         // Dummy gettext calls to get strings in the catalog.
640         /* translators: user role */
641         _x('Administrator', 'User role');
642         /* translators: user role */
643         _x('Editor', 'User role');
644         /* translators: user role */
645         _x('Author', 'User role');
646         /* translators: user role */
647         _x('Contributor', 'User role');
648         /* translators: user role */
649         _x('Subscriber', 'User role');
650
651         add_role('administrator', 'Administrator');
652         add_role('editor', 'Editor');
653         add_role('author', 'Author');
654         add_role('contributor', 'Contributor');
655         add_role('subscriber', 'Subscriber');
656
657         // Add caps for Administrator role
658         $role = get_role('administrator');
659         $role->add_cap('switch_themes');
660         $role->add_cap('edit_themes');
661         $role->add_cap('activate_plugins');
662         $role->add_cap('edit_plugins');
663         $role->add_cap('edit_users');
664         $role->add_cap('edit_files');
665         $role->add_cap('manage_options');
666         $role->add_cap('moderate_comments');
667         $role->add_cap('manage_categories');
668         $role->add_cap('manage_links');
669         $role->add_cap('upload_files');
670         $role->add_cap('import');
671         $role->add_cap('unfiltered_html');
672         $role->add_cap('edit_posts');
673         $role->add_cap('edit_others_posts');
674         $role->add_cap('edit_published_posts');
675         $role->add_cap('publish_posts');
676         $role->add_cap('edit_pages');
677         $role->add_cap('read');
678         $role->add_cap('level_10');
679         $role->add_cap('level_9');
680         $role->add_cap('level_8');
681         $role->add_cap('level_7');
682         $role->add_cap('level_6');
683         $role->add_cap('level_5');
684         $role->add_cap('level_4');
685         $role->add_cap('level_3');
686         $role->add_cap('level_2');
687         $role->add_cap('level_1');
688         $role->add_cap('level_0');
689
690         // Add caps for Editor role
691         $role = get_role('editor');
692         $role->add_cap('moderate_comments');
693         $role->add_cap('manage_categories');
694         $role->add_cap('manage_links');
695         $role->add_cap('upload_files');
696         $role->add_cap('unfiltered_html');
697         $role->add_cap('edit_posts');
698         $role->add_cap('edit_others_posts');
699         $role->add_cap('edit_published_posts');
700         $role->add_cap('publish_posts');
701         $role->add_cap('edit_pages');
702         $role->add_cap('read');
703         $role->add_cap('level_7');
704         $role->add_cap('level_6');
705         $role->add_cap('level_5');
706         $role->add_cap('level_4');
707         $role->add_cap('level_3');
708         $role->add_cap('level_2');
709         $role->add_cap('level_1');
710         $role->add_cap('level_0');
711
712         // Add caps for Author role
713         $role = get_role('author');
714         $role->add_cap('upload_files');
715         $role->add_cap('edit_posts');
716         $role->add_cap('edit_published_posts');
717         $role->add_cap('publish_posts');
718         $role->add_cap('read');
719         $role->add_cap('level_2');
720         $role->add_cap('level_1');
721         $role->add_cap('level_0');
722
723         // Add caps for Contributor role
724         $role = get_role('contributor');
725         $role->add_cap('edit_posts');
726         $role->add_cap('read');
727         $role->add_cap('level_1');
728         $role->add_cap('level_0');
729
730         // Add caps for Subscriber role
731         $role = get_role('subscriber');
732         $role->add_cap('read');
733         $role->add_cap('level_0');
734 }
735
736 /**
737  * Create and modify WordPress roles for WordPress 2.1.
738  *
739  * @since 2.1.0
740  */
741 function populate_roles_210() {
742         $roles = array('administrator', 'editor');
743         foreach ($roles as $role) {
744                 $role = get_role($role);
745                 if ( empty($role) )
746                         continue;
747
748                 $role->add_cap('edit_others_pages');
749                 $role->add_cap('edit_published_pages');
750                 $role->add_cap('publish_pages');
751                 $role->add_cap('delete_pages');
752                 $role->add_cap('delete_others_pages');
753                 $role->add_cap('delete_published_pages');
754                 $role->add_cap('delete_posts');
755                 $role->add_cap('delete_others_posts');
756                 $role->add_cap('delete_published_posts');
757                 $role->add_cap('delete_private_posts');
758                 $role->add_cap('edit_private_posts');
759                 $role->add_cap('read_private_posts');
760                 $role->add_cap('delete_private_pages');
761                 $role->add_cap('edit_private_pages');
762                 $role->add_cap('read_private_pages');
763         }
764
765         $role = get_role('administrator');
766         if ( ! empty($role) ) {
767                 $role->add_cap('delete_users');
768                 $role->add_cap('create_users');
769         }
770
771         $role = get_role('author');
772         if ( ! empty($role) ) {
773                 $role->add_cap('delete_posts');
774                 $role->add_cap('delete_published_posts');
775         }
776
777         $role = get_role('contributor');
778         if ( ! empty($role) ) {
779                 $role->add_cap('delete_posts');
780         }
781 }
782
783 /**
784  * Create and modify WordPress roles for WordPress 2.3.
785  *
786  * @since 2.3.0
787  */
788 function populate_roles_230() {
789         $role = get_role( 'administrator' );
790
791         if ( !empty( $role ) ) {
792                 $role->add_cap( 'unfiltered_upload' );
793         }
794 }
795
796 /**
797  * Create and modify WordPress roles for WordPress 2.5.
798  *
799  * @since 2.5.0
800  */
801 function populate_roles_250() {
802         $role = get_role( 'administrator' );
803
804         if ( !empty( $role ) ) {
805                 $role->add_cap( 'edit_dashboard' );
806         }
807 }
808
809 /**
810  * Create and modify WordPress roles for WordPress 2.6.
811  *
812  * @since 2.6.0
813  */
814 function populate_roles_260() {
815         $role = get_role( 'administrator' );
816
817         if ( !empty( $role ) ) {
818                 $role->add_cap( 'update_plugins' );
819                 $role->add_cap( 'delete_plugins' );
820         }
821 }
822
823 /**
824  * Create and modify WordPress roles for WordPress 2.7.
825  *
826  * @since 2.7.0
827  */
828 function populate_roles_270() {
829         $role = get_role( 'administrator' );
830
831         if ( !empty( $role ) ) {
832                 $role->add_cap( 'install_plugins' );
833                 $role->add_cap( 'update_themes' );
834         }
835 }
836
837 /**
838  * Create and modify WordPress roles for WordPress 2.8.
839  *
840  * @since 2.8.0
841  */
842 function populate_roles_280() {
843         $role = get_role( 'administrator' );
844
845         if ( !empty( $role ) ) {
846                 $role->add_cap( 'install_themes' );
847         }
848 }
849
850 /**
851  * Create and modify WordPress roles for WordPress 3.0.
852  *
853  * @since 3.0.0
854  */
855 function populate_roles_300() {
856         $role = get_role( 'administrator' );
857
858         if ( !empty( $role ) ) {
859                 $role->add_cap( 'update_core' );
860                 $role->add_cap( 'list_users' );
861                 $role->add_cap( 'remove_users' );
862                 $role->add_cap( 'promote_users' );
863                 $role->add_cap( 'edit_theme_options' );
864                 $role->add_cap( 'delete_themes' );
865                 $role->add_cap( 'export' );
866         }
867 }
868
869 /**
870  * Install Network.
871  *
872  * @since 3.0.0
873  *
874  */
875 if ( !function_exists( 'install_network' ) ) :
876 function install_network() {
877         if ( ! defined( 'WP_INSTALLING_NETWORK' ) )
878                 define( 'WP_INSTALLING_NETWORK', true );
879
880         dbDelta( wp_get_db_schema( 'global' ) );
881 }
882 endif;
883
884 /**
885  * Populate network settings.
886  *
887  * @since 3.0.0
888  *
889  * @global wpdb       $wpdb
890  * @global object     $current_site
891  * @global int        $wp_db_version
892  * @global WP_Rewrite $wp_rewrite
893  *
894  * @param int    $network_id        ID of network to populate.
895  * @param string $domain            The domain name for the network (eg. "example.com").
896  * @param string $email             Email address for the network administrator.
897  * @param string $site_name         The name of the network.
898  * @param string $path              Optional. The path to append to the network's domain name. Default '/'.
899  * @param bool   $subdomain_install Optional. Whether the network is a subdomain install or a subdirectory install.
900  *                                  Default false, meaning the network is a subdirectory install.
901  * @return bool|WP_Error True on success, or WP_Error on warning (with the install otherwise successful,
902  *                       so the error code must be checked) or failure.
903  */
904 function populate_network( $network_id = 1, $domain = '', $email = '', $site_name = '', $path = '/', $subdomain_install = false ) {
905         global $wpdb, $current_site, $wp_db_version, $wp_rewrite;
906
907         $errors = new WP_Error();
908         if ( '' == $domain )
909                 $errors->add( 'empty_domain', __( 'You must provide a domain name.' ) );
910         if ( '' == $site_name )
911                 $errors->add( 'empty_sitename', __( 'You must provide a name for your network of sites.' ) );
912
913         // Check for network collision.
914         if ( $network_id == $wpdb->get_var( $wpdb->prepare( "SELECT id FROM $wpdb->site WHERE id = %d", $network_id ) ) )
915                 $errors->add( 'siteid_exists', __( 'The network already exists.' ) );
916
917         if ( ! is_email( $email ) )
918                 $errors->add( 'invalid_email', __( 'You must provide a valid email address.' ) );
919
920         if ( $errors->get_error_code() )
921                 return $errors;
922
923         // If a user with the provided email does not exist, default to the current user as the new network admin.
924         $site_user = get_user_by( 'email', $email );
925         if ( false === $site_user ) {
926                 $site_user = wp_get_current_user();
927         }
928
929         // Set up site tables.
930         $template = get_option( 'template' );
931         $stylesheet = get_option( 'stylesheet' );
932         $allowed_themes = array( $stylesheet => true );
933
934         if ( $template != $stylesheet ) {
935                 $allowed_themes[ $template ] = true;
936         }
937
938         if ( WP_DEFAULT_THEME != $stylesheet && WP_DEFAULT_THEME != $template ) {
939                 $allowed_themes[ WP_DEFAULT_THEME ] = true;
940         }
941
942         // If WP_DEFAULT_THEME doesn't exist, also whitelist the latest core default theme.
943         if ( ! wp_get_theme( WP_DEFAULT_THEME )->exists() ) {
944                 if ( $core_default = WP_Theme::get_core_default_theme() ) {
945                         $allowed_themes[ $core_default->get_stylesheet() ] = true;
946                 }
947         }
948
949         if ( 1 == $network_id ) {
950                 $wpdb->insert( $wpdb->site, array( 'domain' => $domain, 'path' => $path ) );
951                 $network_id = $wpdb->insert_id;
952         } else {
953                 $wpdb->insert( $wpdb->site, array( 'domain' => $domain, 'path' => $path, 'id' => $network_id ) );
954         }
955
956         wp_cache_delete( 'networks_have_paths', 'site-options' );
957
958         if ( !is_multisite() ) {
959                 $site_admins = array( $site_user->user_login );
960                 $users = get_users( array( 'fields' => array( 'ID', 'user_login' ) ) );
961                 if ( $users ) {
962                         foreach ( $users as $user ) {
963                                 if ( is_super_admin( $user->ID ) && !in_array( $user->user_login, $site_admins ) )
964                                         $site_admins[] = $user->user_login;
965                         }
966                 }
967         } else {
968                 $site_admins = get_site_option( 'site_admins' );
969         }
970
971         /* translators: Do not translate USERNAME, SITE_NAME, BLOG_URL, PASSWORD: those are placeholders. */
972         $welcome_email = __( 'Howdy USERNAME,
973
974 Your new SITE_NAME site has been successfully set up at:
975 BLOG_URL
976
977 You can log in to the administrator account with the following information:
978
979 Username: USERNAME
980 Password: PASSWORD
981 Log in here: BLOG_URLwp-login.php
982
983 We hope you enjoy your new site. Thanks!
984
985 --The Team @ SITE_NAME' );
986
987         $misc_exts = array(
988                 // Images.
989                 'jpg', 'jpeg', 'png', 'gif',
990                 // Video.
991                 'mov', 'avi', 'mpg', '3gp', '3g2',
992                 // "audio".
993                 'midi', 'mid',
994                 // Miscellaneous.
995                 'pdf', 'doc', 'ppt', 'odt', 'pptx', 'docx', 'pps', 'ppsx', 'xls', 'xlsx', 'key',
996         );
997         $audio_exts = wp_get_audio_extensions();
998         $video_exts = wp_get_video_extensions();
999         $upload_filetypes = array_unique( array_merge( $misc_exts, $audio_exts, $video_exts ) );
1000
1001         $sitemeta = array(
1002                 'site_name' => $site_name,
1003                 'admin_email' => $email,
1004                 'admin_user_id' => $site_user->ID,
1005                 'registration' => 'none',
1006                 'upload_filetypes' => implode( ' ', $upload_filetypes ),
1007                 'blog_upload_space' => 100,
1008                 'fileupload_maxk' => 1500,
1009                 'site_admins' => $site_admins,
1010                 'allowedthemes' => $allowed_themes,
1011                 'illegal_names' => array( 'www', 'web', 'root', 'admin', 'main', 'invite', 'administrator', 'files' ),
1012                 'wpmu_upgrade_site' => $wp_db_version,
1013                 'welcome_email' => $welcome_email,
1014                 /* translators: %s: site link */
1015                 'first_post' => __( 'Welcome to %s. This is your first post. Edit or delete it, then start blogging!' ),
1016                 // @todo - network admins should have a method of editing the network siteurl (used for cookie hash)
1017                 'siteurl' => get_option( 'siteurl' ) . '/',
1018                 'add_new_users' => '0',
1019                 'upload_space_check_disabled' => is_multisite() ? get_site_option( 'upload_space_check_disabled' ) : '1',
1020                 'subdomain_install' => intval( $subdomain_install ),
1021                 'global_terms_enabled' => global_terms_enabled() ? '1' : '0',
1022                 'ms_files_rewriting' => is_multisite() ? get_site_option( 'ms_files_rewriting' ) : '0',
1023                 'initial_db_version' => get_option( 'initial_db_version' ),
1024                 'active_sitewide_plugins' => array(),
1025                 'WPLANG' => get_locale(),
1026         );
1027         if ( ! $subdomain_install )
1028                 $sitemeta['illegal_names'][] = 'blog';
1029
1030         /**
1031          * Filter meta for a network on creation.
1032          *
1033          * @since 3.7.0
1034          *
1035          * @param array $sitemeta   Associative array of network meta keys and values to be inserted.
1036          * @param int   $network_id ID of network to populate.
1037          */
1038         $sitemeta = apply_filters( 'populate_network_meta', $sitemeta, $network_id );
1039
1040         $insert = '';
1041         foreach ( $sitemeta as $meta_key => $meta_value ) {
1042                 if ( is_array( $meta_value ) )
1043                         $meta_value = serialize( $meta_value );
1044                 if ( !empty( $insert ) )
1045                         $insert .= ', ';
1046                 $insert .= $wpdb->prepare( "( %d, %s, %s)", $network_id, $meta_key, $meta_value );
1047         }
1048         $wpdb->query( "INSERT INTO $wpdb->sitemeta ( site_id, meta_key, meta_value ) VALUES " . $insert );
1049
1050         /*
1051          * When upgrading from single to multisite, assume the current site will
1052          * become the main site of the network. When using populate_network()
1053          * to create another network in an existing multisite environment, skip
1054          * these steps since the main site of the new network has not yet been
1055          * created.
1056          */
1057         if ( ! is_multisite() ) {
1058                 $current_site = new stdClass;
1059                 $current_site->domain = $domain;
1060                 $current_site->path = $path;
1061                 $current_site->site_name = ucfirst( $domain );
1062                 $wpdb->insert( $wpdb->blogs, array( 'site_id' => $network_id, 'blog_id' => 1, 'domain' => $domain, 'path' => $path, 'registered' => current_time( 'mysql' ) ) );
1063                 $current_site->blog_id = $blog_id = $wpdb->insert_id;
1064                 update_user_meta( $site_user->ID, 'source_domain', $domain );
1065                 update_user_meta( $site_user->ID, 'primary_blog', $blog_id );
1066
1067                 if ( $subdomain_install )
1068                         $wp_rewrite->set_permalink_structure( '/%year%/%monthnum%/%day%/%postname%/' );
1069                 else
1070                         $wp_rewrite->set_permalink_structure( '/blog/%year%/%monthnum%/%day%/%postname%/' );
1071
1072                 flush_rewrite_rules();
1073
1074                 if ( ! $subdomain_install )
1075                         return true;
1076
1077                 $vhost_ok = false;
1078                 $errstr = '';
1079                 $hostname = substr( md5( time() ), 0, 6 ) . '.' . $domain; // Very random hostname!
1080                 $page = wp_remote_get( 'http://' . $hostname, array( 'timeout' => 5, 'httpversion' => '1.1' ) );
1081                 if ( is_wp_error( $page ) )
1082                         $errstr = $page->get_error_message();
1083                 elseif ( 200 == wp_remote_retrieve_response_code( $page ) )
1084                                 $vhost_ok = true;
1085
1086                 if ( ! $vhost_ok ) {
1087                         $msg = '<p><strong>' . __( 'Warning! Wildcard DNS may not be configured correctly!' ) . '</strong></p>';
1088
1089                         $msg .= '<p>' . sprintf(
1090                                 /* translators: %s: host name */
1091                                 __( 'The installer attempted to contact a random hostname (%s) on your domain.' ),
1092                                 '<code>' . $hostname . '</code>'
1093                         );
1094                         if ( ! empty ( $errstr ) ) {
1095                                 /* translators: %s: error message */
1096                                 $msg .= ' ' . sprintf( __( 'This resulted in an error message: %s' ), '<code>' . $errstr . '</code>' );
1097                         }
1098                         $msg .= '</p>';
1099
1100                         $msg .= '<p>' . sprintf(
1101                                 /* translators: %s: asterisk symbol (*) */
1102                                 __( 'To use a subdomain configuration, you must have a wildcard entry in your DNS. This usually means adding a %s hostname record pointing at your web server in your DNS configuration tool.' ),
1103                                 '<code>*</code>'
1104                         ) . '</p>';
1105
1106                         $msg .= '<p>' . __( 'You can still use your site but any subdomain you create may not be accessible. If you know your DNS is correct, ignore this message.' ) . '</p>';
1107
1108                         return new WP_Error( 'no_wildcard_dns', $msg );
1109                 }
1110         }
1111
1112         return true;
1113 }