3 * WordPress Administration Scheme API
5 * Here we keep the DB structure and option values.
8 * @subpackage Administration
12 * Declare these as global in case schema.php is included from a function.
15 * @global array $wp_queries
16 * @global string $charset_collate
18 global $wpdb, $wp_queries, $charset_collate;
21 * The database character collate.
23 $charset_collate = $wpdb->get_charset_collate();
26 * Retrieve the SQL for creating database tables.
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.
36 function wp_get_db_schema( $scope = 'all', $blog_id = null ) {
39 $charset_collate = '';
41 if ( ! empty($wpdb->charset) )
42 $charset_collate = "DEFAULT CHARACTER SET $wpdb->charset";
43 if ( ! empty($wpdb->collate) )
44 $charset_collate .= " COLLATE $wpdb->collate";
46 if ( $blog_id && $blog_id != $wpdb->blogid )
47 $old_blog_id = $wpdb->set_blog_id( $blog_id );
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 );
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.
57 $max_index_length = 191;
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))
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)
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)
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,
92 PRIMARY KEY (meta_id),
93 KEY comment_id (comment_id),
94 KEY meta_key (meta_key($max_index_length))
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))
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)
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)
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,
149 PRIMARY KEY (meta_id),
150 KEY post_id (post_id),
151 KEY meta_key (meta_key($max_index_length))
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',
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";
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 '',
197 KEY user_login_key (user_login),
198 KEY user_nicename (user_nicename)
199 ) $charset_collate;\n";
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',
216 KEY user_login_key (user_login),
217 KEY user_nicename (user_nicename)
218 ) $charset_collate;\n";
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,
226 PRIMARY KEY (umeta_id),
227 KEY user_id (user_id),
228 KEY meta_key (meta_key($max_index_length))
229 ) $charset_collate;\n";
233 $global_tables = $users_multi_table . $usermeta_table;
235 $global_tables = $users_single_table . $usermeta_table;
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)
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)
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',
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 '',
276 KEY domain (domain(140),path(51))
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,
283 PRIMARY KEY (meta_id),
284 KEY meta_key (meta_key($max_index_length)),
285 KEY site_id (site_id)
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 '',
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;";
308 $queries = $blog_tables;
311 $queries = $global_tables;
313 $queries .= $ms_global_tables;
316 $queries = $ms_global_tables;
320 $queries = $global_tables . $blog_tables;
322 $queries .= $ms_global_tables;
326 if ( isset( $old_blog_id ) )
327 $wpdb->set_blog_id( $old_blog_id );
332 // Populate for back compat.
333 $wp_queries = wp_get_db_schema( 'all' );
336 * Create WordPress options and set the default values.
340 * @global wpdb $wpdb WordPress database abstraction object.
341 * @global int $wp_db_version
342 * @global int $wp_current_db_version
344 function populate_options() {
345 global $wpdb, $wp_db_version, $wp_current_db_version;
347 $guessurl = wp_guess_url();
349 * Fires before creating WordPress options and populating their default values.
353 do_action( 'populate_options' );
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;
359 $uploads_use_yearmonth_folders = 1;
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();
368 $timezone_string = '';
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.
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;
381 'siteurl' => $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,
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,
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,
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',
436 'use_trackback' => 0,
439 'default_role' => 'subscriber',
440 'db_version' => $wp_db_version,
443 'uploads_use_yearmonth_folders' => $uploads_use_yearmonth_folders,
447 'blog_public' => '1',
448 'default_link_category' => 2,
449 'show_on_front' => 'posts',
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,
465 'avatar_default' => 'mystery',
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(),
488 'timezone_string' => $timezone_string,
491 'page_for_posts' => 0,
492 'page_on_front' => 0,
495 'default_post_format' => 0,
498 'link_manager_enabled' => 0,
501 'finished_splitting_shared_terms' => 1,
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;
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%/';
517 // Set autoload to no for these options
518 $fat_options = array( 'moderation_keys', 'recently_edited', 'blacklist_keys', 'uninstall_plugins' );
520 $keys = "'" . implode( "', '", array_keys( $options ) ) . "'";
521 $existing_options = $wpdb->get_col( "SELECT option_name FROM $wpdb->options WHERE option_name in ( $keys )" );
524 foreach ( $options as $option => $value ) {
525 if ( in_array($option, $existing_options) )
527 if ( in_array($option, $fat_options) )
532 if ( is_array($value) )
533 $value = serialize($value);
534 if ( !empty($insert) )
536 $insert .= $wpdb->prepare( "(%s, %s, %s)", $option, $value, $autoload );
539 if ( !empty($insert) )
540 $wpdb->query("INSERT INTO $wpdb->options (option_name, option_value, autoload) VALUES " . $insert);
542 // In case it is set, but blank, update "home".
543 if ( !__get_option('home') ) update_option('home', $guessurl);
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',
564 foreach ( $unusedoptions as $option )
565 delete_option($option);
567 // Delete obsolete magpie stuff.
568 $wpdb->query("DELETE FROM $wpdb->options WHERE option_name REGEXP '^rss_[0-9a-f]{32}(_ts)?$'");
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.
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 ) );
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 ) );
594 * Execute WordPress role creation for the various WordPress versions.
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();
610 * Create the roles for WordPress 2.0
614 function populate_roles_160() {
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');
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');
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');
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');
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');
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');
708 // Add caps for Subscriber role
709 $role = get_role('subscriber');
710 $role->add_cap('read');
711 $role->add_cap('level_0');
715 * Create and modify WordPress roles for WordPress 2.1.
719 function populate_roles_210() {
720 $roles = array('administrator', 'editor');
721 foreach ($roles as $role) {
722 $role = get_role($role);
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');
743 $role = get_role('administrator');
744 if ( ! empty($role) ) {
745 $role->add_cap('delete_users');
746 $role->add_cap('create_users');
749 $role = get_role('author');
750 if ( ! empty($role) ) {
751 $role->add_cap('delete_posts');
752 $role->add_cap('delete_published_posts');
755 $role = get_role('contributor');
756 if ( ! empty($role) ) {
757 $role->add_cap('delete_posts');
762 * Create and modify WordPress roles for WordPress 2.3.
766 function populate_roles_230() {
767 $role = get_role( 'administrator' );
769 if ( !empty( $role ) ) {
770 $role->add_cap( 'unfiltered_upload' );
775 * Create and modify WordPress roles for WordPress 2.5.
779 function populate_roles_250() {
780 $role = get_role( 'administrator' );
782 if ( !empty( $role ) ) {
783 $role->add_cap( 'edit_dashboard' );
788 * Create and modify WordPress roles for WordPress 2.6.
792 function populate_roles_260() {
793 $role = get_role( 'administrator' );
795 if ( !empty( $role ) ) {
796 $role->add_cap( 'update_plugins' );
797 $role->add_cap( 'delete_plugins' );
802 * Create and modify WordPress roles for WordPress 2.7.
806 function populate_roles_270() {
807 $role = get_role( 'administrator' );
809 if ( !empty( $role ) ) {
810 $role->add_cap( 'install_plugins' );
811 $role->add_cap( 'update_themes' );
816 * Create and modify WordPress roles for WordPress 2.8.
820 function populate_roles_280() {
821 $role = get_role( 'administrator' );
823 if ( !empty( $role ) ) {
824 $role->add_cap( 'install_themes' );
829 * Create and modify WordPress roles for WordPress 3.0.
833 function populate_roles_300() {
834 $role = get_role( 'administrator' );
836 if ( !empty( $role ) ) {
837 $role->add_cap( 'update_core' );
838 $role->add_cap( 'list_users' );
839 $role->add_cap( 'remove_users' );
842 * Never used, will be removed. create_users or promote_users
843 * is the capability you're looking for.
845 $role->add_cap( 'add_users' );
847 $role->add_cap( 'promote_users' );
848 $role->add_cap( 'edit_theme_options' );
849 $role->add_cap( 'delete_themes' );
850 $role->add_cap( 'export' );
860 if ( !function_exists( 'install_network' ) ) :
861 function install_network() {
862 if ( ! defined( 'WP_INSTALLING_NETWORK' ) )
863 define( 'WP_INSTALLING_NETWORK', true );
865 dbDelta( wp_get_db_schema( 'global' ) );
870 * Populate network settings.
875 * @global object $current_site
876 * @global int $wp_db_version
877 * @global WP_Rewrite $wp_rewrite
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.
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;
886 $errors = new WP_Error();
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.' ) );
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.' ) );
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.' ) );
900 if ( $errors->get_error_code() )
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;
912 if ( 1 == $network_id ) {
913 $wpdb->insert( $wpdb->site, array( 'domain' => $domain, 'path' => $path ) );
914 $network_id = $wpdb->insert_id;
916 $wpdb->insert( $wpdb->site, array( 'domain' => $domain, 'path' => $path, 'id' => $network_id ) );
919 wp_cache_delete( 'networks_have_paths', 'site-options' );
921 if ( !is_multisite() ) {
922 $site_admins = array( $site_user->user_login );
923 $users = get_users( array( 'fields' => array( 'ID', 'user_login' ) ) );
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;
931 $site_admins = get_site_option( 'site_admins' );
934 /* translators: Do not translate USERNAME, SITE_NAME, BLOG_URL, PASSWORD: those are placeholders. */
935 $welcome_email = __( 'Howdy USERNAME,
937 Your new SITE_NAME site has been successfully set up at:
940 You can log in to the administrator account with the following information:
944 Log in here: BLOG_URLwp-login.php
946 We hope you enjoy your new site. Thanks!
948 --The Team @ SITE_NAME' );
952 'jpg', 'jpeg', 'png', 'gif',
954 'mov', 'avi', 'mpg', '3gp', '3g2',
958 'pdf', 'doc', 'ppt', 'odt', 'pptx', 'docx', 'pps', 'ppsx', 'xls', 'xlsx', 'key',
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 ) );
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(),
989 if ( ! $subdomain_install )
990 $sitemeta['illegal_names'][] = 'blog';
993 * Filter meta for a network on creation.
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.
1000 $sitemeta = apply_filters( 'populate_network_meta', $sitemeta, $network_id );
1003 foreach ( $sitemeta as $meta_key => $meta_value ) {
1004 if ( is_array( $meta_value ) )
1005 $meta_value = serialize( $meta_value );
1006 if ( !empty( $insert ) )
1008 $insert .= $wpdb->prepare( "( %d, %s, %s)", $network_id, $meta_key, $meta_value );
1010 $wpdb->query( "INSERT INTO $wpdb->sitemeta ( site_id, meta_key, meta_value ) VALUES " . $insert );
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
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 );
1029 if ( $subdomain_install )
1030 $wp_rewrite->set_permalink_structure( '/%year%/%monthnum%/%day%/%postname%/' );
1032 $wp_rewrite->set_permalink_structure( '/blog/%year%/%monthnum%/%day%/%postname%/' );
1034 flush_rewrite_rules();
1036 if ( ! $subdomain_install )
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 ) )
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>' );
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 );