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