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