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