run:R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:52
R W Run
DIR
2026-03-11 16:18:51
R W Run
DIR
2026-03-11 16:18:51
R W Run
23.8 KB
2026-03-11 16:18:51
R W Run
7.8 KB
2026-03-11 16:18:52
R W Run
36.1 KB
2026-03-11 16:18:51
R W Run
11.9 KB
2026-03-11 16:18:52
R W Run
18.94 KB
2026-03-11 16:18:52
R W Run
7.35 KB
2026-03-11 16:18:52
R W Run
28.6 KB
2026-03-11 16:18:51
R W Run
316 By
2026-03-11 16:18:51
R W Run
12.9 KB
2026-03-11 16:18:51
R W Run
61.02 KB
2026-03-11 16:18:52
R W Run
15 KB
2026-03-11 16:18:51
R W Run
112.05 KB
2026-03-11 16:18:51
R W Run
12.47 KB
2026-03-11 16:18:51
R W Run
15.07 KB
2026-03-11 16:18:52
R W Run
9.84 KB
2026-03-11 16:18:52
R W Run
13.17 KB
2026-03-11 16:18:52
R W Run
33.83 KB
2026-03-11 16:18:51
R W Run
42.63 KB
2026-03-11 16:18:51
R W Run
55.71 KB
2026-03-11 16:18:52
R W Run
12.53 KB
2026-03-11 16:18:51
R W Run
2.55 KB
2026-03-11 16:18:52
R W Run
28.92 KB
2026-03-11 16:18:52
R W Run
539 By
2026-03-11 16:18:51
R W Run
367 By
2026-03-11 16:18:52
R W Run
42.65 KB
2026-03-11 16:18:51
R W Run
401 By
2026-03-11 16:18:51
R W Run
6.61 KB
2026-03-11 16:18:51
R W Run
664 By
2026-03-11 16:18:52
R W Run
20.63 KB
2026-03-11 16:18:51
R W Run
2.18 KB
2026-03-11 16:18:52
R W Run
453 By
2026-03-11 16:18:52
R W Run
457 By
2026-03-11 16:18:51
R W Run
36.83 KB
2026-03-11 16:18:52
R W Run
2.41 KB
2026-03-11 16:18:52
R W Run
8.28 KB
2026-03-11 16:18:51
R W Run
13.89 KB
2026-03-11 16:18:51
R W Run
11.76 KB
2026-03-11 16:18:51
R W Run
2.65 KB
2026-03-11 16:18:51
R W Run
7.43 KB
2026-03-11 16:18:51
R W Run
17.46 KB
2026-03-11 16:18:51
R W Run
5.14 KB
2026-03-11 16:18:52
R W Run
16.7 KB
2026-03-11 16:18:51
R W Run
8.28 KB
2026-03-11 16:18:52
R W Run
2.92 KB
2026-03-11 16:18:52
R W Run
1.32 KB
2026-03-11 16:18:51
R W Run
4.6 KB
2026-03-11 16:18:52
R W Run
11.62 KB
2026-03-11 16:18:52
R W Run
2.5 KB
2026-03-11 16:18:51
R W Run
1.97 KB
2026-03-11 16:18:51
R W Run
11.25 KB
2026-03-11 16:18:52
R W Run
5.32 KB
2026-03-11 16:18:51
R W Run
10.99 KB
2026-03-11 16:18:52
R W Run
68.32 KB
2026-03-11 16:18:51
R W Run
6.34 KB
2026-03-11 16:18:51
R W Run
5.49 KB
2026-03-11 16:18:51
R W Run
1.99 KB
2026-03-11 16:18:52
R W Run
7.02 KB
2026-03-11 16:18:51
R W Run
4.91 KB
2026-03-11 16:18:52
R W Run
16.86 KB
2026-03-11 16:18:51
R W Run
24.23 KB
2026-03-11 16:18:51
R W Run
3.97 KB
2026-03-11 16:18:51
R W Run
47.66 KB
2026-03-11 16:18:51
R W Run
9.22 KB
2026-03-11 16:18:51
R W Run
25.51 KB
2026-03-11 16:18:51
R W Run
198.38 KB
2026-03-11 16:18:52
R W Run
56.65 KB
2026-03-11 16:18:51
R W Run
10.46 KB
2026-03-11 16:18:51
R W Run
10.95 KB
2026-03-11 16:18:52
R W Run
29.26 KB
2026-03-11 16:18:51
R W Run
70.91 KB
2026-03-11 16:18:52
R W Run
35.3 KB
2026-03-11 16:18:52
R W Run
16.61 KB
2026-03-11 16:18:52
R W Run
2.57 KB
2026-03-11 16:18:52
R W Run
39.83 KB
2026-03-11 16:18:51
R W Run
70.64 KB
2026-03-11 16:18:51
R W Run
15.56 KB
2026-03-11 16:18:52
R W Run
7.33 KB
2026-03-11 16:18:52
R W Run
253 By
2026-03-11 16:18:51
R W Run
7.96 KB
2026-03-11 16:18:52
R W Run
3.23 KB
2026-03-11 16:18:52
R W Run
969 By
2026-03-11 16:18:52
R W Run
16.28 KB
2026-03-11 16:18:51
R W Run
7.22 KB
2026-03-11 16:18:51
R W Run
12.95 KB
2026-03-11 16:18:51
R W Run
6.53 KB
2026-03-11 16:18:51
R W Run
3.42 KB
2026-03-11 16:18:52
R W Run
5.84 KB
2026-03-11 16:18:51
R W Run
1.97 KB
2026-03-11 16:18:51
R W Run
4.3 KB
2026-03-11 16:18:52
R W Run
2.91 KB
2026-03-11 16:18:51
R W Run
16.46 KB
2026-03-11 16:18:52
R W Run
40.6 KB
2026-03-11 16:18:51
R W Run
20.22 KB
2026-03-11 16:18:51
R W Run
36.11 KB
2026-03-11 16:18:52
R W Run
17.01 KB
2026-03-11 16:18:51
R W Run
7.27 KB
2026-03-11 16:18:52
R W Run
6.62 KB
2026-03-11 16:18:52
R W Run
16.49 KB
2026-03-11 16:18:52
R W Run
1.79 KB
2026-03-11 16:18:52
R W Run
29.82 KB
2026-03-11 16:18:51
R W Run
6.67 KB
2026-03-11 16:18:52
R W Run
8.98 KB
2026-03-11 16:18:52
R W Run
19.42 KB
2026-03-11 16:18:51
R W Run
12.01 KB
2026-03-11 16:18:51
R W Run
17.11 KB
2026-03-11 16:18:51
R W Run
6.74 KB
2026-03-11 16:18:52
R W Run
30.93 KB
2026-03-11 16:18:51
R W Run
4.99 KB
2026-03-11 16:18:51
R W Run
4.25 KB
2026-03-11 16:18:51
R W Run
24.72 KB
2026-03-11 16:18:51
R W Run
29.96 KB
2026-03-11 16:18:52
R W Run
6.41 KB
2026-03-11 16:18:51
R W Run
160 KB
2026-03-11 16:18:51
R W Run
6.72 KB
2026-03-11 16:18:52
R W Run
10.92 KB
2026-03-11 16:18:51
R W Run
4.77 KB
2026-03-11 16:18:51
R W Run
3.38 KB
2026-03-11 16:18:51
R W Run
11.18 KB
2026-03-11 16:18:51
R W Run
62.19 KB
2026-03-11 16:18:51
R W Run
2.46 KB
2026-03-11 16:18:51
R W Run
9.17 KB
2026-03-11 16:18:51
R W Run
32.15 KB
2026-03-11 16:18:51
R W Run
34.05 KB
2026-03-11 16:18:52
R W Run
7.15 KB
2026-03-11 16:18:51
R W Run
3.47 KB
2026-03-11 16:18:52
R W Run
1.87 KB
2026-03-11 16:18:52
R W Run
30.91 KB
2026-03-11 16:18:51
R W Run
7.29 KB
2026-03-11 16:18:52
R W Run
7.35 KB
2026-03-11 16:18:51
R W Run
12.54 KB
2026-03-11 16:18:51
R W Run
19.12 KB
2026-03-11 16:18:51
R W Run
18.12 KB
2026-03-11 16:18:52
R W Run
39.99 KB
2026-03-11 16:18:52
R W Run
5.17 KB
2026-03-11 16:18:52
R W Run
979 By
2026-03-11 16:18:51
R W Run
18.44 KB
2026-03-11 16:18:52
R W Run
10.24 KB
2026-03-11 16:18:51
R W Run
1.77 KB
2026-03-11 16:18:52
R W Run
34.9 KB
2026-03-11 16:18:51
R W Run
7.19 KB
2026-03-11 16:18:52
R W Run
160.5 KB
2026-03-11 16:18:51
R W Run
64.27 KB
2026-03-11 16:18:51
R W Run
27.95 KB
2026-03-11 16:18:51
R W Run
4.69 KB
2026-03-11 16:18:51
R W Run
2.94 KB
2026-03-11 16:18:51
R W Run
43.13 KB
2026-03-11 16:18:52
R W Run
2.25 KB
2026-03-11 16:18:52
R W Run
22.5 KB
2026-03-11 16:18:51
R W Run
13.01 KB
2026-03-11 16:18:52
R W Run
3.27 KB
2026-03-11 16:18:51
R W Run
18 KB
2026-03-11 16:18:51
R W Run
210.4 KB
2026-03-11 16:18:52
R W Run
25.86 KB
2026-03-11 16:18:52
R W Run
115.85 KB
2026-03-11 16:18:51
R W Run
373 By
2026-03-11 16:18:52
R W Run
343 By
2026-03-11 16:18:52
R W Run
338 By
2026-03-11 16:18:51
R W Run
100.73 KB
2026-03-11 16:18:52
R W Run
130.93 KB
2026-03-11 16:18:51
R W Run
19.1 KB
2026-03-11 16:18:51
R W Run
17.41 KB
2026-03-11 16:18:52
R W Run
41.98 KB
2026-03-11 16:18:52
R W Run
400 By
2026-03-11 16:18:52
R W Run
11.1 KB
2026-03-11 16:18:52
R W Run
37.02 KB
2026-03-11 16:18:51
R W Run
2.24 KB
2026-03-11 16:18:51
R W Run
188.13 KB
2026-03-11 16:18:51
R W Run
338 By
2026-03-11 16:18:51
R W Run
38 KB
2026-03-11 16:18:51
R W Run
4.02 KB
2026-03-11 16:18:52
R W Run
5.38 KB
2026-03-11 16:18:51
R W Run
3.05 KB
2026-03-11 16:18:52
R W Run
2.61 KB
2026-03-11 16:18:51
R W Run
1.16 KB
2026-03-11 16:18:52
R W Run
4.04 KB
2026-03-11 16:18:51
R W Run
3.71 KB
2026-03-11 16:18:51
R W Run
24.6 KB
2026-03-11 16:18:51
R W Run
9.56 KB
2026-03-11 16:18:51
R W Run
346.43 KB
2026-03-11 16:18:52
R W Run
281.84 KB
2026-03-11 16:18:52
R W Run
14.95 KB
2026-03-11 16:18:51
R W Run
8.44 KB
2026-03-11 16:18:52
R W Run
168.95 KB
2026-03-11 16:18:52
R W Run
20.71 KB
2026-03-11 16:18:52
R W Run
25.27 KB
2026-03-11 16:18:51
R W Run
5.72 KB
2026-03-11 16:18:51
R W Run
4.63 KB
2026-03-11 16:18:52
R W Run
81.73 KB
2026-03-11 16:18:51
R W Run
67.18 KB
2026-03-11 16:18:51
R W Run
156.36 KB
2026-03-11 16:18:52
R W Run
55.19 KB
2026-03-11 16:18:51
R W Run
162 By
2026-03-11 16:18:51
R W Run
61.72 KB
2026-03-11 16:18:51
R W Run
216.06 KB
2026-03-11 16:18:52
R W Run
65.09 KB
2026-03-11 16:18:51
R W Run
25.24 KB
2026-03-11 16:18:52
R W Run
4.81 KB
2026-03-11 16:18:51
R W Run
6.48 KB
2026-03-11 16:18:52
R W Run
21.25 KB
2026-03-11 16:18:51
R W Run
2.79 KB
2026-03-11 16:18:52
R W Run
89.69 KB
2026-03-11 16:18:52
R W Run
19.42 KB
2026-03-11 16:18:52
R W Run
3.69 KB
2026-03-11 16:18:52
R W Run
4.11 KB
2026-03-11 16:18:51
R W Run
40.74 KB
2026-03-11 16:18:51
R W Run
25.38 KB
2026-03-11 16:18:51
R W Run
43.31 KB
2026-03-11 16:18:52
R W Run
102.57 KB
2026-03-11 16:18:52
R W Run
6.18 KB
2026-03-11 16:18:51
R W Run
124.47 KB
2026-03-11 16:18:52
R W Run
35.65 KB
2026-03-11 16:18:52
R W Run
6.94 KB
2026-03-11 16:18:52
R W Run
67.04 KB
2026-03-11 16:18:52
R W Run
10.62 KB
2026-03-11 16:18:51
R W Run
289.35 KB
2026-03-11 16:18:52
R W Run
36.23 KB
2026-03-11 16:18:51
R W Run
200 By
2026-03-11 16:18:52
R W Run
200 By
2026-03-11 16:18:52
R W Run
98.29 KB
2026-03-11 16:18:52
R W Run
30.02 KB
2026-03-11 16:18:52
R W Run
19.03 KB
2026-03-11 16:18:52
R W Run
5.06 KB
2026-03-11 16:18:52
R W Run
255 By
2026-03-11 16:18:51
R W Run
22.66 KB
2026-03-11 16:18:52
R W Run
154.63 KB
2026-03-11 16:18:51
R W Run
9.68 KB
2026-03-11 16:18:51
R W Run
258 By
2026-03-11 16:18:51
R W Run
23.49 KB
2026-03-11 16:18:51
R W Run
3.16 KB
2026-03-11 16:18:51
R W Run
8.4 KB
2026-03-11 16:18:52
R W Run
441 By
2026-03-11 16:18:51
R W Run
7.39 KB
2026-03-11 16:18:51
R W Run
173 KB
2026-03-11 16:18:52
R W Run
544 By
2026-03-11 16:18:52
R W Run
4.17 KB
2026-03-11 16:18:51
R W Run
35.97 KB
2026-03-11 16:18:52
R W Run
1.69 KB
2026-03-11 16:18:51
R W Run
2.84 KB
2026-03-11 16:18:52
R W Run
6.09 KB
2026-03-11 16:18:51
R W Run
8.71 KB
2026-03-11 16:18:51
R W Run
131.84 KB
2026-03-11 16:18:51
R W Run
37.45 KB
2026-03-11 16:18:51
R W Run
173.89 KB
2026-03-11 16:18:51
R W Run
7.09 KB
2026-03-11 16:18:51
R W Run
6.41 KB
2026-03-11 16:18:51
R W Run
1.08 KB
2026-03-11 16:18:51
R W Run
69.46 KB
2026-03-11 16:18:52
R W Run
445 By
2026-03-11 16:18:51
R W Run
799 By
2026-03-11 16:18:52
R W Run
error_log
📄ms-site.php
1<?php
2/**
3 * Site API
4 *
5 * @package WordPress
6 * @subpackage Multisite
7 * @since 5.1.0
8 */
9
10/**
11 * Inserts a new site into the database.
12 *
13 * @since 5.1.0
14 *
15 * @global wpdb $wpdb WordPress database abstraction object.
16 *
17 * @param array $data {
18 * Data for the new site that should be inserted.
19 *
20 * @type string $domain Site domain. Default empty string.
21 * @type string $path Site path. Default '/'.
22 * @type int $network_id The site's network ID. Default is the current network ID.
23 * @type string $registered When the site was registered, in SQL datetime format. Default is
24 * the current time.
25 * @type string $last_updated When the site was last updated, in SQL datetime format. Default is
26 * the value of $registered.
27 * @type int $public Whether the site is public. Default 1.
28 * @type int $archived Whether the site is archived. Default 0.
29 * @type int $mature Whether the site is mature. Default 0.
30 * @type int $spam Whether the site is spam. Default 0.
31 * @type int $deleted Whether the site is deleted. Default 0.
32 * @type int $lang_id The site's language ID. Currently unused. Default 0.
33 * @type int $user_id User ID for the site administrator. Passed to the
34 * `wp_initialize_site` hook.
35 * @type string $title Site title. Default is 'Site %d' where %d is the site ID. Passed
36 * to the `wp_initialize_site` hook.
37 * @type array $options Custom option $key => $value pairs to use. Default empty array. Passed
38 * to the `wp_initialize_site` hook.
39 * @type array $meta Custom site metadata $key => $value pairs to use. Default empty array.
40 * Passed to the `wp_initialize_site` hook.
41 * }
42 * @return int|WP_Error The new site's ID on success, or error object on failure.
43 */
44function wp_insert_site( array $data ) {
45 global $wpdb;
46
47 $now = current_time( 'mysql', true );
48
49 $defaults = array(
50 'domain' => '',
51 'path' => '/',
52 'network_id' => get_current_network_id(),
53 'registered' => $now,
54 'last_updated' => $now,
55 'public' => 1,
56 'archived' => 0,
57 'mature' => 0,
58 'spam' => 0,
59 'deleted' => 0,
60 'lang_id' => 0,
61 );
62
63 $prepared_data = wp_prepare_site_data( $data, $defaults );
64 if ( is_wp_error( $prepared_data ) ) {
65 return $prepared_data;
66 }
67
68 if ( false === $wpdb->insert( $wpdb->blogs, $prepared_data ) ) {
69 return new WP_Error( 'db_insert_error', __( 'Could not insert site into the database.' ), $wpdb->last_error );
70 }
71
72 $site_id = (int) $wpdb->insert_id;
73
74 clean_blog_cache( $site_id );
75
76 $new_site = get_site( $site_id );
77
78 if ( ! $new_site ) {
79 return new WP_Error( 'get_site_error', __( 'Could not retrieve site data.' ) );
80 }
81
82 /**
83 * Fires once a site has been inserted into the database.
84 *
85 * @since 5.1.0
86 *
87 * @param WP_Site $new_site New site object.
88 */
89 do_action( 'wp_insert_site', $new_site );
90
91 // Extract the passed arguments that may be relevant for site initialization.
92 $args = array_diff_key( $data, $defaults );
93 if ( isset( $args['site_id'] ) ) {
94 unset( $args['site_id'] );
95 }
96
97 /**
98 * Fires when a site's initialization routine should be executed.
99 *
100 * @since 5.1.0
101 *
102 * @param WP_Site $new_site New site object.
103 * @param array $args Arguments for the initialization.
104 */
105 do_action( 'wp_initialize_site', $new_site, $args );
106
107 // Only compute extra hook parameters if the deprecated hook is actually in use.
108 if ( has_action( 'wpmu_new_blog' ) ) {
109 $user_id = ! empty( $args['user_id'] ) ? $args['user_id'] : 0;
110 $meta = ! empty( $args['options'] ) ? $args['options'] : array();
111
112 // WPLANG was passed with `$meta` to the `wpmu_new_blog` hook prior to 5.1.0.
113 if ( ! array_key_exists( 'WPLANG', $meta ) ) {
114 $meta['WPLANG'] = get_network_option( $new_site->network_id, 'WPLANG' );
115 }
116
117 /*
118 * Rebuild the data expected by the `wpmu_new_blog` hook prior to 5.1.0 using allowed keys.
119 * The `$allowed_data_fields` matches the one used in `wpmu_create_blog()`.
120 */
121 $allowed_data_fields = array( 'public', 'archived', 'mature', 'spam', 'deleted', 'lang_id' );
122 $meta = array_merge( array_intersect_key( $data, array_flip( $allowed_data_fields ) ), $meta );
123
124 /**
125 * Fires immediately after a new site is created.
126 *
127 * @since MU (3.0.0)
128 * @deprecated 5.1.0 Use {@see 'wp_initialize_site'} instead.
129 *
130 * @param int $site_id Site ID.
131 * @param int $user_id User ID.
132 * @param string $domain Site domain.
133 * @param string $path Site path.
134 * @param int $network_id Network ID. Only relevant on multi-network installations.
135 * @param array $meta Meta data. Used to set initial site options.
136 */
137 do_action_deprecated(
138 'wpmu_new_blog',
139 array( $new_site->id, $user_id, $new_site->domain, $new_site->path, $new_site->network_id, $meta ),
140 '5.1.0',
141 'wp_initialize_site'
142 );
143 }
144
145 return (int) $new_site->id;
146}
147
148/**
149 * Updates a site in the database.
150 *
151 * @since 5.1.0
152 *
153 * @global wpdb $wpdb WordPress database abstraction object.
154 *
155 * @param int $site_id ID of the site that should be updated.
156 * @param array $data Site data to update. See {@see wp_insert_site()} for the list of supported keys.
157 * @return int|WP_Error The updated site's ID on success, or error object on failure.
158 */
159function wp_update_site( $site_id, array $data ) {
160 global $wpdb;
161
162 if ( empty( $site_id ) ) {
163 return new WP_Error( 'site_empty_id', __( 'Site ID must not be empty.' ) );
164 }
165
166 $old_site = get_site( $site_id );
167 if ( ! $old_site ) {
168 return new WP_Error( 'site_not_exist', __( 'Site does not exist.' ) );
169 }
170
171 $defaults = $old_site->to_array();
172 $defaults['network_id'] = (int) $defaults['site_id'];
173 $defaults['last_updated'] = current_time( 'mysql', true );
174 unset( $defaults['blog_id'], $defaults['site_id'] );
175
176 $data = wp_prepare_site_data( $data, $defaults, $old_site );
177 if ( is_wp_error( $data ) ) {
178 return $data;
179 }
180
181 if ( false === $wpdb->update( $wpdb->blogs, $data, array( 'blog_id' => $old_site->id ) ) ) {
182 return new WP_Error( 'db_update_error', __( 'Could not update site in the database.' ), $wpdb->last_error );
183 }
184
185 clean_blog_cache( $old_site );
186
187 $new_site = get_site( $old_site->id );
188
189 /**
190 * Fires once a site has been updated in the database.
191 *
192 * @since 5.1.0
193 *
194 * @param WP_Site $new_site New site object.
195 * @param WP_Site $old_site Old site object.
196 */
197 do_action( 'wp_update_site', $new_site, $old_site );
198
199 return (int) $new_site->id;
200}
201
202/**
203 * Deletes a site from the database.
204 *
205 * @since 5.1.0
206 *
207 * @global wpdb $wpdb WordPress database abstraction object.
208 *
209 * @param int $site_id ID of the site that should be deleted.
210 * @return WP_Site|WP_Error The deleted site object on success, or error object on failure.
211 */
212function wp_delete_site( $site_id ) {
213 global $wpdb;
214
215 if ( empty( $site_id ) ) {
216 return new WP_Error( 'site_empty_id', __( 'Site ID must not be empty.' ) );
217 }
218
219 $old_site = get_site( $site_id );
220 if ( ! $old_site ) {
221 return new WP_Error( 'site_not_exist', __( 'Site does not exist.' ) );
222 }
223
224 $errors = new WP_Error();
225
226 /**
227 * Fires before a site should be deleted from the database.
228 *
229 * Plugins should amend the `$errors` object via its `WP_Error::add()` method. If any errors
230 * are present, the site will not be deleted.
231 *
232 * @since 5.1.0
233 *
234 * @param WP_Error $errors Error object to add validation errors to.
235 * @param WP_Site $old_site The site object to be deleted.
236 */
237 do_action( 'wp_validate_site_deletion', $errors, $old_site );
238
239 if ( ! empty( $errors->errors ) ) {
240 return $errors;
241 }
242
243 /**
244 * Fires before a site is deleted.
245 *
246 * @since MU (3.0.0)
247 * @deprecated 5.1.0
248 *
249 * @param int $site_id The site ID.
250 * @param bool $drop True if site's table should be dropped. Default false.
251 */
252 do_action_deprecated( 'delete_blog', array( $old_site->id, true ), '5.1.0' );
253
254 /**
255 * Fires when a site's uninitialization routine should be executed.
256 *
257 * @since 5.1.0
258 *
259 * @param WP_Site $old_site Deleted site object.
260 */
261 do_action( 'wp_uninitialize_site', $old_site );
262
263 if ( is_site_meta_supported() ) {
264 $blog_meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->blogmeta WHERE blog_id = %d ", $old_site->id ) );
265 foreach ( $blog_meta_ids as $mid ) {
266 delete_metadata_by_mid( 'blog', $mid );
267 }
268 }
269
270 if ( false === $wpdb->delete( $wpdb->blogs, array( 'blog_id' => $old_site->id ) ) ) {
271 return new WP_Error( 'db_delete_error', __( 'Could not delete site from the database.' ), $wpdb->last_error );
272 }
273
274 clean_blog_cache( $old_site );
275
276 /**
277 * Fires once a site has been deleted from the database.
278 *
279 * @since 5.1.0
280 *
281 * @param WP_Site $old_site Deleted site object.
282 */
283 do_action( 'wp_delete_site', $old_site );
284
285 /**
286 * Fires after the site is deleted from the network.
287 *
288 * @since 4.8.0
289 * @deprecated 5.1.0
290 *
291 * @param int $site_id The site ID.
292 * @param bool $drop True if site's tables should be dropped. Default false.
293 */
294 do_action_deprecated( 'deleted_blog', array( $old_site->id, true ), '5.1.0' );
295
296 return $old_site;
297}
298
299/**
300 * Retrieves site data given a site ID or site object.
301 *
302 * Site data will be cached and returned after being passed through a filter.
303 * If the provided site is empty, the current site global will be used.
304 *
305 * @since 4.6.0
306 *
307 * @param WP_Site|int|null $site Optional. Site to retrieve. Default is the current site.
308 * @return WP_Site|null The site object or null if not found.
309 */
310function get_site( $site = null ) {
311 if ( empty( $site ) ) {
312 $site = get_current_blog_id();
313 }
314
315 if ( $site instanceof WP_Site ) {
316 $_site = $site;
317 } elseif ( is_object( $site ) ) {
318 $_site = new WP_Site( $site );
319 } else {
320 $_site = WP_Site::get_instance( $site );
321 }
322
323 if ( ! $_site ) {
324 return null;
325 }
326
327 /**
328 * Fires after a site is retrieved.
329 *
330 * @since 4.6.0
331 *
332 * @param WP_Site $_site Site data.
333 */
334 $_site = apply_filters( 'get_site', $_site );
335
336 return $_site;
337}
338
339/**
340 * Adds any sites from the given IDs to the cache that do not already exist in cache.
341 *
342 * @since 4.6.0
343 * @since 5.1.0 Introduced the `$update_meta_cache` parameter.
344 * @since 6.1.0 This function is no longer marked as "private".
345 * @since 6.3.0 Use wp_lazyload_site_meta() for lazy-loading of site meta.
346 *
347 * @see update_site_cache()
348 * @global wpdb $wpdb WordPress database abstraction object.
349 *
350 * @param array $ids ID list.
351 * @param bool $update_meta_cache Optional. Whether to update the meta cache. Default true.
352 */
353function _prime_site_caches( $ids, $update_meta_cache = true ) {
354 global $wpdb;
355
356 $non_cached_ids = _get_non_cached_ids( $ids, 'sites' );
357 if ( ! empty( $non_cached_ids ) ) {
358 $fresh_sites = $wpdb->get_results( sprintf( "SELECT * FROM $wpdb->blogs WHERE blog_id IN (%s)", implode( ',', array_map( 'intval', $non_cached_ids ) ) ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
359
360 update_site_cache( $fresh_sites, false );
361 }
362
363 if ( $update_meta_cache ) {
364 wp_lazyload_site_meta( $ids );
365 }
366}
367
368/**
369 * Queue site meta for lazy-loading.
370 *
371 * @since 6.3.0
372 *
373 * @param array $site_ids List of site IDs.
374 */
375function wp_lazyload_site_meta( array $site_ids ) {
376 if ( empty( $site_ids ) ) {
377 return;
378 }
379 $lazyloader = wp_metadata_lazyloader();
380 $lazyloader->queue_objects( 'blog', $site_ids );
381}
382
383/**
384 * Updates sites in cache.
385 *
386 * @since 4.6.0
387 * @since 5.1.0 Introduced the `$update_meta_cache` parameter.
388 *
389 * @param array $sites Array of site objects.
390 * @param bool $update_meta_cache Whether to update site meta cache. Default true.
391 */
392function update_site_cache( $sites, $update_meta_cache = true ) {
393 if ( ! $sites ) {
394 return;
395 }
396 $site_ids = array();
397 $site_data = array();
398 $blog_details_data = array();
399 foreach ( $sites as $site ) {
400 $site_ids[] = $site->blog_id;
401 $site_data[ $site->blog_id ] = $site;
402 $blog_details_data[ $site->blog_id . 'short' ] = $site;
403
404 }
405 wp_cache_add_multiple( $site_data, 'sites' );
406 wp_cache_add_multiple( $blog_details_data, 'blog-details' );
407
408 if ( $update_meta_cache ) {
409 update_sitemeta_cache( $site_ids );
410 }
411}
412
413/**
414 * Updates metadata cache for list of site IDs.
415 *
416 * Performs SQL query to retrieve all metadata for the sites matching `$site_ids` and stores them in the cache.
417 * Subsequent calls to `get_site_meta()` will not need to query the database.
418 *
419 * @since 5.1.0
420 *
421 * @param array $site_ids List of site IDs.
422 * @return array|false An array of metadata on success, false if there is nothing to update.
423 */
424function update_sitemeta_cache( $site_ids ) {
425 // Ensure this filter is hooked in even if the function is called early.
426 if ( ! has_filter( 'update_blog_metadata_cache', 'wp_check_site_meta_support_prefilter' ) ) {
427 add_filter( 'update_blog_metadata_cache', 'wp_check_site_meta_support_prefilter' );
428 }
429 return update_meta_cache( 'blog', $site_ids );
430}
431
432/**
433 * Retrieves a list of sites matching requested arguments.
434 *
435 * @since 4.6.0
436 * @since 4.8.0 Introduced the 'lang_id', 'lang__in', and 'lang__not_in' parameters.
437 *
438 * @see WP_Site_Query::parse_query()
439 *
440 * @param string|array $args Optional. Array or string of arguments. See WP_Site_Query::__construct()
441 * for information on accepted arguments. Default empty array.
442 * @return WP_Site[]|int[]|int List of WP_Site objects, a list of site IDs when 'fields' is set to 'ids',
443 * or the number of sites when 'count' is passed as a query var.
444 */
445function get_sites( $args = array() ) {
446 $query = new WP_Site_Query();
447
448 return $query->query( $args );
449}
450
451/**
452 * Prepares site data for insertion or update in the database.
453 *
454 * @since 5.1.0
455 *
456 * @param array $data Associative array of site data passed to the respective function.
457 * See {@see wp_insert_site()} for the possibly included data.
458 * @param array $defaults Site data defaults to parse $data against.
459 * @param WP_Site|null $old_site Optional. Old site object if an update, or null if an insertion.
460 * Default null.
461 * @return array|WP_Error Site data ready for a database transaction, or WP_Error in case a validation
462 * error occurred.
463 */
464function wp_prepare_site_data( $data, $defaults, $old_site = null ) {
465
466 // Maintain backward-compatibility with `$site_id` as network ID.
467 if ( isset( $data['site_id'] ) ) {
468 if ( ! empty( $data['site_id'] ) && empty( $data['network_id'] ) ) {
469 $data['network_id'] = $data['site_id'];
470 }
471 unset( $data['site_id'] );
472 }
473
474 /**
475 * Filters passed site data in order to normalize it.
476 *
477 * @since 5.1.0
478 *
479 * @param array $data Associative array of site data passed to the respective function.
480 * See {@see wp_insert_site()} for the possibly included data.
481 */
482 $data = apply_filters( 'wp_normalize_site_data', $data );
483
484 $allowed_data_fields = array( 'domain', 'path', 'network_id', 'registered', 'last_updated', 'public', 'archived', 'mature', 'spam', 'deleted', 'lang_id' );
485 $data = array_intersect_key( wp_parse_args( $data, $defaults ), array_flip( $allowed_data_fields ) );
486
487 $errors = new WP_Error();
488
489 /**
490 * Fires when data should be validated for a site prior to inserting or updating in the database.
491 *
492 * Plugins should amend the `$errors` object via its `WP_Error::add()` method.
493 *
494 * @since 5.1.0
495 *
496 * @param WP_Error $errors Error object to add validation errors to.
497 * @param array $data Associative array of complete site data. See {@see wp_insert_site()}
498 * for the included data.
499 * @param WP_Site|null $old_site The old site object if the data belongs to a site being updated,
500 * or null if it is a new site being inserted.
501 */
502 do_action( 'wp_validate_site_data', $errors, $data, $old_site );
503
504 if ( ! empty( $errors->errors ) ) {
505 return $errors;
506 }
507
508 // Prepare for database.
509 $data['site_id'] = $data['network_id'];
510 unset( $data['network_id'] );
511
512 return $data;
513}
514
515/**
516 * Normalizes data for a site prior to inserting or updating in the database.
517 *
518 * @since 5.1.0
519 *
520 * @param array $data Associative array of site data passed to the respective function.
521 * See {@see wp_insert_site()} for the possibly included data.
522 * @return array Normalized site data.
523 */
524function wp_normalize_site_data( $data ) {
525 // Sanitize domain if passed.
526 if ( array_key_exists( 'domain', $data ) ) {
527 $data['domain'] = preg_replace( '/[^a-z0-9\-.:]+/i', '', $data['domain'] );
528 }
529
530 // Sanitize path if passed.
531 if ( array_key_exists( 'path', $data ) ) {
532 $data['path'] = trailingslashit( '/' . trim( $data['path'], '/' ) );
533 }
534
535 // Sanitize network ID if passed.
536 if ( array_key_exists( 'network_id', $data ) ) {
537 $data['network_id'] = (int) $data['network_id'];
538 }
539
540 // Sanitize status fields if passed.
541 $status_fields = array( 'public', 'archived', 'mature', 'spam', 'deleted' );
542 foreach ( $status_fields as $status_field ) {
543 if ( array_key_exists( $status_field, $data ) ) {
544 $data[ $status_field ] = (int) $data[ $status_field ];
545 }
546 }
547
548 // Strip date fields if empty.
549 $date_fields = array( 'registered', 'last_updated' );
550 foreach ( $date_fields as $date_field ) {
551 if ( ! array_key_exists( $date_field, $data ) ) {
552 continue;
553 }
554
555 if ( empty( $data[ $date_field ] ) || '0000-00-00 00:00:00' === $data[ $date_field ] ) {
556 unset( $data[ $date_field ] );
557 }
558 }
559
560 return $data;
561}
562
563/**
564 * Validates data for a site prior to inserting or updating in the database.
565 *
566 * @since 5.1.0
567 *
568 * @param WP_Error $errors Error object, passed by reference. Will contain validation errors if
569 * any occurred.
570 * @param array $data Associative array of complete site data. See {@see wp_insert_site()}
571 * for the included data.
572 * @param WP_Site|null $old_site The old site object if the data belongs to a site being updated,
573 * or null if it is a new site being inserted.
574 */
575function wp_validate_site_data( $errors, $data, $old_site = null ) {
576 // A domain must always be present.
577 if ( empty( $data['domain'] ) ) {
578 $errors->add( 'site_empty_domain', __( 'Site domain must not be empty.' ) );
579 }
580
581 // A path must always be present.
582 if ( empty( $data['path'] ) ) {
583 $errors->add( 'site_empty_path', __( 'Site path must not be empty.' ) );
584 }
585
586 // A network ID must always be present.
587 if ( empty( $data['network_id'] ) ) {
588 $errors->add( 'site_empty_network_id', __( 'Site network ID must be provided.' ) );
589 }
590
591 // Both registration and last updated dates must always be present and valid.
592 $date_fields = array( 'registered', 'last_updated' );
593 foreach ( $date_fields as $date_field ) {
594 if ( empty( $data[ $date_field ] ) ) {
595 $errors->add( 'site_empty_' . $date_field, __( 'Both registration and last updated dates must be provided.' ) );
596 break;
597 }
598
599 // Allow '0000-00-00 00:00:00', although it be stripped out at this point.
600 if ( '0000-00-00 00:00:00' !== $data[ $date_field ] ) {
601 $month = substr( $data[ $date_field ], 5, 2 );
602 $day = substr( $data[ $date_field ], 8, 2 );
603 $year = substr( $data[ $date_field ], 0, 4 );
604 $valid_date = wp_checkdate( $month, $day, $year, $data[ $date_field ] );
605 if ( ! $valid_date ) {
606 $errors->add( 'site_invalid_' . $date_field, __( 'Both registration and last updated dates must be valid dates.' ) );
607 break;
608 }
609 }
610 }
611
612 if ( ! empty( $errors->errors ) ) {
613 return;
614 }
615
616 // If a new site, or domain/path/network ID have changed, ensure uniqueness.
617 if ( ! $old_site
618 || $data['domain'] !== $old_site->domain
619 || $data['path'] !== $old_site->path
620 || $data['network_id'] !== $old_site->network_id
621 ) {
622 if ( domain_exists( $data['domain'], $data['path'], $data['network_id'] ) ) {
623 $errors->add( 'site_taken', __( 'Sorry, that site already exists!' ) );
624 }
625 }
626}
627
628/**
629 * Runs the initialization routine for a given site.
630 *
631 * This process includes creating the site's database tables and
632 * populating them with defaults.
633 *
634 * @since 5.1.0
635 *
636 * @global wpdb $wpdb WordPress database abstraction object.
637 * @global WP_Roles $wp_roles WordPress role management object.
638 *
639 * @param int|WP_Site $site_id Site ID or object.
640 * @param array $args {
641 * Optional. Arguments to modify the initialization behavior.
642 *
643 * @type int $user_id Required. User ID for the site administrator.
644 * @type string $title Site title. Default is 'Site %d' where %d is the
645 * site ID.
646 * @type array $options Custom option $key => $value pairs to use. Default
647 * empty array.
648 * @type array $meta Custom site metadata $key => $value pairs to use.
649 * Default empty array.
650 * }
651 * @return true|WP_Error True on success, or error object on failure.
652 */
653function wp_initialize_site( $site_id, array $args = array() ) {
654 global $wpdb, $wp_roles;
655
656 if ( empty( $site_id ) ) {
657 return new WP_Error( 'site_empty_id', __( 'Site ID must not be empty.' ) );
658 }
659
660 $site = get_site( $site_id );
661 if ( ! $site ) {
662 return new WP_Error( 'site_invalid_id', __( 'Site with the ID does not exist.' ) );
663 }
664
665 if ( wp_is_site_initialized( $site ) ) {
666 return new WP_Error( 'site_already_initialized', __( 'The site appears to be already initialized.' ) );
667 }
668
669 $network = get_network( $site->network_id );
670 if ( ! $network ) {
671 $network = get_network();
672 }
673
674 $args = wp_parse_args(
675 $args,
676 array(
677 'user_id' => 0,
678 /* translators: %d: Site ID. */
679 'title' => sprintf( __( 'Site %d' ), $site->id ),
680 'options' => array(),
681 'meta' => array(),
682 )
683 );
684
685 /**
686 * Filters the arguments for initializing a site.
687 *
688 * @since 5.1.0
689 *
690 * @param array $args Arguments to modify the initialization behavior.
691 * @param WP_Site $site Site that is being initialized.
692 * @param WP_Network $network Network that the site belongs to.
693 */
694 $args = apply_filters( 'wp_initialize_site_args', $args, $site, $network );
695
696 $orig_installing = wp_installing();
697 if ( ! $orig_installing ) {
698 wp_installing( true );
699 }
700
701 $switch = false;
702 if ( get_current_blog_id() !== $site->id ) {
703 $switch = true;
704 switch_to_blog( $site->id );
705 }
706
707 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
708
709 // Set up the database tables.
710 make_db_current_silent( 'blog' );
711
712 $home_scheme = 'http';
713 $siteurl_scheme = 'http';
714 if ( ! is_subdomain_install() ) {
715 if ( 'https' === parse_url( get_home_url( $network->site_id ), PHP_URL_SCHEME ) ) {
716 $home_scheme = 'https';
717 }
718 if ( 'https' === parse_url( get_network_option( $network->id, 'siteurl' ), PHP_URL_SCHEME ) ) {
719 $siteurl_scheme = 'https';
720 }
721 }
722
723 // Populate the site's options.
724 populate_options(
725 array_merge(
726 array(
727 'home' => untrailingslashit( $home_scheme . '://' . $site->domain . $site->path ),
728 'siteurl' => untrailingslashit( $siteurl_scheme . '://' . $site->domain . $site->path ),
729 'blogname' => wp_unslash( $args['title'] ),
730 'admin_email' => '',
731 'upload_path' => get_network_option( $network->id, 'ms_files_rewriting' ) ? UPLOADBLOGSDIR . "/{$site->id}/files" : get_blog_option( $network->site_id, 'upload_path' ),
732 'blog_public' => (int) $site->public,
733 'WPLANG' => get_network_option( $network->id, 'WPLANG' ),
734 ),
735 $args['options']
736 )
737 );
738
739 // Clean blog cache after populating options.
740 clean_blog_cache( $site );
741
742 // Populate the site's roles.
743 populate_roles();
744 $wp_roles = new WP_Roles();
745
746 // Populate metadata for the site.
747 populate_site_meta( $site->id, $args['meta'] );
748
749 // Remove all permissions that may exist for the site.
750 $table_prefix = $wpdb->get_blog_prefix();
751 delete_metadata( 'user', 0, $table_prefix . 'user_level', null, true ); // Delete all.
752 delete_metadata( 'user', 0, $table_prefix . 'capabilities', null, true ); // Delete all.
753
754 // Install default site content.
755 wp_install_defaults( $args['user_id'] );
756
757 // Set the site administrator.
758 add_user_to_blog( $site->id, $args['user_id'], 'administrator' );
759 if ( ! user_can( $args['user_id'], 'manage_network' ) && ! get_user_meta( $args['user_id'], 'primary_blog', true ) ) {
760 update_user_meta( $args['user_id'], 'primary_blog', $site->id );
761 }
762
763 if ( $switch ) {
764 restore_current_blog();
765 }
766
767 wp_installing( $orig_installing );
768
769 return true;
770}
771
772/**
773 * Runs the uninitialization routine for a given site.
774 *
775 * This process includes dropping the site's database tables and deleting its uploads directory.
776 *
777 * @since 5.1.0
778 *
779 * @global wpdb $wpdb WordPress database abstraction object.
780 *
781 * @param int|WP_Site $site_id Site ID or object.
782 * @return true|WP_Error True on success, or error object on failure.
783 */
784function wp_uninitialize_site( $site_id ) {
785 global $wpdb;
786
787 if ( empty( $site_id ) ) {
788 return new WP_Error( 'site_empty_id', __( 'Site ID must not be empty.' ) );
789 }
790
791 $site = get_site( $site_id );
792 if ( ! $site ) {
793 return new WP_Error( 'site_invalid_id', __( 'Site with the ID does not exist.' ) );
794 }
795
796 if ( ! wp_is_site_initialized( $site ) ) {
797 return new WP_Error( 'site_already_uninitialized', __( 'The site appears to be already uninitialized.' ) );
798 }
799
800 $users = get_users(
801 array(
802 'blog_id' => $site->id,
803 'fields' => 'ids',
804 )
805 );
806
807 // Remove users from the site.
808 if ( ! empty( $users ) ) {
809 foreach ( $users as $user_id ) {
810 remove_user_from_blog( $user_id, $site->id );
811 }
812 }
813
814 $switch = false;
815 if ( get_current_blog_id() !== $site->id ) {
816 $switch = true;
817 switch_to_blog( $site->id );
818 }
819
820 $uploads = wp_get_upload_dir();
821
822 $tables = $wpdb->tables( 'blog' );
823
824 /**
825 * Filters the tables to drop when the site is deleted.
826 *
827 * @since MU (3.0.0)
828 *
829 * @param string[] $tables Array of names of the site tables to be dropped.
830 * @param int $site_id The ID of the site to drop tables for.
831 */
832 $drop_tables = apply_filters( 'wpmu_drop_tables', $tables, $site->id );
833
834 foreach ( (array) $drop_tables as $table ) {
835 $wpdb->query( "DROP TABLE IF EXISTS `$table`" ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
836 }
837
838 /**
839 * Filters the upload base directory to delete when the site is deleted.
840 *
841 * @since MU (3.0.0)
842 *
843 * @param string $basedir Uploads path without subdirectory. See {@see wp_upload_dir()}.
844 * @param int $site_id The site ID.
845 */
846 $dir = apply_filters( 'wpmu_delete_blog_upload_dir', $uploads['basedir'], $site->id );
847 $dir = rtrim( $dir, DIRECTORY_SEPARATOR );
848 $top_dir = $dir;
849 $stack = array( $dir );
850 $index = 0;
851
852 while ( $index < count( $stack ) ) {
853 // Get indexed directory from stack.
854 $dir = $stack[ $index ];
855
856 // phpcs:disable WordPress.PHP.NoSilencedErrors.Discouraged
857 $dh = @opendir( $dir );
858 if ( $dh ) {
859 $file = @readdir( $dh );
860 while ( false !== $file ) {
861 if ( '.' === $file || '..' === $file ) {
862 $file = @readdir( $dh );
863 continue;
864 }
865
866 if ( @is_dir( $dir . DIRECTORY_SEPARATOR . $file ) ) {
867 $stack[] = $dir . DIRECTORY_SEPARATOR . $file;
868 } elseif ( @is_file( $dir . DIRECTORY_SEPARATOR . $file ) ) {
869 @unlink( $dir . DIRECTORY_SEPARATOR . $file );
870 }
871
872 $file = @readdir( $dh );
873 }
874 @closedir( $dh );
875 }
876 ++$index;
877 }
878
879 $stack = array_reverse( $stack ); // Last added directories are deepest.
880 foreach ( (array) $stack as $dir ) {
881 if ( $dir !== $top_dir ) {
882 @rmdir( $dir );
883 }
884 }
885
886 // phpcs:enable WordPress.PHP.NoSilencedErrors.Discouraged
887 if ( $switch ) {
888 restore_current_blog();
889 }
890
891 return true;
892}
893
894/**
895 * Checks whether a site is initialized.
896 *
897 * A site is considered initialized when its database tables are present.
898 *
899 * @since 5.1.0
900 *
901 * @global wpdb $wpdb WordPress database abstraction object.
902 *
903 * @param int|WP_Site $site_id Site ID or object.
904 * @return bool True if the site is initialized, false otherwise.
905 */
906function wp_is_site_initialized( $site_id ) {
907 global $wpdb;
908
909 if ( is_object( $site_id ) ) {
910 $site_id = $site_id->blog_id;
911 }
912 $site_id = (int) $site_id;
913
914 /**
915 * Filters the check for whether a site is initialized before the database is accessed.
916 *
917 * Returning a non-null value will effectively short-circuit the function, returning
918 * that value instead.
919 *
920 * @since 5.1.0
921 *
922 * @param bool|null $pre The value to return instead. Default null
923 * to continue with the check.
924 * @param int $site_id The site ID that is being checked.
925 */
926 $pre = apply_filters( 'pre_wp_is_site_initialized', null, $site_id );
927 if ( null !== $pre ) {
928 return (bool) $pre;
929 }
930
931 $switch = false;
932 if ( get_current_blog_id() !== $site_id ) {
933 $switch = true;
934 remove_action( 'switch_blog', 'wp_switch_roles_and_user', 1 );
935 switch_to_blog( $site_id );
936 }
937
938 $suppress = $wpdb->suppress_errors();
939 $result = (bool) $wpdb->get_results( "DESCRIBE {$wpdb->posts}" );
940 $wpdb->suppress_errors( $suppress );
941
942 if ( $switch ) {
943 restore_current_blog();
944 add_action( 'switch_blog', 'wp_switch_roles_and_user', 1, 2 );
945 }
946
947 return $result;
948}
949
950/**
951 * Clean the blog cache
952 *
953 * @since 3.5.0
954 *
955 * @global bool $_wp_suspend_cache_invalidation
956 *
957 * @param WP_Site|int $blog The site object or ID to be cleared from cache.
958 */
959function clean_blog_cache( $blog ) {
960 global $_wp_suspend_cache_invalidation;
961
962 if ( ! empty( $_wp_suspend_cache_invalidation ) ) {
963 return;
964 }
965
966 if ( empty( $blog ) ) {
967 return;
968 }
969
970 $blog_id = $blog;
971 $blog = get_site( $blog_id );
972 if ( ! $blog ) {
973 if ( ! is_numeric( $blog_id ) ) {
974 return;
975 }
976
977 // Make sure a WP_Site object exists even when the site has been deleted.
978 $blog = new WP_Site(
979 (object) array(
980 'blog_id' => $blog_id,
981 'domain' => null,
982 'path' => null,
983 )
984 );
985 }
986
987 $blog_id = $blog->blog_id;
988 $domain_path_key = md5( $blog->domain . $blog->path );
989
990 wp_cache_delete( $blog_id, 'sites' );
991 wp_cache_delete( $blog_id, 'site-details' );
992 wp_cache_delete( $blog_id, 'blog-details' );
993 wp_cache_delete( $blog_id . 'short', 'blog-details' );
994 wp_cache_delete( $domain_path_key, 'blog-lookup' );
995 wp_cache_delete( $domain_path_key, 'blog-id-cache' );
996 wp_cache_delete( $blog_id, 'blog_meta' );
997
998 /**
999 * Fires immediately after a site has been removed from the object cache.
1000 *
1001 * @since 4.6.0
1002 *
1003 * @param string $id Site ID as a numeric string.
1004 * @param WP_Site $blog Site object.
1005 * @param string $domain_path_key md5 hash of domain and path.
1006 */
1007 do_action( 'clean_site_cache', $blog_id, $blog, $domain_path_key );
1008
1009 wp_cache_set_sites_last_changed();
1010
1011 /**
1012 * Fires after the blog details cache is cleared.
1013 *
1014 * @since 3.4.0
1015 * @deprecated 4.9.0 Use {@see 'clean_site_cache'} instead.
1016 *
1017 * @param int $blog_id Blog ID.
1018 */
1019 do_action_deprecated( 'refresh_blog_details', array( $blog_id ), '4.9.0', 'clean_site_cache' );
1020}
1021
1022/**
1023 * Adds metadata to a site.
1024 *
1025 * For historical reasons both the meta key and the meta value are expected to be "slashed" (slashes escaped) on input.
1026 *
1027 * @since 5.1.0
1028 *
1029 * @param int $site_id Site ID.
1030 * @param string $meta_key Metadata name.
1031 * @param mixed $meta_value Metadata value. Arrays and objects are stored as serialized data and
1032 * will be returned as the same type when retrieved. Other data types will
1033 * be stored as strings in the database:
1034 * - false is stored and retrieved as an empty string ('')
1035 * - true is stored and retrieved as '1'
1036 * - numbers (both integer and float) are stored and retrieved as strings
1037 * Must be serializable if non-scalar.
1038 * @param bool $unique Optional. Whether the same key should not be added.
1039 * Default false.
1040 * @return int|false Meta ID on success, false on failure.
1041 */
1042function add_site_meta( $site_id, $meta_key, $meta_value, $unique = false ) {
1043 return add_metadata( 'blog', $site_id, $meta_key, $meta_value, $unique );
1044}
1045
1046/**
1047 * Removes metadata matching criteria from a site.
1048 *
1049 * You can match based on the key, or key and value. Removing based on key and
1050 * value, will keep from removing duplicate metadata with the same key. It also
1051 * allows removing all metadata matching key, if needed.
1052 *
1053 * For historical reasons both the meta key and the meta value are expected to be "slashed" (slashes escaped) on input.
1054 *
1055 * @since 5.1.0
1056 *
1057 * @param int $site_id Site ID.
1058 * @param string $meta_key Metadata name.
1059 * @param mixed $meta_value Optional. Metadata value. If provided,
1060 * rows will only be removed that match the value.
1061 * Must be serializable if non-scalar. Default empty.
1062 * @return bool True on success, false on failure.
1063 */
1064function delete_site_meta( $site_id, $meta_key, $meta_value = '' ) {
1065 return delete_metadata( 'blog', $site_id, $meta_key, $meta_value );
1066}
1067
1068/**
1069 * Retrieves metadata for a site.
1070 *
1071 * @since 5.1.0
1072 *
1073 * @param int $site_id Site ID.
1074 * @param string $key Optional. The meta key to retrieve. By default,
1075 * returns data for all keys. Default empty.
1076 * @param bool $single Optional. Whether to return a single value.
1077 * This parameter has no effect if `$key` is not specified.
1078 * Default false.
1079 * @return mixed An array of values if `$single` is false.
1080 * The value of meta data field if `$single` is true.
1081 * False for an invalid `$site_id` (non-numeric, zero, or negative value).
1082 * An empty array if a valid but non-existing site ID is passed and `$single` is false.
1083 * An empty string if a valid but non-existing site ID is passed and `$single` is true.
1084 * Note: Non-serialized values are returned as strings:
1085 * - false values are returned as empty strings ('')
1086 * - true values are returned as '1'
1087 * - numbers (both integer and float) are returned as strings
1088 * Arrays and objects retain their original type.
1089 */
1090function get_site_meta( $site_id, $key = '', $single = false ) {
1091 return get_metadata( 'blog', $site_id, $key, $single );
1092}
1093
1094/**
1095 * Updates metadata for a site.
1096 *
1097 * Use the `$prev_value` parameter to differentiate between meta fields with the
1098 * same key and site ID.
1099 *
1100 * If the meta field for the site does not exist, it will be added.
1101 *
1102 * For historical reasons both the meta key and the meta value are expected to be "slashed" (slashes escaped) on input.
1103 *
1104 * @since 5.1.0
1105 *
1106 * @param int $site_id Site ID.
1107 * @param string $meta_key Metadata key.
1108 * @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
1109 * @param mixed $prev_value Optional. Previous value to check before updating.
1110 * If specified, only update existing metadata entries with
1111 * this value. Otherwise, update all entries. Default empty.
1112 * @return int|bool Meta ID if the key didn't exist, true on successful update,
1113 * false on failure or if the value passed to the function
1114 * is the same as the one that is already in the database.
1115 */
1116function update_site_meta( $site_id, $meta_key, $meta_value, $prev_value = '' ) {
1117 return update_metadata( 'blog', $site_id, $meta_key, $meta_value, $prev_value );
1118}
1119
1120/**
1121 * Deletes everything from site meta matching meta key.
1122 *
1123 * @since 5.1.0
1124 *
1125 * @param string $meta_key Metadata key to search for when deleting.
1126 * @return bool Whether the site meta key was deleted from the database.
1127 */
1128function delete_site_meta_by_key( $meta_key ) {
1129 return delete_metadata( 'blog', null, $meta_key, '', true );
1130}
1131
1132/**
1133 * Updates the count of sites for a network based on a changed site.
1134 *
1135 * @since 5.1.0
1136 *
1137 * @param WP_Site $new_site The site object that has been inserted, updated or deleted.
1138 * @param WP_Site|null $old_site Optional. If $new_site has been updated, this must be the previous
1139 * state of that site. Default null.
1140 */
1141function wp_maybe_update_network_site_counts_on_update( $new_site, $old_site = null ) {
1142 if ( null === $old_site ) {
1143 wp_maybe_update_network_site_counts( $new_site->network_id );
1144 return;
1145 }
1146
1147 if ( $new_site->network_id !== $old_site->network_id ) {
1148 wp_maybe_update_network_site_counts( $new_site->network_id );
1149 wp_maybe_update_network_site_counts( $old_site->network_id );
1150 }
1151}
1152
1153/**
1154 * Triggers actions on site status updates.
1155 *
1156 * @since 5.1.0
1157 *
1158 * @param WP_Site $new_site The site object after the update.
1159 * @param WP_Site|null $old_site Optional. If $new_site has been updated, this must be the previous
1160 * state of that site. Default null.
1161 */
1162function wp_maybe_transition_site_statuses_on_update( $new_site, $old_site = null ) {
1163 $site_id = $new_site->id;
1164
1165 // Use the default values for a site if no previous state is given.
1166 if ( ! $old_site ) {
1167 $old_site = new WP_Site( new stdClass() );
1168 }
1169
1170 if ( $new_site->spam !== $old_site->spam ) {
1171 if ( '1' === $new_site->spam ) {
1172
1173 /**
1174 * Fires when the 'spam' status is added to a site.
1175 *
1176 * @since MU (3.0.0)
1177 *
1178 * @param int $site_id Site ID.
1179 */
1180 do_action( 'make_spam_blog', $site_id );
1181 } else {
1182
1183 /**
1184 * Fires when the 'spam' status is removed from a site.
1185 *
1186 * @since MU (3.0.0)
1187 *
1188 * @param int $site_id Site ID.
1189 */
1190 do_action( 'make_ham_blog', $site_id );
1191 }
1192 }
1193
1194 if ( $new_site->mature !== $old_site->mature ) {
1195 if ( '1' === $new_site->mature ) {
1196
1197 /**
1198 * Fires when the 'mature' status is added to a site.
1199 *
1200 * @since 3.1.0
1201 *
1202 * @param int $site_id Site ID.
1203 */
1204 do_action( 'mature_blog', $site_id );
1205 } else {
1206
1207 /**
1208 * Fires when the 'mature' status is removed from a site.
1209 *
1210 * @since 3.1.0
1211 *
1212 * @param int $site_id Site ID.
1213 */
1214 do_action( 'unmature_blog', $site_id );
1215 }
1216 }
1217
1218 if ( $new_site->archived !== $old_site->archived ) {
1219 if ( '1' === $new_site->archived ) {
1220
1221 /**
1222 * Fires when the 'archived' status is added to a site.
1223 *
1224 * @since MU (3.0.0)
1225 *
1226 * @param int $site_id Site ID.
1227 */
1228 do_action( 'archive_blog', $site_id );
1229 } else {
1230
1231 /**
1232 * Fires when the 'archived' status is removed from a site.
1233 *
1234 * @since MU (3.0.0)
1235 *
1236 * @param int $site_id Site ID.
1237 */
1238 do_action( 'unarchive_blog', $site_id );
1239 }
1240 }
1241
1242 if ( $new_site->deleted !== $old_site->deleted ) {
1243 if ( '1' === $new_site->deleted ) {
1244
1245 /**
1246 * Fires when the 'flagged for deletion' status is added to a site.
1247 *
1248 * @since 3.5.0
1249 *
1250 * @param int $site_id Site ID.
1251 */
1252 do_action( 'make_delete_blog', $site_id );
1253 } else {
1254
1255 /**
1256 * Fires when the 'flagged for deletion' status is removed from a site.
1257 *
1258 * @since 3.5.0
1259 *
1260 * @param int $site_id Site ID.
1261 */
1262 do_action( 'make_undelete_blog', $site_id );
1263 }
1264 }
1265
1266 if ( $new_site->public !== $old_site->public ) {
1267
1268 /**
1269 * Fires after the current blog's 'public' setting is updated.
1270 *
1271 * @since MU (3.0.0)
1272 *
1273 * @param int $site_id Site ID.
1274 * @param string $is_public Whether the site is public. A numeric string,
1275 * for compatibility reasons. Accepts '1' or '0'.
1276 */
1277 do_action( 'update_blog_public', $site_id, $new_site->public );
1278 }
1279}
1280
1281/**
1282 * Cleans the necessary caches after specific site data has been updated.
1283 *
1284 * @since 5.1.0
1285 *
1286 * @param WP_Site $new_site The site object after the update.
1287 * @param WP_Site $old_site The site object prior to the update.
1288 */
1289function wp_maybe_clean_new_site_cache_on_update( $new_site, $old_site ) {
1290 if ( $old_site->domain !== $new_site->domain || $old_site->path !== $new_site->path ) {
1291 clean_blog_cache( $new_site );
1292 }
1293}
1294
1295/**
1296 * Updates the `blog_public` option for a given site ID.
1297 *
1298 * @since 5.1.0
1299 *
1300 * @param int $site_id Site ID.
1301 * @param string $is_public Whether the site is public. A numeric string,
1302 * for compatibility reasons. Accepts '1' or '0'.
1303 */
1304function wp_update_blog_public_option_on_site_update( $site_id, $is_public ) {
1305
1306 // Bail if the site's database tables do not exist (yet).
1307 if ( ! wp_is_site_initialized( $site_id ) ) {
1308 return;
1309 }
1310
1311 update_blog_option( $site_id, 'blog_public', $is_public );
1312}
1313
1314/**
1315 * Sets the last changed time for the 'sites' cache group.
1316 *
1317 * @since 5.1.0
1318 */
1319function wp_cache_set_sites_last_changed() {
1320 wp_cache_set_last_changed( 'sites' );
1321}
1322
1323/**
1324 * Aborts calls to site meta if it is not supported.
1325 *
1326 * @since 5.1.0
1327 *
1328 * @global wpdb $wpdb WordPress database abstraction object.
1329 *
1330 * @param mixed $check Skip-value for whether to proceed site meta function execution.
1331 * @return mixed Original value of $check, or false if site meta is not supported.
1332 */
1333function wp_check_site_meta_support_prefilter( $check ) {
1334 if ( ! is_site_meta_supported() ) {
1335 /* translators: %s: Database table name. */
1336 _doing_it_wrong( __FUNCTION__, sprintf( __( 'The %s table is not installed. Please run the network database upgrade.' ), $GLOBALS['wpdb']->blogmeta ), '5.1.0' );
1337 return false;
1338 }
1339
1340 return $check;
1341}
1342