Completed
Push — sync/json-endpoints-19apr2017 ( 4d1744 )
by
unknown
64:46 queued 53:25
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
3
class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint {
4
5
	public static $site_format = array(
6
		'ID'                => '(int) Site ID',
7
		'name'              => '(string) Title of site',
8
		'description'       => '(string) Tagline or description of site',
9
		'URL'               => '(string) Full URL to the site',
10
		'user_can_manage'   => '(bool) The current user can manage this site', // deprecated
11
		'capabilities'      => '(array) Array of capabilities for the current user on this site.',
12
		'jetpack'           => '(bool)  Whether the site is a Jetpack site or not',
13
		'is_multisite'      => '(bool) Whether the site is a Multisite site or not. Always true for WP.com sites.',
14
		'post_count'        => '(int) The number of posts the site has',
15
		'subscribers_count' => '(int) The number of subscribers the site has',
16
		'lang'              => '(string) Primary language code of the site',
17
		'icon'              => '(array) An array of icon formats for the site',
18
		'logo'              => '(array) The site logo, set in the Customizer',
19
		'visible'           => '(bool) If this site is visible in the user\'s site list',
20
		'is_private'        => '(bool) If the site is a private site or not',
21
		'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.',
22
		'is_vip'            => '(bool) If the site is a VIP site or not.',
23
		'is_following'      => '(bool) If the current user is subscribed to this site in the reader',
24
		'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/',
25
		'plan'              => '(array) Details of the current plan for this site.',
26
		'updates'           => '(array) An array of available updates for plugins, themes, wordpress, and languages.',
27
		'jetpack_modules'   => '(array) A list of active Jetpack modules.',
28
		'meta'              => '(object) Meta data',
29
		'quota'             => '(array) An array describing how much space a user has left for uploads',
30
	);
31
32
	protected static $no_member_fields = array(
33
		'ID',
34
		'name',
35
		'description',
36
		'URL',
37
		'jetpack',
38
		'post_count',
39
		'subscribers_count',
40
		'lang',
41
		'locale',
42
		'icon',
43
		'logo',
44
		'visible',
45
		'is_private',
46
		'is_following',
47
		'meta',
48
	);
49
50
	protected static $site_options_format = array(
51
		'timezone',
52
		'gmt_offset',
53
		'videopress_enabled',
54
		'upgraded_filetypes_enabled',
55
		'login_url',
56
		'admin_url',
57
		'is_mapped_domain',
58
		'is_redirect',
59
		'unmapped_url',
60
		'featured_images_enabled',
61
		'theme_slug',
62
		'header_image',
63
		'background_color',
64
		'image_default_link_type',
65
		'image_thumbnail_width',
66
		'image_thumbnail_height',
67
		'image_thumbnail_crop',
68
		'image_medium_width',
69
		'image_medium_height',
70
		'image_large_width',
71
		'image_large_height',
72
		'permalink_structure',
73
		'post_formats',
74
		'default_post_format',
75
		'default_category',
76
		'allowed_file_types',
77
		'show_on_front',
78
		/** This filter is documented in modules/likes.php */
79
		'default_likes_enabled',
80
		'default_sharing_status',
81
		'default_comment_status',
82
		'default_ping_status',
83
		'software_version',
84
		'created_at',
85
		'wordads',
86
		'publicize_permanently_disabled',
87
		'frame_nonce',
88
		'page_on_front',
89
		'page_for_posts',
90
		'headstart',
91
		'headstart_is_fresh',
92
		'ak_vp_bundle_enabled',
93
		Jetpack_SEO_Utils::FRONT_PAGE_META_OPTION,
94
		Jetpack_SEO_Titles::TITLE_FORMATS_OPTION,
95
		'verification_services_codes',
96
		'podcasting_archive',
97
		'is_domain_only',
98
		'is_automated_transfer',
99
	);
100
101
	protected static $jetpack_response_field_additions = array( 
102
		'subscribers_count',
103
	);
104
105
	protected static $jetpack_response_field_member_additions = array(
106
		'capabilities',
107
		'plan',
108
	);
109
110
	protected static $jetpack_response_option_additions = array( 
111
		'publicize_permanently_disabled',
112
		'ak_vp_bundle_enabled',
113
		'is_automated_transfer',
114
		'frame_nonce'
115
	);
116
117
	private $site;
118
119
	// protected $compact = null;
120
	protected $fields_to_include = '_all';
121
	protected $options_to_include = '_all';
122
123
	// /sites/mine
124
	// /sites/%s -> $blog_id
125
	function callback( $path = '', $blog_id = 0 ) {
126
		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...
127
			$api = WPCOM_JSON_API::init();
128
			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...
129
				return new WP_Error( 'authorization_required', 'An active access token must be used to query information about the current blog.', 403 );
130
			}
131
			$blog_id = $api->token_details['blog_id'];
132
		}
133
134
		$blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) );
135
		if ( is_wp_error( $blog_id ) ) {
136
			return $blog_id;
137
		}
138
139
		// 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...
140
		// other endpoints that might be wrapping this one.
141
		// Uncomment and see failing test: test_jetpack_site_should_have_true_jetpack_property_via_site_meta
142
		// $this->filter_fields_and_options();
143
144
		$response = $this->build_current_site_response();
145
146
		/** This action is documented in json-endpoints/class.wpcom-json-api-site-settings-endpoint.php */
147
		do_action( 'wpcom_json_api_objects', 'sites' );
148
149
		return $response;
150
	}
151
152
	public function filter_fields_and_options() {
153
		$query_args = $this->query_args();
154
155
		$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...
156
		$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...
157
	}
158
159
	/**
160
	 * Collects the necessary information to return for a site's response.
161
	 *
162
	 * @return (array)
163
	 */
164
	public function build_current_site_response() {
165
166
		$blog_id = (int) $this->api->get_blog_id_for_output();
167
168
		$this->site = $this->get_platform()->get_site( $blog_id );
169
170
		/**
171
 		 * Filter the structure of information about the site to return.
172
 		 *
173
 		 * @module json-api
174
 		 *
175
 		 * @since 3.9.3
176
 		 *
177
 		 * @param array $site_format Data structure.
178
 		 */
179
		$default_fields = array_keys( apply_filters( 'sites_site_format', self::$site_format ) );
180
181
		$response_keys = is_array( $this->fields_to_include ) ?
182
			array_intersect( $default_fields, $this->fields_to_include ) :
183
			$default_fields;
184
185
		if ( ! $this->has_blog_access( $this->api->token_details, $blog_id ) ) {
186
			$response_keys = array_intersect( $response_keys, self::$no_member_fields );
187
		}
188
189
		return $this->render_response_keys( $response_keys );
190
	}
191
192
	private function has_blog_access( $token_details, $blog_id ) {
193
		if ( is_user_member_of_blog( get_current_user_id(), $blog_id ) ) {
194
			return true;
195
		}
196
197
		$token_details = (array) $token_details;
198
		if ( ! isset( $token_details['access'], $token_details['auth'], $token_details['blog_id'] ) ) {
199
			return false;
200
		}
201
202
		if (
203
			'jetpack' === $token_details['auth'] &&
204
			'blog' === $token_details['access'] &&
205
			$blog_id === $token_details['blog_id']
206
		) {
207
			return true;
208
		}
209
		return false;
210
	}
211
212
	private function render_response_keys( &$response_keys ) {
213
		$response = array();
214
215
		$is_user_logged_in = is_user_logged_in();
216
217
		$this->site->before_render();
218
219
		foreach ( $response_keys as $key ) {
220
			$this->render_response_key( $key, $response, $is_user_logged_in );
221
		}
222
223
		$this->site->after_render( $response );
224
225
		return $response;
226
	}
227
228
	protected function render_response_key( $key, &$response, $is_user_logged_in ) {
229
		do_action( 'pre_render_site_response_key', $key );
230
231
		switch ( $key ) {
232
			case 'ID' :
233
				$response[ $key ] = $this->site->blog_id;
234
				break;
235
			case 'name' :
236
				$response[ $key ] = $this->site->get_name();
237
				break;
238
			case 'description' :
239
				$response[ $key ] = $this->site->get_description();
240
				break;
241
			case 'URL' :
242
				$response[ $key ] = $this->site->get_url();
243
				break;
244
			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...
245
				$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...
246
			case 'is_private' :
247
				$response[ $key ] = $this->site->is_private();
248
				break;
249
			case 'visible' :
250
				$response[ $key ] = $this->site->is_visible();
251
				break;
252
			case 'subscribers_count' :
253
				$response[ $key ] = $this->site->get_subscribers_count();
254
				break;
255
			case 'post_count' :
256
				if ( $is_user_logged_in ) {
257
					$response[ $key ] = $this->site->get_post_count();
258
				}
259
				break;
260
			case 'icon' :
261
				$icon = $this->site->get_icon();
262
263
				if ( ! is_null( $icon ) ) {
264
					$response[ $key ] = $icon;
265
				}
266
				break;
267
			case 'logo' :
268
				$response[ $key ] = $this->site->get_logo();
269
				break;
270
			case 'is_following':
271
				$response[ $key ] = $this->site->is_following();
272
				break;
273
			case 'options':
274
				// small optimisation - don't recalculate 
275
				$all_options = apply_filters( 'sites_site_options_format', self::$site_options_format );
276
277
				$options_response_keys = is_array( $this->options_to_include ) ?
278
					array_intersect( $all_options, $this->options_to_include ) :
279
					$all_options;
280
281
				$options = $this->render_option_keys( $options_response_keys );
282
283
				$this->site->after_render_options( $options );
284
285
				$response[ $key ] = (object) $options;
286
				break;
287
			case 'meta':
288
				$this->build_meta_response( $response );
289
				break;
290
			case 'lang' :
291
				$response[ $key ] = $is_user_logged_in ? $this->site->get_locale() : false;
292
				break;
293
			case 'locale' :
294
				$response[ $key ] = $is_user_logged_in ? $this->site->get_locale() : false;
295
				break;
296
			case 'jetpack' :
297
				$response[ $key ] = $this->site->is_jetpack();
298
				break;
299
			case 'single_user_site' : 
300
				$response[ $key ] = $this->site->is_single_user_site();
301
				break;
302
			case 'is_vip' : 
303
				$response[ $key ] = $this->site->is_vip();
304
				break;
305
			case 'is_multisite' :
306
				$response[ $key ] = $this->site->is_multisite();
307
				break;
308
			case 'capabilities' : 
309
				$response[ $key ] = $this->site->get_capabilities();
310
				break;
311
			case 'jetpack_modules':
312
				$jetpack_modules = $this->site->get_jetpack_modules();
313
				if ( ! is_null( $jetpack_modules ) ) {
314
					$response[ $key ] = $jetpack_modules;
315
				}
316
				break;
317
			case 'plan' :
318
				$response[ $key ] = $this->site->get_plan();
319
				break;
320
			case 'quota' :
321
				$response[ $key ] = $this->site->get_quota();
0 ignored issues
show
Bug introduced by
The method get_quota() does not seem to exist on object<Jetpack_Site>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

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

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
465
					break;
466
				case 'ak_vp_bundle_enabled' :
467
					$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...
468
					break;
469
				case Jetpack_SEO_Utils::FRONT_PAGE_META_OPTION :
470
					$options[ $key ] = $site->get_jetpack_seo_front_page_description();
471
					break;
472
				case Jetpack_SEO_Titles::TITLE_FORMATS_OPTION:
473
					$options[ $key ] = $site->get_jetpack_seo_title_formats();
474
					break;
475
				case 'verification_services_codes' :
476
					$options[ $key ] = $site->get_verification_services_codes();
477
					break;
478
				case 'podcasting_archive':
479
					$options[ $key ] = $site->get_podcasting_archive();
0 ignored issues
show
Bug introduced by
The method get_podcasting_archive() does not seem to exist on object<Jetpack_Site>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
480
					break;
481
				case 'is_domain_only':
482
					$options[ $key ] = $site->is_domain_only();
0 ignored issues
show
Bug introduced by
The method is_domain_only() does not seem to exist on object<Jetpack_Site>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
483
					break;
484
				case 'is_automated_transfer':
485
					$options[ $key ] = $site->is_automated_transfer();
0 ignored issues
show
Bug introduced by
The method is_automated_transfer() does not seem to exist on object<Jetpack_Site>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
486
					break;
487
			}
488
		}
489
490
		return $options;
491
	}
492
493
	protected function build_meta_response( &$response ) {
494
		$links = array(
495
			'self'     => (string) $this->links->get_site_link( $this->site->blog_id ),
496
			'help'     => (string) $this->links->get_site_link( $this->site->blog_id, 'help'      ),
497
			'posts'    => (string) $this->links->get_site_link( $this->site->blog_id, 'posts/'    ),
498
			'comments' => (string) $this->links->get_site_link( $this->site->blog_id, 'comments/' ),
499
			'xmlrpc'   => (string) $this->site->get_xmlrpc_url(),
500
		);
501
502
		$icon = $this->site->get_icon();
503
		if ( ! empty( $icon ) && ! empty( $icon['media_id'] ) ) {
504
			$links['site_icon'] = (string) $this->links->get_site_link( $this->site->blog_id, 'media/' . $icon['media_id'] );
505
		}
506
507
		$response['meta'] = (object) array(
508
			'links' => (object) $links
509
		);
510
	}
511
512
	// apply any WPCOM-only response components to a Jetpack site response
513
	public function decorate_jetpack_response( &$response ) {
514
		$this->site = $this->get_platform()->get_site( $response->ID );
515
		switch_to_blog( $this->site->get_id() );
516
517
		// ensure the response is marked as being from Jetpack
518
		$response->jetpack = true;
519
520
		$wpcom_response = $this->render_response_keys( self::$jetpack_response_field_additions );
521
522
		foreach( $wpcom_response as $key => $value ) {
523
			$response->{ $key } = $value;
524
		}
525
526
		if ( $this->has_blog_access( $this->api->token_details, $response->ID ) ) {
527
			$wpcom_member_response = $this->render_response_keys( self::$jetpack_response_field_member_additions );
528
529
			foreach( $wpcom_member_response as $key => $value ) {
530
				$response->{ $key } = $value;
531
			}
532
		} else {
533
			// ensure private data is not rendered for non members of the site
534
			unset( $response->options );
535
			unset( $response->is_vip );
536
			unset( $response->single_user_site );
537
			unset( $response->is_private );
538
			unset( $response->capabilities );
539
			unset( $response->lang );
540
			unset( $response->user_can_manage );
541
			unset( $response->is_multisite );
542
			unset( $response->plan );
543
		}
544
545
		// render additional options
546
		if ( $response->options ) {
547
			$wpcom_options_response = $this->render_option_keys( self::$jetpack_response_option_additions );
548
549
			foreach ( $wpcom_options_response as $key => $value ) {
550
				$response->options[ $key ] = $value;
551
			}
552
		}
553
554
		restore_current_blog();
555
		return $response; // possibly no need since it's modified in place
556
	}
557
}
558
559
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...
560
	// /sites/%s/post-formats -> $blog_id
561
	function callback( $path = '', $blog_id = 0 ) {
562
		$blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) );
563
		if ( is_wp_error( $blog_id ) ) {
564
			return $blog_id;
565
		}
566
567
		if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
568
			$this->load_theme_functions();
569
		}
570
571
		// Get a list of supported post formats.
572
		$all_formats = get_post_format_strings();
573
		$supported   = get_theme_support( 'post-formats' );
574
575
		$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...
576
577 View Code Duplication
		if ( isset( $supported[0] ) ) {
578
			foreach ( $supported[0] as $format ) {
579
				$supported_formats[ $format ] = $all_formats[ $format ];
580
			}
581
		}
582
583
		$response['formats'] = (object) $supported_formats;
584
585
		return $response;
586
	}
587
}
588
589
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...
590
	// /sites/%s/page-templates -> $blog_id
591
	function callback( $path = '', $blog_id = 0 ) {
592
		$blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) );
593
		if ( is_wp_error( $blog_id ) ) {
594
			return $blog_id;
595
		}
596
597
		if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
598
			$this->load_theme_functions();
599
		}
600
601
		$response = array();
602
		$page_templates = array();
603
604
		$templates = get_page_templates();
605
		ksort( $templates );
606
607
		foreach ( array_keys( $templates ) as $label ) {
608
			$page_templates[] = array(
609
				'label' => $label,
610
				'file'  => $templates[ $label ]
611
			);
612
		}
613
614
		$response['templates'] = $page_templates;
615
616
		return $response;
617
	}
618
}
619