PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 9.2
Jetpack – WP Security, Backup, Speed, & Growth v9.2
16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 All 501 releases
jetpack / sal / class.json-api-site-base.php
class.json-api-site-base.php
693 lines 17.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 require_once dirname( __FILE__ ) . '/class.json-api-date.php';
4 require_once dirname( __FILE__ ) . '/class.json-api-post-base.php';
5
6 /**
7 * Base class for the Site Abstraction Layer (SAL)
8 * Note that this is the site "as seen by user $user_id with token $token", which
9 * is why we pass the token to the platform; these site instances are value objects
10 * to be used in the context of a single request for a single user.
11 * Also note that at present this class _assumes_ you've "switched to"
12 * the site in question, and functions like `get_bloginfo( 'name' )` will
13 * therefore return the correct value
14 **/
15 abstract class SAL_Site {
16 public $blog_id;
17 public $platform;
18
19 public function __construct( $blog_id, $platform ) {
20 $this->blog_id = $blog_id;
21 $this->platform = $platform;
22 }
23
24 public function get_id() {
25 return $this->blog_id;
26 }
27
28 public function get_name() {
29 return (string) htmlspecialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES );
30 }
31
32 public function get_description() {
33 return (string) htmlspecialchars_decode( get_bloginfo( 'description' ), ENT_QUOTES );
34 }
35
36 public function get_url() {
37 return (string) home_url();
38 }
39
40 public function get_post_count() {
41 return (int) wp_count_posts( 'post' )->publish;
42 }
43
44 public function get_quota() {
45 return null;
46 }
47
48 abstract public function has_videopress();
49
50 abstract public function upgraded_filetypes_enabled();
51
52 abstract public function is_mapped_domain();
53
54 abstract public function get_unmapped_url();
55
56 abstract public function is_redirect();
57
58 abstract public function is_headstart_fresh();
59
60 abstract public function featured_images_enabled();
61
62 abstract public function has_wordads();
63
64 abstract public function get_frame_nonce();
65
66 abstract public function get_jetpack_frame_nonce();
67
68 abstract public function allowed_file_types();
69
70 abstract public function get_post_formats();
71
72 abstract public function is_private();
73
74 abstract public function is_coming_soon();
75
76 abstract public function is_following();
77
78 abstract public function get_subscribers_count();
79
80 abstract public function get_locale();
81
82 /**
83 * The flag indicates that the site has Jetpack installed
84 *
85 * @return bool
86 */
87 abstract public function is_jetpack();
88
89 /**
90 * The flag indicates that the site is connected to WP.com via Jetpack Connection
91 *
92 * @return bool
93 */
94 abstract public function is_jetpack_connection();
95
96 abstract public function get_jetpack_modules();
97
98 abstract public function is_module_active( $module );
99
100 abstract public function is_vip();
101
102 abstract public function is_multisite();
103
104 abstract public function is_single_user_site();
105
106 abstract public function get_plan();
107
108 abstract public function get_ak_vp_bundle_enabled();
109
110 abstract public function get_podcasting_archive();
111
112 abstract public function get_import_engine();
113
114 abstract public function get_jetpack_seo_front_page_description();
115
116 abstract public function get_jetpack_seo_title_formats();
117
118 abstract public function get_verification_services_codes();
119
120 abstract public function before_render();
121
122 abstract public function after_render( &$response );
123
124 // TODO - factor this out? Seems an odd thing to have on a site
125 abstract public function after_render_options( &$options );
126
127 // wrap a WP_Post object with SAL methods
128 abstract public function wrap_post( $post, $context );
129
130 abstract protected function is_a8c_publication( $post_id );
131
132 public function is_automated_transfer() {
133 /**
134 * Filter if a site is an automated-transfer site.
135 *
136 * @module json-api
137 *
138 * @since 6.4.0
139 *
140 * @param bool is_automated_transfer( $this->blog_id )
141 * @param int $blog_id Blog identifier.
142 */
143 return apply_filters(
144 'jetpack_site_automated_transfer',
145 false,
146 $this->blog_id
147 );
148 }
149
150 abstract protected function is_wpforteams_site();
151
152 public function is_wpcom_atomic() {
153 return false;
154 }
155
156 public function is_wpcom_store() {
157 return false;
158 }
159
160 public function woocommerce_is_active() {
161 return false;
162 }
163
164 public function is_cloud_eligible() {
165 return false;
166 }
167
168 public function get_products() {
169 return array();
170 }
171
172 public function get_post_by_id( $post_id, $context ) {
173 $post = get_post( $post_id, OBJECT, $context );
174
175 if ( ! $post ) {
176 return new WP_Error( 'unknown_post', 'Unknown post', 404 );
177 }
178
179 $wrapped_post = $this->wrap_post( $post, $context );
180
181 // validate access
182 return $this->validate_access( $wrapped_post );
183 }
184
185 /**
186 * Validate current user can access the post
187 *
188 * @return WP_Error or post
189 */
190 private function validate_access( $post ) {
191 $context = $post->context;
192
193 if (
194 ! $this->is_post_type_allowed( $post->post_type )
195 && ! $this->is_a8c_publication( $post->ID )
196 ) {
197 return new WP_Error( 'unknown_post', 'Unknown post', 404 );
198 }
199
200 switch ( $context ) {
201 case 'edit' :
202 if ( ! current_user_can( 'edit_post', $post->ID ) ) {
203 return new WP_Error( 'unauthorized', 'User cannot edit post', 403 );
204 }
205 break;
206 case 'display' :
207 $can_view = $this->user_can_view_post( $post );
208 if ( is_wp_error( $can_view ) ) {
209 return $can_view;
210 }
211 break;
212 default :
213 return new WP_Error( 'invalid_context', 'Invalid API CONTEXT', 400 );
214 }
215
216 return $post;
217 }
218
219 public function current_user_can_access_post_type( $post_type, $context ) {
220 $post_type_object = $this->get_post_type_object( $post_type );
221 if ( ! $post_type_object ) {
222 return false;
223 }
224
225 switch( $context ) {
226 case 'edit':
227 return current_user_can( $post_type_object->cap->edit_posts );
228 case 'display':
229 return $post_type_object->public || current_user_can( $post_type_object->cap->read_private_posts );
230 default:
231 return false;
232 }
233 }
234
235 protected function get_post_type_object( $post_type ) {
236 return get_post_type_object( $post_type );
237 }
238
239 // copied from class.json-api-endpoints.php
240 public function is_post_type_allowed( $post_type ) {
241 // if the post type is empty, that's fine, WordPress will default to post
242 if ( empty( $post_type ) ) {
243 return true;
244 }
245
246 // allow special 'any' type
247 if ( 'any' == $post_type ) {
248 return true;
249 }
250
251 // check for allowed types
252 if ( in_array( $post_type, $this->get_whitelisted_post_types() ) ) {
253 return true;
254 }
255
256 if ( $post_type_object = get_post_type_object( $post_type ) ) {
257 if ( ! empty( $post_type_object->show_in_rest ) ) {
258 return $post_type_object->show_in_rest;
259 }
260 if ( ! empty( $post_type_object->publicly_queryable ) ) {
261 return $post_type_object->publicly_queryable;
262 }
263 }
264
265 return ! empty( $post_type_object->public );
266 }
267
268 // copied from class.json-api-endpoints.php
269 /**
270 * Gets the whitelisted post types that JP should allow access to.
271 *
272 * @return array Whitelisted post types.
273 */
274 public function get_whitelisted_post_types() {
275 $allowed_types = array( 'post', 'page', 'revision' );
276
277 /**
278 * Filter the post types Jetpack has access to, and can synchronize with WordPress.com.
279 *
280 * @module json-api
281 *
282 * @since 2.2.3
283 *
284 * @param array $allowed_types Array of whitelisted post types. Default to `array( 'post', 'page', 'revision' )`.
285 */
286 $allowed_types = apply_filters( 'rest_api_allowed_post_types', $allowed_types );
287
288 return array_unique( $allowed_types );
289 }
290
291 // copied and modified a little from class.json-api-endpoints.php
292 private function user_can_view_post( $post ) {
293 if ( !$post || is_wp_error( $post ) ) {
294 return false;
295 }
296
297 if ( 'inherit' === $post->post_status ) {
298 $parent_post = get_post( $post->post_parent );
299 $post_status_obj = get_post_status_object( $parent_post->post_status );
300 } else {
301 $post_status_obj = get_post_status_object( $post->post_status );
302 }
303
304 $authorized = (
305 $post_status_obj->public ||
306 ( is_user_logged_in() &&
307 (
308 ( $post_status_obj->protected && current_user_can( 'edit_post', $post->ID ) ) ||
309 ( $post_status_obj->private && current_user_can( 'read_post', $post->ID ) ) ||
310 ( 'trash' === $post->post_status && current_user_can( 'edit_post', $post->ID ) ) ||
311 'auto-draft' === $post->post_status
312 )
313 )
314 );
315
316 if ( ! $authorized ) {
317 return new WP_Error( 'unauthorized', 'User cannot view post', 403 );
318 }
319
320 if (
321 -1 == get_option( 'blog_public' ) &&
322 /**
323 * Filter access to a specific post.
324 *
325 * @module json-api
326 *
327 * @since 3.4.0
328 *
329 * @param bool current_user_can( 'read_post', $post->ID ) Can the current user access the post.
330 * @param WP_Post $post Post data.
331 */
332 ! apply_filters(
333 'wpcom_json_api_user_can_view_post',
334 current_user_can( 'read_post', $post->ID ),
335 $post
336 )
337 ) {
338 return new WP_Error( 'unauthorized', 'User cannot view post', array( 'status_code' => 403, 'error' => 'private_blog' ) );
339 }
340
341 if ( strlen( $post->post_password ) && !current_user_can( 'edit_post', $post->ID ) ) {
342 return new WP_Error( 'unauthorized', 'User cannot view password protected post', array( 'status_code' => 403, 'error' => 'password_protected' ) );
343 }
344
345 return true;
346 }
347
348 /**
349 * Get post ID by name
350 *
351 * Attempts to match name on post title and page path
352 *
353 * @param string $name
354 *
355 * @return int|object Post ID on success, WP_Error object on failure
356 */
357 public function get_post_id_by_name( $name ) {
358 $name = sanitize_title( $name );
359
360 if ( ! $name ) {
361 return new WP_Error( 'invalid_post', 'Invalid post', 400 );
362 }
363
364 $posts = get_posts( array(
365 'name' => $name,
366 'numberposts' => 1,
367 'post_type' => $this->get_whitelisted_post_types(),
368 ) );
369
370 if ( ! $posts || ! isset( $posts[0]->ID ) || ! $posts[0]->ID ) {
371 $page = get_page_by_path( $name );
372
373 if ( ! $page ) {
374 return new WP_Error( 'unknown_post', 'Unknown post', 404 );
375 }
376
377 return $page->ID;
378 }
379
380 return (int) $posts[0]->ID;
381 }
382
383 /**
384 * Get post by name
385 *
386 * Attempts to match name on post title and page path
387 *
388 * @param string $name
389 * @param string $context (display or edit)
390 *
391 * @return object Post object on success, WP_Error object on failure
392 **/
393 public function get_post_by_name( $name, $context ) {
394 $post_id = $this->get_post_id_by_name( $name );
395 if ( is_wp_error( $post_id ) ) {
396 return $post_id;
397 }
398
399 return $this->get_post_by_id( $post_id, $context );
400 }
401
402 function user_can_manage() {
403 current_user_can( 'manage_options' );
404 }
405
406 function get_xmlrpc_url() {
407 $xmlrpc_scheme = apply_filters( 'wpcom_json_api_xmlrpc_scheme', wp_parse_url( get_option( 'home' ), PHP_URL_SCHEME ) );
408 return site_url( 'xmlrpc.php', $xmlrpc_scheme );
409 }
410
411 function get_registered_date() {
412 if ( function_exists( 'get_blog_details' ) ) {
413 $blog_details = get_blog_details();
414 if ( ! empty( $blog_details->registered ) ) {
415 return WPCOM_JSON_API_Date::format_date( $blog_details->registered );
416 }
417 }
418
419 return '0000-00-00T00:00:00+00:00';
420 }
421
422 function get_capabilities() {
423 $is_wpcom_blog_owner = wpcom_get_blog_owner() === (int) get_current_user_id();
424
425 return array(
426 'edit_pages' => current_user_can( 'edit_pages' ),
427 'edit_posts' => current_user_can( 'edit_posts' ),
428 'edit_others_posts' => current_user_can( 'edit_others_posts' ),
429 'edit_others_pages' => current_user_can( 'edit_others_pages' ),
430 'delete_posts' => current_user_can( 'delete_posts' ),
431 'delete_others_posts' => current_user_can( 'delete_others_posts' ),
432 'edit_theme_options' => current_user_can( 'edit_theme_options' ),
433 'edit_users' => current_user_can( 'edit_users' ),
434 'list_users' => current_user_can( 'list_users' ),
435 'manage_categories' => current_user_can( 'manage_categories' ),
436 'manage_options' => current_user_can( 'manage_options' ),
437 'moderate_comments' => current_user_can( 'moderate_comments' ),
438 'activate_wordads' => $is_wpcom_blog_owner,
439 'promote_users' => current_user_can( 'promote_users' ),
440 'publish_posts' => current_user_can( 'publish_posts' ),
441 'upload_files' => current_user_can( 'upload_files' ),
442 'delete_users' => current_user_can( 'delete_users' ),
443 'remove_users' => current_user_can( 'remove_users' ),
444 'own_site' => $is_wpcom_blog_owner,
445 /**
446 * Filter whether the Hosting section in Calypso should be available for site.
447 *
448 * @module json-api
449 *
450 * @since 8.2.0
451 *
452 * @param bool $view_hosting Can site access Hosting section. Default to false.
453 */
454 'view_hosting' => apply_filters( 'jetpack_json_api_site_can_view_hosting', false ),
455 'view_stats' => stats_is_blog_user( $this->blog_id )
456 );
457 }
458
459 function is_visible() {
460 if ( is_user_logged_in() ) {
461 $current_user = wp_get_current_user();
462 $visible = (array) get_user_meta( $current_user->ID, 'blog_visibility', true );
463
464 $is_visible = true;
465 if ( isset( $visible[ $this->blog_id ] ) ) {
466 $is_visible = (bool) $visible[ $this->blog_id ];
467 }
468
469 // null and true are visible
470 return $is_visible;
471 }
472
473 return null;
474 }
475
476 function get_logo() {
477
478 // Set an empty response array.
479 $logo_setting = array(
480 'id' => (int) 0,
481 'sizes' => array(),
482 'url' => '',
483 );
484
485 // Get current site logo values.
486 $logo = get_option( 'site_logo' );
487
488 // Update the response array if there's a site logo currenty active.
489 if ( $logo && 0 != $logo['id'] ) {
490 $logo_setting['id'] = $logo['id'];
491 $logo_setting['url'] = $logo['url'];
492
493 foreach ( $logo['sizes'] as $size => $properties ) {
494 $logo_setting['sizes'][ $size ] = $properties;
495 }
496 }
497
498 return $logo_setting;
499 }
500
501 function get_timezone() {
502 return (string) get_option( 'timezone_string' );
503 }
504
505 function get_gmt_offset() {
506 return (float) get_option( 'gmt_offset' );
507 }
508
509 function get_login_url() {
510 return wp_login_url();
511 }
512
513 function get_admin_url() {
514 return get_admin_url();
515 }
516
517 function get_theme_slug() {
518 return get_option( 'stylesheet' );
519 }
520
521 function get_header_image() {
522 return get_theme_mod( 'header_image_data' );
523 }
524
525 function get_background_color() {
526 return get_theme_mod( 'background_color' );
527 }
528
529 function get_image_default_link_type() {
530 return get_option( 'image_default_link_type' );
531 }
532
533 function get_image_thumbnail_width() {
534 return (int) get_option( 'thumbnail_size_w' );
535 }
536
537 function get_image_thumbnail_height() {
538 return (int) get_option( 'thumbnail_size_h' );
539 }
540
541 function get_image_thumbnail_crop() {
542 return get_option( 'thumbnail_crop' );
543 }
544
545 function get_image_medium_width() {
546 return (int) get_option( 'medium_size_w' );
547 }
548
549 function get_image_medium_height() {
550 return (int) get_option( 'medium_size_h' );
551 }
552
553 function get_image_large_width() {
554 return (int) get_option( 'large_size_w' );
555 }
556
557 function get_image_large_height() {
558 return (int) get_option( 'large_size_h' );
559 }
560
561 function get_permalink_structure() {
562 return get_option( 'permalink_structure' );
563 }
564
565 function get_default_post_format() {
566 return get_option( 'default_post_format' );
567 }
568
569 function get_default_category() {
570 return (int) get_option( 'default_category' );
571 }
572
573 function get_show_on_front() {
574 return get_option( 'show_on_front' );
575 }
576
577 function is_custom_front_page() {
578 return ( 'page' === $this->get_show_on_front() );
579 }
580
581 function get_default_likes_enabled() {
582 return (bool) apply_filters( 'wpl_is_enabled_sitewide', ! get_option( 'disabled_likes' ) );
583 }
584
585 function get_default_sharing_status() {
586 $default_sharing_status = false;
587 if ( class_exists( 'Sharing_Service' ) ) {
588 $ss = new Sharing_Service();
589 $blog_services = $ss->get_blog_services();
590 $default_sharing_status = ! empty( $blog_services['visible'] );
591 }
592 return (bool) $default_sharing_status;
593 }
594
595 function get_default_comment_status() {
596 return 'closed' !== get_option( 'default_comment_status' );
597 }
598
599 function default_ping_status() {
600 return 'closed' !== get_option( 'default_ping_status' );
601 }
602
603 function is_publicize_permanently_disabled() {
604 $publicize_permanently_disabled = false;
605 if ( function_exists( 'is_publicize_permanently_disabled' ) ) {
606 $publicize_permanently_disabled = is_publicize_permanently_disabled( $this->blog_id );
607 }
608 return $publicize_permanently_disabled;
609 }
610
611 function get_page_on_front() {
612 return (int) get_option( 'page_on_front' );
613 }
614
615 function get_page_for_posts() {
616 return (int) get_option( 'page_for_posts' );
617 }
618
619 function is_headstart() {
620 return get_option( 'headstart' );
621 }
622
623 function get_wordpress_version() {
624 global $wp_version;
625 return $wp_version;
626 }
627
628 function is_domain_only() {
629 $options = get_option( 'options' );
630 return ! empty ( $options['is_domain_only'] ) ? (bool) $options['is_domain_only'] : false;
631 }
632
633 function get_blog_public() {
634 return (int) get_option( 'blog_public' );
635 }
636
637 function has_pending_automated_transfer() {
638 /**
639 * Filter if a site is in pending automated transfer state.
640 *
641 * @module json-api
642 *
643 * @since 6.4.0
644 *
645 * @param bool has_site_pending_automated_transfer( $this->blog_id )
646 * @param int $blog_id Blog identifier.
647 */
648 return apply_filters(
649 'jetpack_site_pending_automated_transfer',
650 false,
651 $this->blog_id
652 );
653 }
654
655 function signup_is_store() {
656 return $this->get_design_type() === 'store';
657 }
658
659 function get_roles() {
660 return new WP_Roles();
661 }
662
663 function get_design_type() {
664 $options = get_option( 'options' );
665 return empty( $options[ 'designType'] ) ? null : $options[ 'designType' ];
666 }
667
668 function get_site_goals() {
669 $options = get_option( 'options' );
670 return empty( $options[ 'siteGoals'] ) ? null : $options[ 'siteGoals' ];
671 }
672
673 function get_launch_status() {
674 return false;
675 }
676
677 function get_migration_meta() {
678 return null;
679 }
680
681 function get_site_segment() {
682 return false;
683 }
684
685 function get_site_creation_flow() {
686 return get_option( 'site_creation_flow' );
687 }
688
689 public function get_selected_features() {
690 return get_option( 'selected_features' );
691 }
692 }
693