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