Complex classes like WPCOM_JSON_API 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, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
7 | class WPCOM_JSON_API { |
||
8 | static $self = null; |
||
9 | |||
10 | public $endpoints = array(); |
||
11 | |||
12 | public $token_details = array(); |
||
13 | |||
14 | public $method = ''; |
||
15 | public $url = ''; |
||
16 | public $path = ''; |
||
17 | public $version = null; |
||
18 | public $query = array(); |
||
19 | public $post_body = null; |
||
20 | public $files = null; |
||
21 | public $content_type = null; |
||
22 | public $accept = ''; |
||
23 | |||
24 | public $_server_https; |
||
25 | public $exit = true; |
||
26 | public $public_api_scheme = 'https'; |
||
27 | |||
28 | public $output_status_code = 200; |
||
29 | |||
30 | public $trapped_error = null; |
||
31 | public $did_output = false; |
||
32 | |||
33 | public $extra_headers = array(); |
||
34 | |||
35 | /** |
||
36 | * @return WPCOM_JSON_API instance |
||
37 | */ |
||
38 | static function init( $method = null, $url = null, $post_body = null ) { |
||
39 | if ( !self::$self ) { |
||
40 | $class = function_exists( 'get_called_class' ) ? get_called_class() : __CLASS__; |
||
41 | self::$self = new $class( $method, $url, $post_body ); |
||
42 | } |
||
43 | return self::$self; |
||
44 | } |
||
45 | |||
46 | function add( WPCOM_JSON_API_Endpoint $endpoint ) { |
||
47 | $path_versions = serialize( array ( |
||
48 | $endpoint->path, |
||
49 | $endpoint->min_version, |
||
50 | $endpoint->max_version, |
||
51 | ) ); |
||
52 | if ( !isset( $this->endpoints[$path_versions] ) ) { |
||
53 | $this->endpoints[$path_versions] = array(); |
||
54 | } |
||
55 | $this->endpoints[$path_versions][$endpoint->method] = $endpoint; |
||
56 | } |
||
57 | |||
58 | static function is_truthy( $value ) { |
||
59 | switch ( strtolower( (string) $value ) ) { |
||
60 | case '1' : |
||
61 | case 't' : |
||
62 | case 'true' : |
||
63 | return true; |
||
64 | } |
||
65 | |||
66 | return false; |
||
67 | } |
||
68 | |||
69 | static function is_falsy( $value ) { |
||
70 | switch ( strtolower( (string) $value ) ) { |
||
71 | case '0' : |
||
72 | case 'f' : |
||
73 | case 'false' : |
||
74 | return true; |
||
75 | } |
||
76 | |||
77 | return false; |
||
78 | } |
||
79 | |||
80 | function __construct() { |
||
81 | $args = func_get_args(); |
||
82 | call_user_func_array( array( $this, 'setup_inputs' ), $args ); |
||
83 | } |
||
84 | |||
85 | function setup_inputs( $method = null, $url = null, $post_body = null ) { |
||
86 | if ( is_null( $method ) ) { |
||
87 | $this->method = strtoupper( $_SERVER['REQUEST_METHOD'] ); |
||
88 | } else { |
||
89 | $this->method = strtoupper( $method ); |
||
90 | } |
||
91 | if ( is_null( $url ) ) { |
||
92 | $this->url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ); |
||
93 | } else { |
||
94 | $this->url = $url; |
||
95 | } |
||
96 | |||
97 | $parsed = parse_url( $this->url ); |
||
98 | $this->path = $parsed['path']; |
||
99 | |||
100 | if ( !empty( $parsed['query'] ) ) { |
||
101 | wp_parse_str( $parsed['query'], $this->query ); |
||
102 | } |
||
103 | |||
104 | if ( isset( $_SERVER['HTTP_ACCEPT'] ) && $_SERVER['HTTP_ACCEPT'] ) { |
||
105 | $this->accept = $_SERVER['HTTP_ACCEPT']; |
||
106 | } |
||
107 | |||
108 | if ( 'POST' === $this->method ) { |
||
109 | if ( is_null( $post_body ) ) { |
||
110 | $this->post_body = file_get_contents( 'php://input' ); |
||
111 | |||
112 | if ( isset( $_SERVER['HTTP_CONTENT_TYPE'] ) && $_SERVER['HTTP_CONTENT_TYPE'] ) { |
||
113 | $this->content_type = $_SERVER['HTTP_CONTENT_TYPE']; |
||
114 | } elseif ( isset( $_SERVER['CONTENT_TYPE'] ) && $_SERVER['CONTENT_TYPE'] ) { |
||
115 | $this->content_type = $_SERVER['CONTENT_TYPE'] ; |
||
116 | } elseif ( '{' === $this->post_body[0] ) { |
||
117 | $this->content_type = 'application/json'; |
||
118 | } else { |
||
119 | $this->content_type = 'application/x-www-form-urlencoded'; |
||
120 | } |
||
121 | |||
122 | if ( 0 === strpos( strtolower( $this->content_type ), 'multipart/' ) ) { |
||
123 | $this->post_body = http_build_query( stripslashes_deep( $_POST ) ); |
||
124 | $this->files = $_FILES; |
||
125 | $this->content_type = 'multipart/form-data'; |
||
126 | } |
||
127 | } else { |
||
128 | $this->post_body = $post_body; |
||
129 | $this->content_type = '{' === isset( $this->post_body[0] ) && $this->post_body[0] ? 'application/json' : 'application/x-www-form-urlencoded'; |
||
130 | } |
||
131 | } else { |
||
132 | $this->post_body = null; |
||
133 | $this->content_type = null; |
||
134 | } |
||
135 | |||
136 | $this->_server_https = array_key_exists( 'HTTPS', $_SERVER ) ? $_SERVER['HTTPS'] : '--UNset--'; |
||
137 | } |
||
138 | |||
139 | function initialize() { |
||
140 | $this->token_details['blog_id'] = Jetpack_Options::get_option( 'id' ); |
||
141 | } |
||
142 | |||
143 | function serve( $exit = true ) { |
||
144 | ini_set( 'display_errors', false ); |
||
145 | |||
146 | $this->exit = (bool) $exit; |
||
147 | |||
148 | // This was causing problems with Jetpack, but is necessary for wpcom |
||
149 | // @see https://github.com/Automattic/jetpack/pull/2603 |
||
150 | // @see r124548-wpcom |
||
151 | if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { |
||
152 | add_filter( 'home_url', array( $this, 'ensure_http_scheme_of_home_url' ), 10, 3 ); |
||
153 | } |
||
154 | |||
155 | add_filter( 'user_can_richedit', '__return_true' ); |
||
156 | |||
157 | add_filter( 'comment_edit_pre', array( $this, 'comment_edit_pre' ) ); |
||
158 | |||
159 | $initialization = $this->initialize(); |
||
160 | if ( 'OPTIONS' == $this->method ) { |
||
161 | /** |
||
162 | * Fires before the page output. |
||
163 | * Can be used to specify custom header options. |
||
164 | * |
||
165 | * @module json-api |
||
166 | * |
||
167 | * @since 3.1.0 |
||
168 | */ |
||
169 | do_action( 'wpcom_json_api_options' ); |
||
170 | return $this->output( 200, '', 'text/plain' ); |
||
171 | } |
||
172 | |||
173 | if ( is_wp_error( $initialization ) ) { |
||
174 | $this->output_error( $initialization ); |
||
175 | return; |
||
176 | } |
||
177 | |||
178 | // Normalize path and extract API version |
||
179 | $this->path = untrailingslashit( $this->path ); |
||
180 | preg_match( '#^/rest/v(\d+(\.\d+)*)#', $this->path, $matches ); |
||
181 | $this->path = substr( $this->path, strlen( $matches[0] ) ); |
||
182 | $this->version = $matches[1]; |
||
183 | |||
184 | $allowed_methods = array( 'GET', 'POST' ); |
||
185 | $four_oh_five = false; |
||
186 | |||
187 | $is_help = preg_match( '#/help/?$#i', $this->path ); |
||
188 | $matching_endpoints = array(); |
||
189 | |||
190 | if ( $is_help ) { |
||
191 | $origin = get_http_origin(); |
||
192 | |||
193 | if ( !empty( $origin ) && 'GET' == $this->method ) { |
||
194 | header( 'Access-Control-Allow-Origin: ' . esc_url_raw( $origin ) ); |
||
195 | } |
||
196 | |||
197 | $this->path = substr( rtrim( $this->path, '/' ), 0, -5 ); |
||
198 | // Show help for all matching endpoints regardless of method |
||
199 | $methods = $allowed_methods; |
||
200 | $find_all_matching_endpoints = true; |
||
201 | // How deep to truncate each endpoint's path to see if it matches this help request |
||
202 | $depth = substr_count( $this->path, '/' ) + 1; |
||
203 | if ( false !== stripos( $this->accept, 'javascript' ) || false !== stripos( $this->accept, 'json' ) ) { |
||
204 | $help_content_type = 'json'; |
||
205 | } else { |
||
206 | $help_content_type = 'html'; |
||
207 | } |
||
208 | } else { |
||
209 | if ( in_array( $this->method, $allowed_methods ) ) { |
||
210 | // Only serve requested method |
||
211 | $methods = array( $this->method ); |
||
212 | $find_all_matching_endpoints = false; |
||
213 | } else { |
||
214 | // We don't allow this requested method - find matching endpoints and send 405 |
||
215 | $methods = $allowed_methods; |
||
216 | $find_all_matching_endpoints = true; |
||
217 | $four_oh_five = true; |
||
218 | } |
||
219 | } |
||
220 | |||
221 | // Find which endpoint to serve |
||
222 | $found = false; |
||
223 | foreach ( $this->endpoints as $endpoint_path_versions => $endpoints_by_method ) { |
||
224 | $endpoint_path_versions = unserialize( $endpoint_path_versions ); |
||
225 | $endpoint_path = $endpoint_path_versions[0]; |
||
226 | $endpoint_min_version = $endpoint_path_versions[1]; |
||
227 | $endpoint_max_version = $endpoint_path_versions[2]; |
||
228 | |||
229 | // Make sure max_version is not less than min_version |
||
230 | if ( version_compare( $endpoint_max_version, $endpoint_min_version, '<' ) ) { |
||
231 | $endpoint_max_version = $endpoint_min_version; |
||
232 | } |
||
233 | |||
234 | foreach ( $methods as $method ) { |
||
235 | if ( !isset( $endpoints_by_method[$method] ) ) { |
||
236 | continue; |
||
237 | } |
||
238 | |||
239 | // Normalize |
||
240 | $endpoint_path = untrailingslashit( $endpoint_path ); |
||
241 | if ( $is_help ) { |
||
242 | // Truncate path at help depth |
||
243 | $endpoint_path = join( '/', array_slice( explode( '/', $endpoint_path ), 0, $depth ) ); |
||
244 | } |
||
245 | |||
246 | // Generate regular expression from sprintf() |
||
247 | $endpoint_path_regex = str_replace( array( '%s', '%d' ), array( '([^/?&]+)', '(\d+)' ), $endpoint_path ); |
||
248 | |||
249 | if ( !preg_match( "#^$endpoint_path_regex\$#", $this->path, $path_pieces ) ) { |
||
250 | // This endpoint does not match the requested path. |
||
251 | continue; |
||
252 | } |
||
253 | |||
254 | if ( version_compare( $this->version, $endpoint_min_version, '<' ) || version_compare( $this->version, $endpoint_max_version, '>' ) ) { |
||
255 | // This endpoint does not match the requested version. |
||
256 | continue; |
||
257 | } |
||
258 | |||
259 | $found = true; |
||
260 | |||
261 | if ( $find_all_matching_endpoints ) { |
||
262 | $matching_endpoints[] = array( $endpoints_by_method[$method], $path_pieces ); |
||
263 | } else { |
||
264 | // The method parameters are now in $path_pieces |
||
265 | $endpoint = $endpoints_by_method[$method]; |
||
266 | break 2; |
||
267 | } |
||
268 | } |
||
269 | } |
||
270 | |||
271 | if ( !$found ) { |
||
272 | return $this->output( 404, '', 'text/plain' ); |
||
273 | } |
||
274 | |||
275 | if ( $four_oh_five ) { |
||
276 | $allowed_methods = array(); |
||
277 | foreach ( $matching_endpoints as $matching_endpoint ) { |
||
278 | $allowed_methods[] = $matching_endpoint[0]->method; |
||
279 | } |
||
280 | |||
281 | header( 'Allow: ' . strtoupper( join( ',', array_unique( $allowed_methods ) ) ) ); |
||
282 | return $this->output( 405, array( 'error' => 'not_allowed', 'error_message' => 'Method not allowed' ) ); |
||
283 | } |
||
284 | |||
285 | if ( $is_help ) { |
||
286 | /** |
||
287 | * Fires before the API output. |
||
288 | * |
||
289 | * @since 1.9.0 |
||
290 | * |
||
291 | * @param string help. |
||
292 | */ |
||
293 | do_action( 'wpcom_json_api_output', 'help' ); |
||
294 | $proxied = function_exists( 'wpcom_is_proxied_request' ) ? wpcom_is_proxied_request() : false; |
||
295 | if ( 'json' === $help_content_type ) { |
||
296 | $docs = array(); |
||
297 | foreach ( $matching_endpoints as $matching_endpoint ) { |
||
298 | if ( $matching_endpoint[0]->is_publicly_documentable() || $proxied || WPCOM_JSON_API__DEBUG ) |
||
299 | $docs[] = call_user_func( array( $matching_endpoint[0], 'generate_documentation' ) ); |
||
300 | } |
||
301 | return $this->output( 200, $docs ); |
||
302 | } else { |
||
303 | status_header( 200 ); |
||
304 | foreach ( $matching_endpoints as $matching_endpoint ) { |
||
305 | if ( $matching_endpoint[0]->is_publicly_documentable() || $proxied || WPCOM_JSON_API__DEBUG ) |
||
306 | call_user_func( array( $matching_endpoint[0], 'document' ) ); |
||
307 | } |
||
308 | } |
||
309 | exit; |
||
310 | } |
||
311 | |||
312 | if ( $endpoint->in_testing && !WPCOM_JSON_API__DEBUG ) { |
||
313 | return $this->output( 404, '', 'text/plain' ); |
||
314 | } |
||
315 | |||
316 | /** This action is documented in class.json-api.php */ |
||
317 | do_action( 'wpcom_json_api_output', $endpoint->stat ); |
||
318 | |||
319 | $response = $this->process_request( $endpoint, $path_pieces ); |
||
320 | |||
321 | if ( !$response && !is_array( $response ) ) { |
||
322 | return $this->output( 500, '', 'text/plain' ); |
||
323 | } elseif ( is_wp_error( $response ) ) { |
||
324 | return $this->output_error( $response ); |
||
325 | } |
||
326 | |||
327 | $output_status_code = $this->output_status_code; |
||
328 | $this->set_output_status_code(); |
||
329 | |||
330 | return $this->output( $output_status_code, $response, 'application/json', $this->extra_headers ); |
||
331 | } |
||
332 | |||
333 | function process_request( WPCOM_JSON_API_Endpoint $endpoint, $path_pieces ) { |
||
334 | $this->endpoint = $endpoint; |
||
335 | return call_user_func_array( array( $endpoint, 'callback' ), $path_pieces ); |
||
336 | } |
||
337 | |||
338 | function output_early( $status_code, $response = null, $content_type = 'application/json' ) { |
||
339 | $exit = $this->exit; |
||
340 | $this->exit = false; |
||
341 | if ( is_wp_error( $response ) ) |
||
342 | $this->output_error( $response ); |
||
343 | else |
||
344 | $this->output( $status_code, $response, $content_type ); |
||
345 | $this->exit = $exit; |
||
346 | if ( ! defined( 'XMLRPC_REQUEST' ) || ! XMLRPC_REQUEST ) { |
||
347 | $this->finish_request(); |
||
348 | } |
||
349 | } |
||
350 | |||
351 | function set_output_status_code( $code = 200 ) { |
||
352 | $this->output_status_code = $code; |
||
353 | } |
||
354 | |||
355 | function output( $status_code, $response = null, $content_type = 'application/json', $extra = array() ) { |
||
356 | // In case output() was called before the callback returned |
||
357 | if ( $this->did_output ) { |
||
358 | if ( $this->exit ) |
||
359 | exit; |
||
360 | return $content_type; |
||
361 | } |
||
362 | $this->did_output = true; |
||
363 | |||
364 | // 400s and 404s are allowed for all origins |
||
365 | if ( 404 == $status_code || 400 == $status_code ) |
||
366 | header( 'Access-Control-Allow-Origin: *' ); |
||
367 | |||
368 | if ( is_null( $response ) ) { |
||
369 | $response = new stdClass; |
||
370 | } |
||
371 | |||
372 | if ( 'text/plain' === $content_type ) { |
||
373 | status_header( (int) $status_code ); |
||
374 | header( 'Content-Type: text/plain' ); |
||
375 | foreach( $extra as $key => $value ) { |
||
376 | header( "$key: $value" ); |
||
377 | } |
||
378 | echo $response; |
||
379 | if ( $this->exit ) { |
||
380 | exit; |
||
381 | } |
||
382 | |||
383 | return $content_type; |
||
384 | } |
||
385 | |||
386 | $response = $this->filter_fields( $response ); |
||
387 | |||
388 | if ( isset( $this->query['http_envelope'] ) && self::is_truthy( $this->query['http_envelope'] ) ) { |
||
389 | $headers = array( |
||
390 | array( |
||
391 | 'name' => 'Content-Type', |
||
392 | 'value' => $content_type, |
||
393 | ) |
||
394 | ); |
||
395 | |||
396 | foreach( $extra as $key => $value ) { |
||
397 | $headers[] = array( 'name' => $key, 'value' => $value ); |
||
398 | } |
||
399 | |||
400 | $response = array( |
||
401 | 'code' => (int) $status_code, |
||
402 | 'headers' => $headers, |
||
403 | 'body' => $response, |
||
404 | ); |
||
405 | $status_code = 200; |
||
406 | $content_type = 'application/json'; |
||
407 | } |
||
408 | |||
409 | status_header( (int) $status_code ); |
||
410 | header( "Content-Type: $content_type" ); |
||
411 | if ( isset( $this->query['callback'] ) && is_string( $this->query['callback'] ) ) { |
||
412 | $callback = preg_replace( '/[^a-z0-9_.]/i', '', $this->query['callback'] ); |
||
413 | } else { |
||
414 | $callback = false; |
||
415 | } |
||
416 | |||
417 | if ( $callback ) { |
||
418 | // Mitigate Rosetta Flash [1] by setting the Content-Type-Options: nosniff header |
||
419 | // and by prepending the JSONP response with a JS comment. |
||
420 | // [1] http://miki.it/blog/2014/7/8/abusing-jsonp-with-rosetta-flash/ |
||
421 | echo "/**/$callback("; |
||
422 | |||
423 | } |
||
424 | echo $this->json_encode( $response ); |
||
425 | if ( $callback ) { |
||
426 | echo ");"; |
||
427 | } |
||
428 | |||
429 | if ( $this->exit ) { |
||
430 | exit; |
||
431 | } |
||
432 | |||
433 | return $content_type; |
||
434 | } |
||
435 | |||
436 | public static function serializable_error ( $error ) { |
||
437 | |||
438 | $status_code = $error->get_error_data(); |
||
439 | |||
440 | if ( is_array( $status_code ) ) |
||
441 | $status_code = $status_code['status_code']; |
||
442 | |||
443 | if ( !$status_code ) { |
||
444 | $status_code = 400; |
||
445 | } |
||
446 | $response = array( |
||
447 | 'error' => $error->get_error_code(), |
||
448 | 'message' => $error->get_error_message(), |
||
449 | ); |
||
450 | return array( |
||
451 | 'status_code' => $status_code, |
||
452 | 'errors' => $response |
||
453 | ); |
||
454 | } |
||
455 | |||
456 | function output_error( $error ) { |
||
457 | $error_response = $this->serializable_error( $error ); |
||
458 | |||
459 | return $this->output( $error_response[ 'status_code'], $error_response['errors'] ); |
||
460 | } |
||
461 | |||
462 | function filter_fields( $response ) { |
||
463 | if ( empty( $this->query['fields'] ) || ( is_array( $response ) && ! empty( $response['error'] ) ) || ! empty( $this->endpoint->custom_fields_filtering ) ) |
||
464 | return $response; |
||
465 | |||
466 | $fields = array_map( 'trim', explode( ',', $this->query['fields'] ) ); |
||
467 | |||
468 | if ( is_object( $response ) ) { |
||
469 | $response = (array) $response; |
||
470 | } |
||
471 | |||
472 | $has_filtered = false; |
||
473 | if ( is_array( $response ) && empty( $response['ID'] ) ) { |
||
474 | $keys_to_filter = array( |
||
475 | 'categories', |
||
476 | 'comments', |
||
477 | 'connections', |
||
478 | 'domains', |
||
479 | 'groups', |
||
480 | 'likes', |
||
481 | 'media', |
||
482 | 'notes', |
||
483 | 'posts', |
||
484 | 'services', |
||
485 | 'sites', |
||
486 | 'suggestions', |
||
487 | 'tags', |
||
488 | 'themes', |
||
489 | 'topics', |
||
490 | 'users', |
||
491 | ); |
||
492 | |||
493 | foreach ( $keys_to_filter as $key_to_filter ) { |
||
494 | if ( ! isset( $response[ $key_to_filter ] ) || $has_filtered ) |
||
495 | continue; |
||
496 | |||
497 | foreach ( $response[ $key_to_filter ] as $key => $values ) { |
||
498 | if ( is_object( $values ) ) { |
||
499 | $response[ $key_to_filter ][ $key ] = (object) array_intersect_key( (array) $values, array_flip( $fields ) ); |
||
500 | } elseif ( is_array( $values ) ) { |
||
501 | $response[ $key_to_filter ][ $key ] = array_intersect_key( $values, array_flip( $fields ) ); |
||
502 | } |
||
503 | } |
||
504 | |||
505 | $has_filtered = true; |
||
506 | } |
||
507 | } |
||
508 | |||
509 | if ( ! $has_filtered ) { |
||
510 | if ( is_object( $response ) ) { |
||
511 | $response = (object) array_intersect_key( (array) $response, array_flip( $fields ) ); |
||
512 | } else if ( is_array( $response ) ) { |
||
513 | $response = array_intersect_key( $response, array_flip( $fields ) ); |
||
514 | } |
||
515 | } |
||
516 | |||
517 | return $response; |
||
518 | } |
||
519 | |||
520 | function ensure_http_scheme_of_home_url( $url, $path, $original_scheme ) { |
||
521 | if ( $original_scheme ) { |
||
522 | return $url; |
||
523 | } |
||
524 | |||
525 | return preg_replace( '#^https:#', 'http:', $url ); |
||
526 | } |
||
527 | |||
528 | function comment_edit_pre( $comment_content ) { |
||
529 | return htmlspecialchars_decode( $comment_content, ENT_QUOTES ); |
||
530 | } |
||
531 | |||
532 | function json_encode( $data ) { |
||
533 | return json_encode( $data ); |
||
534 | } |
||
535 | |||
536 | function ends_with( $haystack, $needle ) { |
||
537 | return $needle === substr( $haystack, -strlen( $needle ) ); |
||
538 | } |
||
539 | |||
540 | // Returns the site's blog_id in the WP.com ecosystem |
||
541 | function get_blog_id_for_output() { |
||
542 | return $this->token_details['blog_id']; |
||
543 | } |
||
544 | |||
545 | // Returns the site's local blog_id |
||
546 | function get_blog_id( $blog_id ) { |
||
547 | return $GLOBALS['blog_id']; |
||
548 | } |
||
549 | |||
550 | function switch_to_blog_and_validate_user( $blog_id = 0, $verify_token_for_blog = true ) { |
||
551 | if ( $this->is_restricted_blog( $blog_id ) ) { |
||
552 | return new WP_Error( 'unauthorized', 'User cannot access this restricted blog', 403 ); |
||
553 | } |
||
554 | |||
555 | if ( -1 == get_option( 'blog_public' ) && !current_user_can( 'read' ) ) { |
||
556 | return new WP_Error( 'unauthorized', 'User cannot access this private blog.', 403 ); |
||
557 | } |
||
558 | |||
559 | return $blog_id; |
||
560 | } |
||
561 | |||
562 | // Returns true if the specified blog ID is a restricted blog |
||
563 | function is_restricted_blog( $blog_id ) { |
||
564 | /** |
||
565 | * Filters all REST API access and return a 403 unauthorized response for all Restricted blog IDs. |
||
566 | * |
||
567 | * @module json-api |
||
568 | * |
||
569 | * @since 3.4.0 |
||
570 | * |
||
571 | * @param array $array Array of Blog IDs. |
||
572 | */ |
||
573 | $restricted_blog_ids = apply_filters( 'wpcom_json_api_restricted_blog_ids', array() ); |
||
574 | return true === in_array( $blog_id, $restricted_blog_ids ); |
||
575 | } |
||
576 | |||
577 | function post_like_count( $blog_id, $post_id ) { |
||
578 | return 0; |
||
579 | } |
||
580 | |||
581 | function is_liked( $blog_id, $post_id ) { |
||
582 | return false; |
||
583 | } |
||
584 | |||
585 | function is_reblogged( $blog_id, $post_id ) { |
||
586 | return false; |
||
587 | } |
||
588 | |||
589 | function is_following( $blog_id ) { |
||
590 | return false; |
||
591 | } |
||
592 | |||
593 | function add_global_ID( $blog_id, $post_id ) { |
||
594 | return ''; |
||
595 | } |
||
596 | |||
597 | function get_avatar_url( $email, $avatar_size = null ) { |
||
598 | if ( function_exists( 'wpcom_get_avatar_url' ) ) { |
||
599 | return null === $avatar_size |
||
600 | ? wpcom_get_avatar_url( $email ) |
||
601 | : wpcom_get_avatar_url( $email, $avatar_size ); |
||
602 | } else { |
||
603 | return null === $avatar_size |
||
604 | ? get_avatar_url( $email ) |
||
605 | : get_avatar_url( $email, $avatar_size ); |
||
606 | } |
||
607 | } |
||
608 | |||
609 | /** |
||
610 | * traps `wp_die()` calls and outputs a JSON response instead. |
||
611 | * The result is always output, never returned. |
||
612 | * |
||
613 | * @param string|null $error_code Call with string to start the trapping. Call with null to stop. |
||
614 | * @param int $http_status HTTP status code, 400 by default. |
||
615 | */ |
||
616 | function trap_wp_die( $error_code = null, $http_status = 400 ) { |
||
617 | if ( is_null( $error_code ) ) { |
||
618 | $this->trapped_error = null; |
||
619 | // Stop trapping |
||
620 | remove_filter( 'wp_die_handler', array( $this, 'wp_die_handler_callback' ) ); |
||
621 | return; |
||
622 | } |
||
623 | |||
624 | // If API called via PHP, bail: don't do our custom wp_die(). Do the normal wp_die(). |
||
625 | if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { |
||
626 | if ( ! defined( 'REST_API_REQUEST' ) || ! REST_API_REQUEST ) { |
||
627 | return; |
||
628 | } |
||
629 | } else { |
||
630 | if ( ! defined( 'XMLRPC_REQUEST' ) || ! XMLRPC_REQUEST ) { |
||
631 | return; |
||
632 | } |
||
633 | } |
||
634 | |||
635 | $this->trapped_error = array( |
||
636 | 'status' => $http_status, |
||
637 | 'code' => $error_code, |
||
638 | 'message' => '', |
||
639 | ); |
||
640 | // Start trapping |
||
641 | add_filter( 'wp_die_handler', array( $this, 'wp_die_handler_callback' ) ); |
||
642 | } |
||
643 | |||
644 | function wp_die_handler_callback() { |
||
645 | return array( $this, 'wp_die_handler' ); |
||
646 | } |
||
647 | |||
648 | function wp_die_handler( $message, $title = '', $args = array() ) { |
||
649 | // Allow wp_die calls to override HTTP status code... |
||
650 | $args = wp_parse_args( $args, array( |
||
651 | 'response' => $this->trapped_error['status'], |
||
652 | ) ); |
||
653 | |||
654 | // ... unless it's 500 ( see http://wp.me/pMz3w-5VV ) |
||
655 | if ( (int) $args['response'] !== 500 ) { |
||
656 | $this->trapped_error['status'] = $args['response']; |
||
657 | } |
||
658 | |||
659 | if ( $title ) { |
||
660 | $message = "$title: $message"; |
||
661 | } |
||
662 | |||
663 | $this->trapped_error['message'] = wp_kses( $message, array() ); |
||
664 | |||
665 | switch ( $this->trapped_error['code'] ) { |
||
666 | case 'comment_failure' : |
||
667 | if ( did_action( 'comment_duplicate_trigger' ) ) { |
||
668 | $this->trapped_error['code'] = 'comment_duplicate'; |
||
669 | } else if ( did_action( 'comment_flood_trigger' ) ) { |
||
670 | $this->trapped_error['code'] = 'comment_flood'; |
||
671 | } |
||
672 | break; |
||
673 | } |
||
674 | |||
675 | // We still want to exit so that code execution stops where it should. |
||
676 | // Attach the JSON output to the WordPress shutdown handler |
||
677 | add_action( 'shutdown', array( $this, 'output_trapped_error' ), 0 ); |
||
678 | exit; |
||
679 | } |
||
680 | |||
681 | function output_trapped_error() { |
||
688 | |||
689 | function finish_request() { |
||
693 | } |
||
694 |
PHP has two types of connecting operators (logical operators, and boolean operators):
and
&&
or
||
The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like
&&
, or||
.Let’s take a look at a few examples:
Logical Operators are used for Control-Flow
One case where you explicitly want to use logical operators is for control-flow such as this:
Since
die
introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined withthrow
at this point:These limitations lead to logical operators rarely being of use in current PHP code.