Completed
Push — master-stable ( 53f101...a82972 )
by
unknown
86:26 queued 76:28
created

WPCOM_JSON_API_GET_Site_Endpoint::callback()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 26
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 12
nc 5
nop 2
dl 0
loc 26
rs 8.439
c 0
b 0
f 0
1
<?php
2
class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint {
3
4
	public static $site_format = array(
5
		'ID'                => '(int) Site ID',
6
		'name'              => '(string) Title of site',
7
		'description'       => '(string) Tagline or description of site',
8
		'URL'               => '(string) Full URL to the site',
9
		'user_can_manage'   => '(bool) The current user can manage this site', // deprecated
10
		'capabilities'      => '(array) Array of capabilities for the current user on this site.',
11
		'jetpack'           => '(bool)  Whether the site is a Jetpack site or not',
12
		'is_multisite'      => '(bool) Whether the site is a Multisite site or not. Always true for WP.com sites.',
13
		'post_count'        => '(int) The number of posts the site has',
14
		'subscribers_count' => '(int) The number of subscribers the site has',
15
		'lang'              => '(string) Primary language code of the site',
16
		'icon'              => '(array) An array of icon formats for the site',
17
		'logo'              => '(array) The site logo, set in the Customizer',
18
		'visible'           => '(bool) If this site is visible in the user\'s site list',
19
		'is_private'        => '(bool) If the site is a private site or not',
20
		'single_user_site'  => '(bool) Whether the site is single user. Only returned for WP.com sites and for Jetpack sites with version 3.4 or higher.',
21
		'is_vip'            => '(bool) If the site is a VIP site or not.',
22
		'is_following'      => '(bool) If the current user is subscribed to this site in the reader',
23
		'options'           => '(array) An array of options/settings for the blog. Only viewable by users with post editing rights to the site. Note: Post formats is deprecated, please see /sites/$id/post-formats/',
24
		'plan'              => '(array) Details of the current plan for this site.',
25
		'updates'           => '(array) An array of available updates for plugins, themes, wordpress, and languages.',
26
		'jetpack_modules'   => '(array) A list of active Jetpack modules.',
27
		'meta'              => '(object) Meta data',
28
		'quota'             => '(array) An array describing how much space a user has left for uploads',
29
	);
30
31
	protected static $no_member_fields = array(
32
		'ID',
33
		'name',
34
		'description',
35
		'URL',
36
		'jetpack',
37
		'post_count',
38
		'subscribers_count',
39
		'lang',
40
		'locale',
41
		'icon',
42
		'logo',
43
		'visible',
44
		'is_private',
45
		'is_following',
46
		'meta',
47
	);
48
49
	protected static $site_options_format = array(
50
		'timezone',
51
		'gmt_offset',
52
		'videopress_enabled',
53
		'upgraded_filetypes_enabled',
54
		'login_url',
55
		'admin_url',
56
		'is_mapped_domain',
57
		'is_redirect',
58
		'unmapped_url',
59
		'featured_images_enabled',
60
		'theme_slug',
61
		'header_image',
62
		'background_color',
63
		'image_default_link_type',
64
		'image_thumbnail_width',
65
		'image_thumbnail_height',
66
		'image_thumbnail_crop',
67
		'image_medium_width',
68
		'image_medium_height',
69
		'image_large_width',
70
		'image_large_height',
71
		'permalink_structure',
72
		'post_formats',
73
		'default_post_format',
74
		'default_category',
75
		'allowed_file_types',
76
		'show_on_front',
77
		/** This filter is documented in modules/likes.php */
78
		'default_likes_enabled',
79
		'default_sharing_status',
80
		'default_comment_status',
81
		'default_ping_status',
82
		'software_version',
83
		'created_at',
84
		'wordads',
85
		'publicize_permanently_disabled',
86
		'frame_nonce',
87
		'page_on_front',
88
		'page_for_posts',
89
		'headstart',
90
		'headstart_is_fresh',
91
		'ak_vp_bundle_enabled',
92
		Jetpack_SEO_Utils::FRONT_PAGE_META_OPTION,
93
		Jetpack_SEO_Titles::TITLE_FORMATS_OPTION,
94
		'verification_services_codes',
95
		'podcasting_archive',
96
		'is_domain_only',
97
		'is_automated_transfer',
98
	);
99
100
	protected static $jetpack_response_field_additions = array(
101
		'subscribers_count',
102
	);
103
104
	protected static $jetpack_response_field_member_additions = array(
105
		'capabilities',
106
		'plan',
107
	);
108
109
	protected static $jetpack_response_option_additions = array(
110
		'publicize_permanently_disabled',
111
		'ak_vp_bundle_enabled',
112
		'is_automated_transfer',
113
		'frame_nonce'
114
	);
115
116
	private $site;
117
118
	// protected $compact = null;
119
	protected $fields_to_include = '_all';
120
	protected $options_to_include = '_all';
121
122
	// /sites/mine
123
	// /sites/%s -> $blog_id
124
	function callback( $path = '', $blog_id = 0 ) {
125
		if ( 'mine' === $blog_id ) {
0 ignored issues
show
Unused Code Bug introduced by
The strict comparison === seems to always evaluate to false as the types of 'mine' (string) and $blog_id (integer) can never be identical. Maybe you want to use a loose comparison == instead?
Loading history...
126
			$api = WPCOM_JSON_API::init();
127
			if ( ! $api->token_details || empty( $api->token_details['blog_id'] ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $api->token_details of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
128
				return new WP_Error( 'authorization_required', 'An active access token must be used to query information about the current blog.', 403 );
129
			}
130
			$blog_id = $api->token_details['blog_id'];
131
		}
132
133
		$blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) );
134
		if ( is_wp_error( $blog_id ) ) {
135
			return $blog_id;
136
		}
137
138
		// TODO: enable this when we can do so without being interfered with by
0 ignored issues
show
Coding Style Best Practice introduced by
Comments for TODO tasks are often forgotten in the code; it might be better to use a dedicated issue tracker.
Loading history...
139
		// other endpoints that might be wrapping this one.
140
		// Uncomment and see failing test: test_jetpack_site_should_have_true_jetpack_property_via_site_meta
141
		// $this->filter_fields_and_options();
142
143
		$response = $this->build_current_site_response();
144
145
		/** This action is documented in json-endpoints/class.wpcom-json-api-site-settings-endpoint.php */
146
		do_action( 'wpcom_json_api_objects', 'sites' );
147
148
		return $response;
149
	}
150
151
	public function filter_fields_and_options() {
152
		$query_args = $this->query_args();
153
154
		$this->fields_to_include  = empty( $query_args['fields'] ) ? '_all' : array_map( 'trim', explode( ',', $query_args['fields'] ) );
0 ignored issues
show
Documentation Bug introduced by
It seems like empty($query_args['field...$query_args['fields'])) can also be of type array. However, the property $fields_to_include is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
155
		$this->options_to_include = empty( $query_args['options'] ) ? '_all' : array_map( 'trim', explode( ',', $query_args['options'] ) );
0 ignored issues
show
Documentation Bug introduced by
It seems like empty($query_args['optio...query_args['options'])) can also be of type array. However, the property $options_to_include is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
156
	}
157
158
	/**
159
	 * Collects the necessary information to return for a site's response.
160
	 *
161
	 * @return (array)
162
	 */
163
	public function build_current_site_response() {
164
165
		$blog_id = (int) $this->api->get_blog_id_for_output();
166
167
		$this->site = $this->get_platform()->get_site( $blog_id );
168
169
		/**
170
 		 * Filter the structure of information about the site to return.
171
 		 *
172
 		 * @module json-api
173
 		 *
174
 		 * @since 3.9.3
175
 		 *
176
 		 * @param array $site_format Data structure.
177
 		 */
178
		$default_fields = array_keys( apply_filters( 'sites_site_format', self::$site_format ) );
179
180
		$response_keys = is_array( $this->fields_to_include ) ?
181
			array_intersect( $default_fields, $this->fields_to_include ) :
182
			$default_fields;
183
184
		if ( ! $this->has_blog_access( $this->api->token_details, $blog_id ) ) {
185
			$response_keys = array_intersect( $response_keys, self::$no_member_fields );
186
		}
187
188
		return $this->render_response_keys( $response_keys );
189
	}
190
191
	private function has_blog_access( $token_details, $blog_id ) {
192
		if ( is_user_member_of_blog( get_current_user_id(), $blog_id ) ) {
193
			return true;
194
		}
195
196
		$token_details = (array) $token_details;
197
		if ( ! isset( $token_details['access'], $token_details['auth'], $token_details['blog_id'] ) ) {
198
			return false;
199
		}
200
201
		if (
202
			'jetpack' === $token_details['auth'] &&
203
			'blog' === $token_details['access'] &&
204
			$blog_id === $token_details['blog_id']
205
		) {
206
			return true;
207
		}
208
		return false;
209
	}
210
211
	private function render_response_keys( &$response_keys ) {
212
		$response = array();
213
214
		$is_user_logged_in = is_user_logged_in();
215
216
		$this->site->before_render();
217
218
		foreach ( $response_keys as $key ) {
219
			$this->render_response_key( $key, $response, $is_user_logged_in );
220
		}
221
222
		$this->site->after_render( $response );
223
224
		return $response;
225
	}
226
227
	protected function render_response_key( $key, &$response, $is_user_logged_in ) {
228
		do_action( 'pre_render_site_response_key', $key );
229
230
		switch ( $key ) {
231
			case 'ID' :
232
				$response[ $key ] = $this->site->blog_id;
233
				break;
234
			case 'name' :
235
				$response[ $key ] = $this->site->get_name();
236
				break;
237
			case 'description' :
238
				$response[ $key ] = $this->site->get_description();
239
				break;
240
			case 'URL' :
241
				$response[ $key ] = $this->site->get_url();
242
				break;
243
			case 'user_can_manage' :
0 ignored issues
show
Coding Style introduced by
There must be a comment when fall-through is intentional in a non-empty case body
Loading history...
244
				$response[ $key ] = $this->site->user_can_manage();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $response[$key] is correct as $this->site->user_can_manage() (which targets SAL_Site::user_can_manage()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
245
			case 'is_private' :
246
				$response[ $key ] = $this->site->is_private();
247
				break;
248
			case 'visible' :
249
				$response[ $key ] = $this->site->is_visible();
250
				break;
251
			case 'subscribers_count' :
252
				$response[ $key ] = $this->site->get_subscribers_count();
253
				break;
254
			case 'post_count' :
255
				if ( $is_user_logged_in ) {
256
					$response[ $key ] = $this->site->get_post_count();
257
				}
258
				break;
259
			case 'icon' :
260
				$icon = $this->site->get_icon();
261
262
				if ( ! is_null( $icon ) ) {
263
					$response[ $key ] = $icon;
264
				}
265
				break;
266
			case 'logo' :
267
				$response[ $key ] = $this->site->get_logo();
268
				break;
269
			case 'is_following':
270
				$response[ $key ] = $this->site->is_following();
271
				break;
272
			case 'options':
273
				// small optimisation - don't recalculate
274
				$all_options = apply_filters( 'sites_site_options_format', self::$site_options_format );
275
276
				$options_response_keys = is_array( $this->options_to_include ) ?
277
					array_intersect( $all_options, $this->options_to_include ) :
278
					$all_options;
279
280
				$options = $this->render_option_keys( $options_response_keys );
281
282
				$this->site->after_render_options( $options );
283
284
				$response[ $key ] = (object) $options;
285
				break;
286
			case 'meta':
287
				$this->build_meta_response( $response );
288
				break;
289
			case 'lang' :
290
				$response[ $key ] = $is_user_logged_in ? $this->site->get_locale() : false;
291
				break;
292
			case 'locale' :
293
				$response[ $key ] = $is_user_logged_in ? $this->site->get_locale() : false;
294
				break;
295
			case 'jetpack' :
296
				$response[ $key ] = $this->site->is_jetpack();
297
				break;
298
			case 'single_user_site' :
299
				$response[ $key ] = $this->site->is_single_user_site();
300
				break;
301
			case 'is_vip' :
302
				$response[ $key ] = $this->site->is_vip();
303
				break;
304
			case 'is_multisite' :
305
				$response[ $key ] = $this->site->is_multisite();
306
				break;
307
			case 'capabilities' :
308
				$response[ $key ] = $this->site->get_capabilities();
309
				break;
310
			case 'jetpack_modules':
311
				$jetpack_modules = $this->site->get_jetpack_modules();
312
				if ( ! is_null( $jetpack_modules ) ) {
313
					$response[ $key ] = $jetpack_modules;
314
				}
315
				break;
316
			case 'plan' :
317
				$response[ $key ] = $this->site->get_plan();
318
				break;
319
			case 'quota' :
320
				$response[ $key ] = $this->site->get_quota();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $response[$key] is correct as $this->site->get_quota() (which targets SAL_Site::get_quota()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
321
				break;
322
		}
323
324
		do_action( 'post_render_site_response_key', $key );
325
	}
326
327
	protected function render_option_keys( &$options_response_keys ) {
328
		if ( ! current_user_can( 'edit_posts' ) ) {
329
			return array();
330
		}
331
332
		$options = array();
333
		$site = $this->site;
334
335
		$custom_front_page = $site->is_custom_front_page();
336
337
		foreach ( $options_response_keys as $key ) {
338
			switch ( $key ) {
339
				case 'timezone' :
340
					$options[ $key ] = $site->get_timezone();
341
					break;
342
				case 'gmt_offset' :
343
					$options[ $key ] = $site->get_gmt_offset();
344
					break;
345
				case 'videopress_enabled' :
346
					$options[ $key ] = $site->has_videopress();
347
					break;
348
				case 'upgraded_filetypes_enabled' :
349
					$options[ $key ] = $site->upgraded_filetypes_enabled();
350
					break;
351
				case 'login_url' :
352
					$options[ $key ] = $site->get_login_url();
353
					break;
354
				case 'admin_url' :
355
					$options[ $key ] = $site->get_admin_url();
356
					break;
357
				case 'is_mapped_domain' :
358
					$options[ $key ] = $site->is_mapped_domain();
359
					break;
360
				case 'is_redirect' :
361
					$options[ $key ] = $site->is_redirect();
362
					break;
363
				case 'unmapped_url' :
364
					$options[ $key ] = $site->get_unmapped_url();
365
					break;
366
				case 'featured_images_enabled' :
367
					$options[ $key ] = $site->featured_images_enabled();
368
					break;
369
				case 'theme_slug' :
370
					$options[ $key ] = $site->get_theme_slug();
371
					break;
372
				case 'header_image' :
373
					$options[ $key ] = $site->get_header_image();
374
					break;
375
				case 'background_color' :
376
					$options[ $key ] = $site->get_background_color();
377
					break;
378
				case 'image_default_link_type' :
379
					$options[ $key ] = $site->get_image_default_link_type();
380
					break;
381
				case 'image_thumbnail_width' :
382
					$options[ $key ] = $site->get_image_thumbnail_width();
383
					break;
384
				case 'image_thumbnail_height' :
385
					$options[ $key ] = $site->get_image_thumbnail_height();
386
					break;
387
				case 'image_thumbnail_crop' :
388
					$options[ $key ] = $site->get_image_thumbnail_crop();
389
					break;
390
				case 'image_medium_width' :
391
					$options[ $key ] = $site->get_image_medium_width();
392
					break;
393
				case 'image_medium_height' :
394
					$options[ $key ] = $site->get_image_medium_height();
395
					break;
396
				case 'image_large_width' :
397
					$options[ $key ] = $site->get_image_large_width();
398
					break;
399
				case 'image_large_height' :
400
					$options[ $key ] = $site->get_image_large_height();
401
					break;
402
				case 'permalink_structure' :
403
					$options[ $key ] = $site->get_permalink_structure();
404
					break;
405
				case 'post_formats' :
406
					$options[ $key ] = $site->get_post_formats();
407
					break;
408
				case 'default_post_format' :
409
					$options[ $key ] = $site->get_default_post_format();
410
					break;
411
				case 'default_category' :
412
					$options[ $key ] = $site->get_default_category();
413
					break;
414
				case 'allowed_file_types' :
415
					$options[ $key ] = $site->allowed_file_types();
416
					break;
417
				case 'show_on_front' :
418
					$options[ $key ] = $site->get_show_on_front();
419
					break;
420
				/** This filter is documented in modules/likes.php */
421
				case 'default_likes_enabled' :
422
					$options[ $key ] = $site->get_default_likes_enabled();
423
					break;
424
				case 'default_sharing_status' :
425
					$options[ $key ] = $site->get_default_sharing_status();
426
					break;
427
				case 'default_comment_status' :
428
					$options[ $key ] = $site->get_default_comment_status();
429
					break;
430
				case 'default_ping_status' :
431
					$options[ $key ] = $site->default_ping_status();
432
					break;
433
				case 'software_version' :
434
					$options[ $key ] = $site->get_wordpress_version();
435
					break;
436
				case 'created_at' :
437
					$options[ $key ] = $site->get_registered_date();
438
					break;
439
				case 'wordads' :
440
					$options[ $key ] = $site->has_wordads();
441
					break;
442
				case 'publicize_permanently_disabled' :
443
					$options[ $key ] = $site->is_publicize_permanently_disabled();
444
					break;
445
				case 'frame_nonce' :
446
					$options[ $key ] = $site->get_frame_nonce();
447
					break;
448
				case 'page_on_front' :
449
					if ( $custom_front_page ) {
450
						$options[ $key ] = $site->get_page_on_front();
451
					}
452
					break;
453
				case 'page_for_posts' :
454
					if ( $custom_front_page ) {
455
						$options[ $key ] = $site->get_page_for_posts();
456
					}
457
					break;
458
				case 'headstart' :
459
					$options[ $key ] = $site->is_headstart();
460
					break;
461
				case 'headstart_is_fresh' :
462
					$options[ $key ] = $site->is_headstart_fresh();
463
					break;
464
				case 'ak_vp_bundle_enabled' :
465
					$options[ $key ] = $site->get_ak_vp_bundle_enabled();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $options[$key] is correct as $site->get_ak_vp_bundle_enabled() (which targets Jetpack_Site::get_ak_vp_bundle_enabled()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
466
					break;
467
				case Jetpack_SEO_Utils::FRONT_PAGE_META_OPTION :
468
					$options[ $key ] = $site->get_jetpack_seo_front_page_description();
469
					break;
470
				case Jetpack_SEO_Titles::TITLE_FORMATS_OPTION :
471
					$options[ $key ] = $site->get_jetpack_seo_title_formats();
472
					break;
473
				case 'verification_services_codes' :
474
					$options[ $key ] = $site->get_verification_services_codes();
475
					break;
476
				case 'podcasting_archive':
477
					$options[ $key ] = $site->get_podcasting_archive();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $options[$key] is correct as $site->get_podcasting_archive() (which targets Jetpack_Site::get_podcasting_archive()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
478
					break;
479
				case 'is_domain_only':
480
					$options[ $key ] = $site->is_domain_only();
481
					break;
482
				case 'is_automated_transfer':
483
					$options[ $key ] = $site->is_automated_transfer();
484
					break;
485
			}
486
		}
487
488
		return $options;
489
	}
490
491
	protected function build_meta_response( &$response ) {
492
		$links = array(
493
			'self'     => (string) $this->links->get_site_link( $this->site->blog_id ),
494
			'help'     => (string) $this->links->get_site_link( $this->site->blog_id, 'help'      ),
495
			'posts'    => (string) $this->links->get_site_link( $this->site->blog_id, 'posts/'    ),
496
			'comments' => (string) $this->links->get_site_link( $this->site->blog_id, 'comments/' ),
497
			'xmlrpc'   => (string) $this->site->get_xmlrpc_url(),
498
		);
499
500
		$icon = $this->site->get_icon();
501
		if ( ! empty( $icon ) && ! empty( $icon['media_id'] ) ) {
502
			$links['site_icon'] = (string) $this->links->get_site_link( $this->site->blog_id, 'media/' . $icon['media_id'] );
503
		}
504
505
		$response['meta'] = (object) array(
506
			'links' => (object) $links
507
		);
508
	}
509
510
	// apply any WPCOM-only response components to a Jetpack site response
511
	public function decorate_jetpack_response( &$response ) {
512
		$this->site = $this->get_platform()->get_site( $response->ID );
513
		switch_to_blog( $this->site->get_id() );
514
515
		// ensure the response is marked as being from Jetpack
516
		$response->jetpack = true;
517
518
		$wpcom_response = $this->render_response_keys( self::$jetpack_response_field_additions );
519
520
		foreach( $wpcom_response as $key => $value ) {
521
			$response->{ $key } = $value;
522
		}
523
524
		if ( $this->has_blog_access( $this->api->token_details, $response->ID ) ) {
525
			$wpcom_member_response = $this->render_response_keys( self::$jetpack_response_field_member_additions );
526
527
			foreach( $wpcom_member_response as $key => $value ) {
528
				$response->{ $key } = $value;
529
			}
530
		} else {
531
			// ensure private data is not rendered for non members of the site
532
			unset( $response->options );
533
			unset( $response->is_vip );
534
			unset( $response->single_user_site );
535
			unset( $response->is_private );
536
			unset( $response->capabilities );
537
			unset( $response->lang );
538
			unset( $response->user_can_manage );
539
			unset( $response->is_multisite );
540
			unset( $response->plan );
541
		}
542
543
		// render additional options
544
		if ( $response->options ) {
545
			$wpcom_options_response = $this->render_option_keys( self::$jetpack_response_option_additions );
546
547
			foreach ( $wpcom_options_response as $key => $value ) {
548
				$response->options[ $key ] = $value;
549
			}
550
		}
551
552
		restore_current_blog();
553
		return $response; // possibly no need since it's modified in place
554
	}
555
}
556
557
class WPCOM_JSON_API_List_Post_Formats_Endpoint extends WPCOM_JSON_API_Endpoint {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
558
	// /sites/%s/post-formats -> $blog_id
559
	function callback( $path = '', $blog_id = 0 ) {
560
		$blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) );
561
		if ( is_wp_error( $blog_id ) ) {
562
			return $blog_id;
563
		}
564
565
		if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
566
			$this->load_theme_functions();
567
		}
568
569
		// Get a list of supported post formats.
570
		$all_formats = get_post_format_strings();
571
		$supported   = get_theme_support( 'post-formats' );
572
573
		$supported_formats = $response['formats'] = array();
0 ignored issues
show
Coding Style Comprehensibility introduced by
$response was never initialized. Although not strictly required by PHP, it is generally a good practice to add $response = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
574
575 View Code Duplication
		if ( isset( $supported[0] ) ) {
576
			foreach ( $supported[0] as $format ) {
577
				$supported_formats[ $format ] = $all_formats[ $format ];
578
			}
579
		}
580
581
		$response['formats'] = (object) $supported_formats;
582
583
		return $response;
584
	}
585
}
586
587
class WPCOM_JSON_API_List_Page_Templates_Endpoint extends WPCOM_JSON_API_Endpoint {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
588
	// /sites/%s/page-templates -> $blog_id
589
	function callback( $path = '', $blog_id = 0 ) {
590
		$blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) );
591
		if ( is_wp_error( $blog_id ) ) {
592
			return $blog_id;
593
		}
594
595
		if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
596
			$this->load_theme_functions();
597
		}
598
599
		$response = array();
600
		$page_templates = array();
601
602
		$templates = get_page_templates();
603
		ksort( $templates );
604
605
		foreach ( array_keys( $templates ) as $label ) {
606
			$page_templates[] = array(
607
				'label' => $label,
608
				'file'  => $templates[ $label ]
609
			);
610
		}
611
612
		$response['templates'] = $page_templates;
613
614
		return $response;
615
	}
616
}
617