1<?php
2/**
3 * Site API: WP_Site class
4 *
5 * @package WordPress
6 * @subpackage Multisite
7 * @since 4.5.0
8 */
9
10/**
11 * Core class used for interacting with a multisite site.
12 *
13 * This class is used during load to populate the `$current_blog` global and
14 * setup the current site.
15 *
16 * @since 4.5.0
17 *
18 * @property int $id
19 * @property int $network_id
20 * @property string $blogname
21 * @property string $siteurl
22 * @property int $post_count
23 * @property string $home
24 */
25#[AllowDynamicProperties]
26final class WP_Site {
27
28 /**
29 * Site ID.
30 *
31 * Named "blog" vs. "site" for legacy reasons.
32 *
33 * A numeric string, for compatibility reasons.
34 *
35 * @since 4.5.0
36 * @var string
37 */
38 public $blog_id;
39
40 /**
41 * Domain of the site.
42 *
43 * @since 4.5.0
44 * @var string
45 */
46 public $domain = '';
47
48 /**
49 * Path of the site.
50 *
51 * @since 4.5.0
52 * @var string
53 */
54 public $path = '';
55
56 /**
57 * The ID of the site's parent network.
58 *
59 * Named "site" vs. "network" for legacy reasons. An individual site's "site" is
60 * its network.
61 *
62 * A numeric string, for compatibility reasons.
63 *
64 * @since 4.5.0
65 * @var string
66 */
67 public $site_id = '0';
68
69 /**
70 * The date and time on which the site was created or registered.
71 *
72 * @since 4.5.0
73 * @var string Date in MySQL's datetime format.
74 */
75 public $registered = '0000-00-00 00:00:00';
76
77 /**
78 * The date and time on which site settings were last updated.
79 *
80 * @since 4.5.0
81 * @var string Date in MySQL's datetime format.
82 */
83 public $last_updated = '0000-00-00 00:00:00';
84
85 /**
86 * Whether the site should be treated as public.
87 *
88 * A numeric string, for compatibility reasons.
89 *
90 * @since 4.5.0
91 * @var string
92 */
93 public $public = '1';
94
95 /**
96 * Whether the site should be treated as archived.
97 *
98 * A numeric string, for compatibility reasons.
99 *
100 * @since 4.5.0
101 * @var string
102 */
103 public $archived = '0';
104
105 /**
106 * Whether the site should be treated as mature.
107 *
108 * Handling for this does not exist throughout WordPress core, but custom
109 * implementations exist that require the property to be present.
110 *
111 * A numeric string, for compatibility reasons.
112 *
113 * @since 4.5.0
114 * @var string
115 */
116 public $mature = '0';
117
118 /**
119 * Whether the site should be treated as spam.
120 *
121 * A numeric string, for compatibility reasons.
122 *
123 * @since 4.5.0
124 * @var string
125 */
126 public $spam = '0';
127
128 /**
129 * Whether the site should be treated as flagged for deletion.
130 *
131 * A numeric string, for compatibility reasons.
132 *
133 * @since 4.5.0
134 * @var string
135 */
136 public $deleted = '0';
137
138 /**
139 * The language pack associated with this site.
140 *
141 * A numeric string, for compatibility reasons.
142 *
143 * @since 4.5.0
144 * @var string
145 */
146 public $lang_id = '0';
147
148 /**
149 * Retrieves a site from the database by its ID.
150 *
151 * @since 4.5.0
152 *
153 * @global wpdb $wpdb WordPress database abstraction object.
154 *
155 * @param int $site_id The ID of the site to retrieve.
156 * @return WP_Site|false The site's object if found. False if not.
157 */
158 public static function get_instance( $site_id ) {
159 global $wpdb;
160
161 $site_id = (int) $site_id;
162 if ( ! $site_id ) {
163 return false;
164 }
165
166 $_site = wp_cache_get( $site_id, 'sites' );
167
168 if ( false === $_site ) {
169 $_site = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->blogs} WHERE blog_id = %d LIMIT 1", $site_id ) );
170
171 if ( empty( $_site ) || is_wp_error( $_site ) ) {
172 $_site = -1;
173 }
174
175 wp_cache_add( $site_id, $_site, 'sites' );
176 }
177
178 if ( is_numeric( $_site ) ) {
179 return false;
180 }
181
182 return new WP_Site( $_site );
183 }
184
185 /**
186 * Creates a new WP_Site object.
187 *
188 * Will populate object properties from the object provided and assign other
189 * default properties based on that information.
190 *
191 * @since 4.5.0
192 *
193 * @param WP_Site|object $site A site object.
194 */
195 public function __construct( $site ) {
196 foreach ( get_object_vars( $site ) as $key => $value ) {
197 $this->$key = $value;
198 }
199 }
200
201 /**
202 * Converts an object to array.
203 *
204 * @since 4.6.0
205 *
206 * @return array Object as array.
207 */
208 public function to_array() {
209 return get_object_vars( $this );
210 }
211
212 /**
213 * Getter.
214 *
215 * Allows current multisite naming conventions when getting properties.
216 * Allows access to extended site properties.
217 *
218 * @since 4.6.0
219 *
220 * @param string $key Property to get.
221 * @return mixed Value of the property. Null if not available.
222 */
223 public function __get( $key ) {
224 switch ( $key ) {
225 case 'id':
226 return (int) $this->blog_id;
227 case 'network_id':
228 return (int) $this->site_id;
229 case 'blogname':
230 case 'siteurl':
231 case 'post_count':
232 case 'home':
233 default: // Custom properties added by 'site_details' filter.
234 if ( ! did_action( 'ms_loaded' ) ) {
235 return null;
236 }
237
238 $details = $this->get_details();
239 if ( isset( $details->$key ) ) {
240 return $details->$key;
241 }
242 }
243
244 return null;
245 }
246
247 /**
248 * Isset-er.
249 *
250 * Allows current multisite naming conventions when checking for properties.
251 * Checks for extended site properties.
252 *
253 * @since 4.6.0
254 *
255 * @param string $key Property to check if set.
256 * @return bool Whether the property is set.
257 */
258 public function __isset( $key ) {
259 switch ( $key ) {
260 case 'id':
261 case 'network_id':
262 return true;
263 case 'blogname':
264 case 'siteurl':
265 case 'post_count':
266 case 'home':
267 if ( ! did_action( 'ms_loaded' ) ) {
268 return false;
269 }
270 return true;
271 default: // Custom properties added by 'site_details' filter.
272 if ( ! did_action( 'ms_loaded' ) ) {
273 return false;
274 }
275
276 $details = $this->get_details();
277 if ( isset( $details->$key ) ) {
278 return true;
279 }
280 }
281
282 return false;
283 }
284
285 /**
286 * Setter.
287 *
288 * Allows current multisite naming conventions while setting properties.
289 *
290 * @since 4.6.0
291 *
292 * @param string $key Property to set.
293 * @param mixed $value Value to assign to the property.
294 */
295 public function __set( $key, $value ) {
296 switch ( $key ) {
297 case 'id':
298 $this->blog_id = (string) $value;
299 break;
300 case 'network_id':
301 $this->site_id = (string) $value;
302 break;
303 default:
304 $this->$key = $value;
305 }
306 }
307
308 /**
309 * Retrieves the details for this site.
310 *
311 * This method is used internally to lazy-load the extended properties of a site.
312 *
313 * @since 4.6.0
314 *
315 * @see WP_Site::__get()
316 *
317 * @return stdClass A raw site object with all details included.
318 */
319 private function get_details() {
320 $details = wp_cache_get( $this->blog_id, 'site-details' );
321
322 if ( false === $details ) {
323
324 switch_to_blog( $this->blog_id );
325 // Create a raw copy of the object for backward compatibility with the filter below.
326 $details = new stdClass();
327 foreach ( get_object_vars( $this ) as $key => $value ) {
328 $details->$key = $value;
329 }
330 $details->blogname = get_option( 'blogname' );
331 $details->siteurl = get_option( 'siteurl' );
332 $details->post_count = get_option( 'post_count' );
333 $details->home = get_option( 'home' );
334 restore_current_blog();
335
336 wp_cache_set( $this->blog_id, $details, 'site-details' );
337 }
338
339 /** This filter is documented in wp-includes/ms-blogs.php */
340 $details = apply_filters_deprecated( 'blog_details', array( $details ), '4.7.0', 'site_details' );
341
342 /**
343 * Filters a site's extended properties.
344 *
345 * @since 4.6.0
346 *
347 * @param stdClass $details The site details.
348 */
349 $details = apply_filters( 'site_details', $details );
350
351 return $details;
352 }
353}
354