Completed
Push — add/double-encode-message ( 8b6530...2d4e84 )
by
unknown
14:26 queued 05:57
created

WPCOM_JSON_API_GET_Site_Endpoint   F

Complexity

Total Complexity 123

Size/Duplication

Total Lines 610
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
dl 0
loc 610
rs 1.99
c 0
b 0
f 0
wmc 123
lcom 1
cbo 4

9 Methods

Rating   Name   Duplication   Size   Complexity  
A callback() 0 23 5
A filter_fields_and_options() 0 6 3
A build_current_site_response() 0 27 3
B has_blog_access() 0 23 8
A render_response_keys() 0 15 2
F render_response_key() 0 101 32
F render_option_keys() 0 194 61
A build_meta_response() 0 18 3
B decorate_jetpack_response() 0 44 6

How to fix   Complexity   

Complex Class

Complex classes like WPCOM_JSON_API_GET_Site_Endpoint often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use WPCOM_JSON_API_GET_Site_Endpoint, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
new WPCOM_JSON_API_GET_Site_Endpoint( array(
4
	'description' => 'Get information about a site.',
5
	'group'       => 'sites',
6
	'stat'        => 'sites:X',
7
	'allowed_if_flagged' => true,
8
	'method'      => 'GET',
9
	'max_version' => '1.1',
10
	'new_version' => '1.2',
11
	'path'        => '/sites/%s',
12
	'path_labels' => array(
13
		'$site' => '(int|string) Site ID or domain',
14
	),
15
	'allow_jetpack_site_auth' => true,
16
	'query_parameters' => array(
17
		'context' => false,
18
		'options' => '(string) Optional. Returns specified options only. Comma-separated list. Example: options=login_url,timezone',
19
	),
20
21
	'response_format' => WPCOM_JSON_API_GET_Site_Endpoint::$site_format,
22
23
	'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/en.blog.wordpress.com/',
24
) );
25
26
class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint {
27
28
	public static $site_format = array(
29
		'ID'                => '(int) Site ID',
30
		'name'              => '(string) Title of site',
31
		'description'       => '(string) Tagline or description of site',
32
		'URL'               => '(string) Full URL to the site',
33
		'user_can_manage'   => '(bool) The current user can manage this site', // deprecated
34
		'capabilities'      => '(array) Array of capabilities for the current user on this site.',
35
		'jetpack'           => '(bool)  Whether the site is a Jetpack site or not',
36
		'is_multisite'      => '(bool) Whether the site is a Multisite site or not. Always true for WP.com sites.',
37
		'post_count'        => '(int) The number of posts the site has',
38
		'subscribers_count' => '(int) The number of subscribers the site has',
39
		'lang'              => '(string) Primary language code of the site',
40
		'icon'              => '(array) An array of icon formats for the site',
41
		'logo'              => '(array) The site logo, set in the Customizer',
42
		'visible'           => '(bool) If this site is visible in the user\'s site list',
43
		'is_private'        => '(bool) If the site is a private site or not',
44
		'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.',
45
		'is_vip'            => '(bool) If the site is a VIP site or not.',
46
		'is_following'      => '(bool) If the current user is subscribed to this site in the reader',
47
		'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/',
48
		'plan'              => '(array) Details of the current plan for this site.',
49
		'updates'           => '(array) An array of available updates for plugins, themes, wordpress, and languages.',
50
		'jetpack_modules'   => '(array) A list of active Jetpack modules.',
51
		'meta'              => '(object) Meta data',
52
		'quota'             => '(array) An array describing how much space a user has left for uploads',
53
		'launch_status'     => '(string) A string describing the launch status of a site',
54
	);
55
56
	protected static $no_member_fields = array(
57
		'ID',
58
		'name',
59
		'description',
60
		'URL',
61
		'jetpack',
62
		'post_count',
63
		'subscribers_count',
64
		'lang',
65
		'locale',
66
		'icon',
67
		'logo',
68
		'visible',
69
		'is_private',
70
		'is_following',
71
		'meta',
72
		'launch_status',
73
	);
74
75
	protected static $site_options_format = array(
76
		'timezone',
77
		'gmt_offset',
78
		'blog_public',
79
		'videopress_enabled',
80
		'upgraded_filetypes_enabled',
81
		'login_url',
82
		'admin_url',
83
		'is_mapped_domain',
84
		'is_redirect',
85
		'unmapped_url',
86
		'featured_images_enabled',
87
		'theme_slug',
88
		'header_image',
89
		'background_color',
90
		'image_default_link_type',
91
		'image_thumbnail_width',
92
		'image_thumbnail_height',
93
		'image_thumbnail_crop',
94
		'image_medium_width',
95
		'image_medium_height',
96
		'image_large_width',
97
		'image_large_height',
98
		'permalink_structure',
99
		'post_formats',
100
		'default_post_format',
101
		'default_category',
102
		'allowed_file_types',
103
		'show_on_front',
104
		/** This filter is documented in modules/likes.php */
105
		'default_likes_enabled',
106
		'default_sharing_status',
107
		'default_comment_status',
108
		'default_ping_status',
109
		'software_version',
110
		'created_at',
111
		'wordads',
112
		'publicize_permanently_disabled',
113
		'frame_nonce',
114
		'page_on_front',
115
		'page_for_posts',
116
		'headstart',
117
		'headstart_is_fresh',
118
		'ak_vp_bundle_enabled',
119
		Jetpack_SEO_Utils::FRONT_PAGE_META_OPTION,
120
		Jetpack_SEO_Titles::TITLE_FORMATS_OPTION,
121
		'verification_services_codes',
122
		'podcasting_archive',
123
		'is_domain_only',
124
		'is_automated_transfer',
125
		'is_wpcom_store',
126
		'signup_is_store',
127
		'has_pending_automated_transfer',
128
		'woocommerce_is_active',
129
		'design_type',
130
		'site_goals',
131
	);
132
133
	protected static $jetpack_response_field_additions = array(
134
		'subscribers_count',
135
	);
136
137
	protected static $jetpack_response_field_member_additions = array(
138
		'capabilities',
139
		'plan',
140
	);
141
142
	protected static $jetpack_response_option_additions = array(
143
		'publicize_permanently_disabled',
144
		'ak_vp_bundle_enabled',
145
		'is_automated_transfer',
146
		'is_wpcom_store',
147
		'woocommerce_is_active',
148
		'frame_nonce',
149
		'design_type',
150
		'wordads'
151
	);
152
153
	private $site;
154
155
	// protected $compact = null;
156
	protected $fields_to_include = '_all';
157
	protected $options_to_include = '_all';
158
159
	// /sites/mine
160
	// /sites/%s -> $blog_id
161
	function callback( $path = '', $blog_id = 0 ) {
162
		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...
163
			$api = WPCOM_JSON_API::init();
164
			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...
165
				return new WP_Error( 'authorization_required', 'An active access token must be used to query information about the current blog.', 403 );
166
			}
167
			$blog_id = $api->token_details['blog_id'];
168
		}
169
170
		$blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) );
171
		if ( is_wp_error( $blog_id ) ) {
172
			return $blog_id;
173
		}
174
175
		$this->filter_fields_and_options();
176
177
		$response = $this->build_current_site_response();
178
179
		/** This action is documented in json-endpoints/class.wpcom-json-api-site-settings-endpoint.php */
180
		do_action( 'wpcom_json_api_objects', 'sites' );
181
182
		return $response;
183
	}
184
185
	public function filter_fields_and_options() {
186
		$query_args = $this->query_args();
187
188
		$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...
189
		$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...
190
	}
191
192
	/**
193
	 * Collects the necessary information to return for a site's response.
194
	 *
195
	 * @return array
196
	 */
197
	public function build_current_site_response() {
198
199
		$blog_id = (int) $this->api->get_blog_id_for_output();
200
201
		$this->site = $this->get_platform()->get_site( $blog_id );
202
203
		/**
204
 		 * Filter the structure of information about the site to return.
205
 		 *
206
 		 * @module json-api
207
 		 *
208
 		 * @since 3.9.3
209
 		 *
210
 		 * @param array $site_format Data structure.
211
 		 */
212
		$default_fields = array_keys( apply_filters( 'sites_site_format', self::$site_format ) );
213
214
		$response_keys = is_array( $this->fields_to_include ) ?
215
			array_intersect( $default_fields, $this->fields_to_include ) :
216
			$default_fields;
217
218
		if ( ! $this->has_blog_access( $this->api->token_details, $blog_id ) ) {
219
			$response_keys = array_intersect( $response_keys, self::$no_member_fields );
220
		}
221
222
		return $this->render_response_keys( $response_keys );
223
	}
224
225
	/**
226
	 * Checks that the current user has access to the current blog,
227
	 * and failing that checks that we have a valid blog token.
228
	 *
229
	 * @param $token_details array Details obtained from the authorization token
230
	 * @param $blog_id int The server-side blog id on wordpress.com
231
	 *
232
	 * @return bool
233
	 */
234
	private function has_blog_access( $token_details, $blog_id ) {
235
		$current_blog_id = (  defined( 'IS_WPCOM' ) && IS_WPCOM ) ?
236
			$blog_id :
237
			get_current_blog_id();
238
239
		if ( is_user_member_of_blog( get_current_user_id(), $current_blog_id ) ) {
240
			return true;
241
		}
242
243
		$token_details = (array) $token_details;
244
		if ( ! isset( $token_details['access'], $token_details['auth'], $token_details['blog_id'] ) ) {
245
			return false;
246
		}
247
248
		if (
249
			'jetpack' === $token_details['auth'] &&
250
			'blog' === $token_details['access'] &&
251
			$current_blog_id === $token_details['blog_id']
252
		) {
253
			return true;
254
		}
255
		return false;
256
	}
257
258
	private function render_response_keys( &$response_keys ) {
259
		$response = array();
260
261
		$is_user_logged_in = is_user_logged_in();
262
263
		$this->site->before_render();
264
265
		foreach ( $response_keys as $key ) {
266
			$this->render_response_key( $key, $response, $is_user_logged_in );
267
		}
268
269
		$this->site->after_render( $response );
270
271
		return $response;
272
	}
273
274
	protected function render_response_key( $key, &$response, $is_user_logged_in ) {
275
		do_action( 'pre_render_site_response_key', $key );
276
277
		switch ( $key ) {
278
			case 'ID' :
279
				$response[ $key ] = $this->site->blog_id;
280
				break;
281
			case 'name' :
282
				$response[ $key ] = $this->site->get_name();
283
				break;
284
			case 'description' :
285
				$response[ $key ] = $this->site->get_description();
286
				break;
287
			case 'URL' :
288
				$response[ $key ] = $this->site->get_url();
289
				break;
290
			case 'user_can_manage' :
291
				$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...
292
			case 'is_private' :
293
				$response[ $key ] = $this->site->is_private();
294
				break;
295
			case 'visible' :
296
				$response[ $key ] = $this->site->is_visible();
297
				break;
298
			case 'subscribers_count' :
299
				$response[ $key ] = $this->site->get_subscribers_count();
300
				break;
301
			case 'post_count' :
302
				if ( $is_user_logged_in ) {
303
					$response[ $key ] = $this->site->get_post_count();
304
				}
305
				break;
306
			case 'icon' :
307
				$icon = $this->site->get_icon();
308
309
				if ( ! is_null( $icon ) ) {
310
					$response[ $key ] = $icon;
311
				}
312
				break;
313
			case 'logo' :
314
				$response[ $key ] = $this->site->get_logo();
315
				break;
316
			case 'is_following':
317
				$response[ $key ] = $this->site->is_following();
318
				break;
319
			case 'options':
320
				// small optimisation - don't recalculate
321
				$all_options = apply_filters( 'sites_site_options_format', self::$site_options_format );
322
323
				$options_response_keys = is_array( $this->options_to_include ) ?
324
					array_intersect( $all_options, $this->options_to_include ) :
325
					$all_options;
326
327
				$options = $this->render_option_keys( $options_response_keys );
328
329
				$this->site->after_render_options( $options );
330
331
				$response[ $key ] = (object) $options;
332
				break;
333
			case 'meta':
334
				$this->build_meta_response( $response );
335
				break;
336
			case 'lang' :
337
				$response[ $key ] = $is_user_logged_in ? $this->site->get_locale() : false;
338
				break;
339
			case 'locale' :
340
				$response[ $key ] = $is_user_logged_in ? $this->site->get_locale() : false;
341
				break;
342
			case 'jetpack' :
343
				$response[ $key ] = $this->site->is_jetpack();
344
				break;
345
			case 'single_user_site' :
346
				$response[ $key ] = $this->site->is_single_user_site();
347
				break;
348
			case 'is_vip' :
349
				$response[ $key ] = $this->site->is_vip();
350
				break;
351
			case 'is_multisite' :
352
				$response[ $key ] = $this->site->is_multisite();
353
				break;
354
			case 'capabilities' :
355
				$response[ $key ] = $this->site->get_capabilities();
356
				break;
357
			case 'jetpack_modules':
358
				if ( is_user_member_of_blog() ) {
359
					$response[ $key ] = $this->site->get_jetpack_modules();
360
				}
361
				break;
362
			case 'plan' :
363
				$response[ $key ] = $this->site->get_plan();
364
				break;
365
			case 'quota' :
366
				$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...
367
				break;
368
			case 'launch_status' : 
369
				$response[ $key ] = $this->site->get_launch_status();
370
				break;
371
		}
372
373
		do_action( 'post_render_site_response_key', $key );
374
	}
375
376
	protected function render_option_keys( &$options_response_keys ) {
377
		if ( ! current_user_can( 'edit_posts' ) ) {
378
			return array();
379
		}
380
381
		$options = array();
382
		$site = $this->site;
383
384
		$custom_front_page = $site->is_custom_front_page();
385
386
		foreach ( $options_response_keys as $key ) {
387
			switch ( $key ) {
388
				case 'timezone' :
389
					$options[ $key ] = $site->get_timezone();
390
					break;
391
				case 'gmt_offset' :
392
					$options[ $key ] = $site->get_gmt_offset();
393
					break;
394
				case 'videopress_enabled' :
395
					$options[ $key ] = $site->has_videopress();
396
					break;
397
				case 'upgraded_filetypes_enabled' :
398
					$options[ $key ] = $site->upgraded_filetypes_enabled();
399
					break;
400
				case 'login_url' :
401
					$options[ $key ] = $site->get_login_url();
402
					break;
403
				case 'admin_url' :
404
					$options[ $key ] = $site->get_admin_url();
405
					break;
406
				case 'is_mapped_domain' :
407
					$options[ $key ] = $site->is_mapped_domain();
408
					break;
409
				case 'is_redirect' :
410
					$options[ $key ] = $site->is_redirect();
411
					break;
412
				case 'unmapped_url' :
413
					$options[ $key ] = $site->get_unmapped_url();
414
					break;
415
				case 'featured_images_enabled' :
416
					$options[ $key ] = $site->featured_images_enabled();
417
					break;
418
				case 'theme_slug' :
419
					$options[ $key ] = $site->get_theme_slug();
420
					break;
421
				case 'header_image' :
422
					$options[ $key ] = $site->get_header_image();
423
					break;
424
				case 'background_color' :
425
					$options[ $key ] = $site->get_background_color();
426
					break;
427
				case 'image_default_link_type' :
428
					$options[ $key ] = $site->get_image_default_link_type();
429
					break;
430
				case 'image_thumbnail_width' :
431
					$options[ $key ] = $site->get_image_thumbnail_width();
432
					break;
433
				case 'image_thumbnail_height' :
434
					$options[ $key ] = $site->get_image_thumbnail_height();
435
					break;
436
				case 'image_thumbnail_crop' :
437
					$options[ $key ] = $site->get_image_thumbnail_crop();
438
					break;
439
				case 'image_medium_width' :
440
					$options[ $key ] = $site->get_image_medium_width();
441
					break;
442
				case 'image_medium_height' :
443
					$options[ $key ] = $site->get_image_medium_height();
444
					break;
445
				case 'image_large_width' :
446
					$options[ $key ] = $site->get_image_large_width();
447
					break;
448
				case 'image_large_height' :
449
					$options[ $key ] = $site->get_image_large_height();
450
					break;
451
				case 'permalink_structure' :
452
					$options[ $key ] = $site->get_permalink_structure();
453
					break;
454
				case 'post_formats' :
455
					$options[ $key ] = $site->get_post_formats();
456
					break;
457
				case 'default_post_format' :
458
					$options[ $key ] = $site->get_default_post_format();
459
					break;
460
				case 'default_category' :
461
					$options[ $key ] = $site->get_default_category();
462
					break;
463
				case 'allowed_file_types' :
464
					$options[ $key ] = $site->allowed_file_types();
465
					break;
466
				case 'show_on_front' :
467
					$options[ $key ] = $site->get_show_on_front();
468
					break;
469
				/** This filter is documented in modules/likes.php */
470
				case 'default_likes_enabled' :
471
					$options[ $key ] = $site->get_default_likes_enabled();
472
					break;
473
				case 'default_sharing_status' :
474
					$options[ $key ] = $site->get_default_sharing_status();
475
					break;
476
				case 'default_comment_status' :
477
					$options[ $key ] = $site->get_default_comment_status();
478
					break;
479
				case 'default_ping_status' :
480
					$options[ $key ] = $site->default_ping_status();
481
					break;
482
				case 'software_version' :
483
					$options[ $key ] = $site->get_wordpress_version();
484
					break;
485
				case 'created_at' :
486
					$options[ $key ] = $site->get_registered_date();
487
					break;
488
				case 'wordads' :
489
					$options[ $key ] = $site->has_wordads();
490
					break;
491
				case 'publicize_permanently_disabled' :
492
					$options[ $key ] = $site->is_publicize_permanently_disabled();
493
					break;
494
				case 'frame_nonce' :
495
					$options[ $key ] = $site->get_frame_nonce();
496
					break;
497
				case 'page_on_front' :
498
					if ( $custom_front_page ) {
499
						$options[ $key ] = $site->get_page_on_front();
500
					}
501
					break;
502
				case 'page_for_posts' :
503
					if ( $custom_front_page ) {
504
						$options[ $key ] = $site->get_page_for_posts();
505
					}
506
					break;
507
				case 'headstart' :
508
					$options[ $key ] = $site->is_headstart();
509
					break;
510
				case 'headstart_is_fresh' :
511
					$options[ $key ] = $site->is_headstart_fresh();
512
					break;
513
				case 'ak_vp_bundle_enabled' :
514
					$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...
515
					break;
516
				case Jetpack_SEO_Utils::FRONT_PAGE_META_OPTION :
517
					$options[ $key ] = $site->get_jetpack_seo_front_page_description();
518
					break;
519
				case Jetpack_SEO_Titles::TITLE_FORMATS_OPTION :
520
					$options[ $key ] = $site->get_jetpack_seo_title_formats();
521
					break;
522
				case 'verification_services_codes' :
523
					$options[ $key ] = $site->get_verification_services_codes();
524
					break;
525
				case 'podcasting_archive':
526
					$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...
527
					break;
528
				case 'is_domain_only':
529
					$options[ $key ] = $site->is_domain_only();
530
					break;
531
				case 'is_automated_transfer':
532
					$options[ $key ] = $site->is_automated_transfer();
533
					break;
534
				case 'blog_public':
535
					$options[ $key ] = $site->get_blog_public();
536
					break;
537
				case 'is_wpcom_store':
538
					$options[ $key ] = $site->is_wpcom_store();
539
					break;
540
				case 'signup_is_store':
541
					$signup_is_store = $site->signup_is_store();
542
543
					if ( $signup_is_store ) {
544
						$options[ $key ] = $site->signup_is_store();
545
					}
546
547
					break;
548
				case 'has_pending_automated_transfer':
549
					$has_pending_automated_transfer = $site->has_pending_automated_transfer();
550
551
					if ( $has_pending_automated_transfer ) {
552
						$options[ $key ] = true;
553
					}
554
555
					break;
556
				case 'woocommerce_is_active':
557
					$options[ $key ] = $site->woocommerce_is_active();
558
					break;
559
				case 'design_type':
560
					$options[ $key ] = $site->get_design_type();
561
					break;
562
				case 'site_goals':
563
					$options[ $key ] = $site->get_site_goals();
564
					break;
565
			}
566
		}
567
568
		return $options;
569
	}
570
571
	protected function build_meta_response( &$response ) {
572
		$links = array(
573
			'self'     => (string) $this->links->get_site_link( $this->site->blog_id ),
574
			'help'     => (string) $this->links->get_site_link( $this->site->blog_id, 'help'      ),
575
			'posts'    => (string) $this->links->get_site_link( $this->site->blog_id, 'posts/'    ),
576
			'comments' => (string) $this->links->get_site_link( $this->site->blog_id, 'comments/' ),
577
			'xmlrpc'   => (string) $this->site->get_xmlrpc_url(),
578
		);
579
580
		$icon = $this->site->get_icon();
581
		if ( ! empty( $icon ) && ! empty( $icon['media_id'] ) ) {
582
			$links['site_icon'] = (string) $this->links->get_site_link( $this->site->blog_id, 'media/' . $icon['media_id'] );
583
		}
584
585
		$response['meta'] = (object) array(
586
			'links' => (object) $links
587
		);
588
	}
589
590
	// apply any WPCOM-only response components to a Jetpack site response
591
	public function decorate_jetpack_response( &$response ) {
592
		$this->site = $this->get_platform()->get_site( $response->ID );
593
		switch_to_blog( $this->site->get_id() );
594
595
		// ensure the response is marked as being from Jetpack
596
		$response->jetpack = true;
597
598
		$wpcom_response = $this->render_response_keys( self::$jetpack_response_field_additions );
599
600
		foreach( $wpcom_response as $key => $value ) {
601
			$response->{ $key } = $value;
602
		}
603
604
		if ( $this->has_blog_access( $this->api->token_details, $response->ID ) ) {
605
			$wpcom_member_response = $this->render_response_keys( self::$jetpack_response_field_member_additions );
606
607
			foreach( $wpcom_member_response as $key => $value ) {
608
				$response->{ $key } = $value;
609
			}
610
		} else {
611
			// ensure private data is not rendered for non members of the site
612
			unset( $response->options );
613
			unset( $response->is_vip );
614
			unset( $response->single_user_site );
615
			unset( $response->is_private );
616
			unset( $response->capabilities );
617
			unset( $response->lang );
618
			unset( $response->user_can_manage );
619
			unset( $response->is_multisite );
620
			unset( $response->plan );
621
		}
622
623
		// render additional options
624
		if ( $response->options ) {
625
			$wpcom_options_response = $this->render_option_keys( self::$jetpack_response_option_additions );
626
627
			foreach ( $wpcom_options_response as $key => $value ) {
628
				$response->options[ $key ] = $value;
629
			}
630
		}
631
632
		restore_current_blog();
633
		return $response; // possibly no need since it's modified in place
634
	}
635
}
636
637
new WPCOM_JSON_API_List_Post_Formats_Endpoint( array(
638
	'description' => 'Get a list of post formats supported by a site.',
639
	'group'       => '__do_not_document',
640
	'stat'        => 'sites:X:post-formats',
641
642
	'method'      => 'GET',
643
	'path'        => '/sites/%s/post-formats',
644
	'path_labels' => array(
645
		'$site' => '(int|string) Site ID or domain',
646
	),
647
648
	'query_parameters' => array(
649
		'context' => false,
650
	),
651
652
	'response_format' => array(
653
		'formats' => '(object) An object of supported post formats, each key a supported format slug mapped to its display string.',
654
	)
655
) );
656
657
class WPCOM_JSON_API_List_Post_Formats_Endpoint extends WPCOM_JSON_API_Endpoint {
658
	// /sites/%s/post-formats -> $blog_id
659
	function callback( $path = '', $blog_id = 0 ) {
660
		$blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) );
661
		if ( is_wp_error( $blog_id ) ) {
662
			return $blog_id;
663
		}
664
665
		if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
666
			$this->load_theme_functions();
667
		}
668
669
		// Get a list of supported post formats.
670
		$all_formats = get_post_format_strings();
671
		$supported   = get_theme_support( 'post-formats' );
672
673
		$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...
674
675 View Code Duplication
		if ( isset( $supported[0] ) ) {
676
			foreach ( $supported[0] as $format ) {
677
				$supported_formats[ $format ] = $all_formats[ $format ];
678
			}
679
		}
680
681
		$response['formats'] = (object) $supported_formats;
682
683
		return $response;
684
	}
685
}
686
687
new WPCOM_JSON_API_List_Page_Templates_Endpoint( array(
688
	'description' => 'Get a list of page templates supported by a site.',
689
	'group'       => 'sites',
690
	'stat'        => 'sites:X:post-templates',
691
692
	'method'      => 'GET',
693
	'path'        => '/sites/%s/page-templates',
694
	'path_labels' => array(
695
		'$site' => '(int|string) Site ID or domain',
696
	),
697
	'query_parameters' => array(
698
		'context' => false,
699
	),
700
	'response_format' => array(
701
		'templates' => '(array) A list of supported page templates. Contains label and file.',
702
	),
703
	'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/33534099/page-templates'
704
) );
705
706
class WPCOM_JSON_API_List_Page_Templates_Endpoint extends WPCOM_JSON_API_Endpoint {
707
	// /sites/%s/page-templates -> $blog_id
708
	function callback( $path = '', $blog_id = 0 ) {
709
		$blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) );
710
		if ( is_wp_error( $blog_id ) ) {
711
			return $blog_id;
712
		}
713
714
		if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
715
			$this->load_theme_functions();
716
		}
717
718
		$response = array();
719
		$page_templates = array();
720
721
		$templates = get_page_templates();
722
		ksort( $templates );
723
724
		foreach ( array_keys( $templates ) as $label ) {
725
			$page_templates[] = array(
726
				'label' => $label,
727
				'file'  => $templates[ $label ]
728
			);
729
		}
730
731
		$response['templates'] = $page_templates;
732
733
		return $response;
734
	}
735
}
736