PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 14.2
Jetpack – WP Security, Backup, Speed, & Growth v14.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 in Jetpack – WP Security, Backup, Speed, & Growth 14.2, at sal/class.json-api-site-base.php

1,689 lines 43.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2 /**
3 * This file defines the base class for the Site Abstraction Layer (SAL).
4 * Note that this is the site "as seen by user $user_id with token $token", which
5 * is why we pass the token to the platform; these site instances are value objects
6 * to be used in the context of a single request for a single user.
7 * Also note that at present this class _assumes_ you've "switched to"
8 * the site in question, and functions like `get_bloginfo( 'name' )` will
9 * therefore return the correct value.
10 *
11 * @package automattic/jetpack
12 **/
13
14 use Automattic\Jetpack\Blaze;
15 use Automattic\Jetpack\Status;
16 use Automattic\Jetpack\Status\Host;
17
18 require_once __DIR__ . '/class.json-api-date.php';
19 require_once __DIR__ . '/class.json-api-post-base.php';
20
21 /**
22 * Base class for SAL_Site.
23 * The abstract functions here are extended by Abstract_Jetpack_Site in class.json-api-site-jetpack-base.php.
24 */
25 abstract class SAL_Site {
26
27 /**
28 * The Jetpack blog ID for the site.
29 *
30 * @var int
31 */
32 public $blog_id;
33
34 /**
35 * A new WPORG_Platform instance.
36 *
37 * @see class.json-api-platform-jetpack.php.
38 *
39 * @var WPORG_Platform
40 */
41 public $platform;
42
43 /**
44 * Contructs the SAL_Site instance.
45 *
46 * @param int $blog_id The Jetpack blog ID for the site.
47 * @param WPORG_Platform $platform A new WPORG_Platform instance.
48 */
49 public function __construct( $blog_id, $platform ) {
50 $this->blog_id = $blog_id;
51 $this->platform = $platform;
52 }
53
54 /**
55 * Get the blog_id property.
56 *
57 * @return int
58 */
59 public function get_id() {
60 return $this->blog_id;
61 }
62
63 /**
64 * Returns the site name.
65 *
66 * @return string
67 */
68 public function get_name() {
69 return (string) htmlspecialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES );
70 }
71
72 /**
73 * Returns the site description.
74 *
75 * @return string
76 */
77 public function get_description() {
78 return (string) htmlspecialchars_decode( get_bloginfo( 'description' ), ENT_QUOTES );
79 }
80
81 /**
82 * Returns the URL for the current site.
83 *
84 * @return string
85 */
86 public function get_url() {
87 return (string) home_url();
88 }
89
90 /**
91 * Returns the number of published posts with the 'post' post-type.
92 *
93 * @return int
94 */
95 public function get_post_count() {
96 return (int) wp_count_posts( 'post' )->publish;
97 }
98
99 /**
100 * A prototype function for get_quota - currently returns null.
101 *
102 * @return null
103 */
104 public function get_quota() {
105 return null;
106 }
107
108 /**
109 * Returns an array of blogging prompt settings. Only applicable on WordPress.com.
110 *
111 * Data comes from .com since the fearture requires a .com connection to work.
112 *
113 * @param int $user_id the current user_id.
114 * @param int $blog_id the blog id in this context.
115 */
116 public function get_blogging_prompts_settings( $user_id, $blog_id ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
117 return false;
118 }
119
120 /**
121 * Returns true if a site has the 'videopress' option enabled, false otherwise.
122 *
123 * @see class.json-api-site-jetpack.php for implementation.
124 */
125 abstract public function has_videopress();
126
127 /**
128 * Returns VideoPress storage used, in MB.
129 *
130 * @see class.json-api-site-jetpack-shadow.php on WordPress.com for implementation. Only applicable on WordPress.com.
131 */
132 abstract public function get_videopress_storage_used();
133
134 /**
135 * Sets the upgraded_filetypes_enabled Jetpack option to true as a default. Only relevant for WordPress.com sites.
136 *
137 * @see class.json-api-site-jetpack.php for implementation.
138 */
139 abstract public function upgraded_filetypes_enabled();
140
141 /**
142 * Sets the is_mapped_domain Jetpack option to true as a default.
143 *
144 * Primarily used in WordPress.com to confirm the current blog's domain does or doesn't match the primary redirect.
145 *
146 * @see class.json-api-site-jetpack.php for implementation.
147 */
148 abstract public function is_mapped_domain();
149
150 /**
151 * Fallback to the home URL since all Jetpack sites don't have an unmapped *.wordpress.com domain.
152 *
153 * @see class.json-api-site-jetpack.php for implementation.
154 */
155 abstract public function get_unmapped_url();
156
157 /**
158 * Whether the domain is a site redirect or not. Defaults to false on a Jetpack site.
159 *
160 * Primarily used in WordPress.com where it is determined if a HTTP status check is a redirect or not and whether an exception should be thrown.
161 *
162 * @see class.json-api-site-jetpack.php for implementation.
163 */
164 abstract public function is_redirect();
165
166 /**
167 * Defaults to false on Jetpack sites, however is used on WordPress.com sites, where it returns true if the headstart-fresh blog sticker is present.
168 *
169 * @see class.json-api-site-jetpack.php for implementation.
170 */
171 abstract public function is_headstart_fresh();
172
173 /**
174 * If the site's current theme supports post thumbnails, return true (otherwise return false).
175 *
176 * @see class.json-api-site-jetpack-base.php for implementation.
177 */
178 abstract public function featured_images_enabled();
179
180 /**
181 * Whether or not the Jetpack 'wordads' module is active on the site.
182 *
183 * @see class.json-api-site-jetpack.php for implementation.
184 */
185 abstract public function has_wordads();
186
187 /**
188 * Defaults to false on Jetpack sites, however is used on WordPress.com sites. This nonce is used for previews on Jetpack sites.
189 *
190 * @see class.json-api-site-jetpack.php for implementation.
191 */
192 abstract public function get_frame_nonce();
193
194 /**
195 * Defaults to false on Jetpack sites, however is used on WordPress.com sites where
196 * it creates a nonce to be used with iframed block editor requests to a Jetpack site.
197 *
198 * @see class.json-api-site-jetpack.php for implementation.
199 */
200 abstract public function get_jetpack_frame_nonce();
201
202 /**
203 * Returns the allowed mime types and file extensions for a site.
204 *
205 * @see class.json-api-site-jetpack.php for implementation.
206 */
207 abstract public function allowed_file_types();
208
209 /**
210 * Returns an array of supported post formats.
211 *
212 * @see class.json-api-site-jetpack-base.php for implementation.
213 */
214 abstract public function get_post_formats();
215
216 /**
217 * Return site's privacy status.
218 *
219 * @see class.json-api-site-jetpack.php for implementation.
220 */
221 abstract public function is_private();
222
223 /**
224 * Return site's coming soon status.
225 *
226 * @see class.json-api-site-jetpack.php for implementation.
227 */
228 abstract public function is_coming_soon();
229
230 /**
231 * Whether or not the current user is following this blog. Defaults to false.
232 *
233 * @see class.json-api-site-jetpack.php for implementation.
234 */
235 abstract public function is_following();
236
237 /**
238 * Defaults to 0 for the number of WordPress.com subscribers - this is filled in on the WordPress.com side.
239 *
240 * @see class.json-api-site-jetpack.php for implementation.
241 */
242 abstract public function get_subscribers_count();
243
244 /**
245 * Returns the language code for the current site.
246 *
247 * @see class.json-api-site-jetpack.php for implementation.
248 */
249 abstract public function get_locale();
250
251 /**
252 * The flag indicates that the site has Jetpack installed.
253 *
254 * @see class.json-api-site-jetpack.php for implementation.
255 */
256 abstract public function is_jetpack();
257
258 /**
259 * The flag indicates that the site is connected to WP.com via Jetpack Connection.
260 *
261 * @see class.json-api-site-jetpack.php for implementation.
262 */
263 abstract public function is_jetpack_connection();
264
265 /**
266 * This function returns the values of any active Jetpack modules.
267 *
268 * @see class.json-api-site-jetpack-base.php for implementation.
269 */
270 abstract public function get_jetpack_modules();
271
272 /**
273 * This function returns true if a specified Jetpack module is active, false otherwise.
274 *
275 * @see class.json-api-site-jetpack-base.php for implementation.
276 *
277 * @param string $module The Jetpack module name to check.
278 */
279 abstract public function is_module_active( $module );
280
281 /**
282 * This function returns false for a check as to whether a site is a VIP site or not.
283 *
284 * @see class.json-api-site-jetpack-base.php for implementation.
285 */
286 abstract public function is_vip();
287
288 /**
289 * Returns true if Multisite is enabled, false otherwise.
290 *
291 * @see class.json-api-site-jetpack.php for implementation.
292 */
293 abstract public function is_multisite();
294
295 /**
296 * Points to the user ID of the site owner
297 *
298 * @see class.json-api-site-jetpack.php for implementation.
299 */
300 abstract public function get_site_owner();
301
302 /**
303 * Returns true if the current site is a single user site, false otherwise.
304 *
305 * @see class.json-api-site-jetpack.php for implementation.
306 */
307 abstract public function is_single_user_site();
308
309 /**
310 * Defaults to false instead of returning the current site plan.
311 *
312 * @see class.json-api-site-jetpack.php for implementation.
313 */
314 abstract public function get_plan();
315
316 /**
317 * Empty function declaration - this function is filled out on the WordPress.com side, returning true if the site has an AK / VP bundle.
318 *
319 * @see class.json-api-site-jetpack.php and /wpcom/public.api/rest/sal/class.json-api-site-jetpack-shadow.php.
320 */
321 abstract public function get_ak_vp_bundle_enabled();
322
323 /**
324 * Returns null for Jetpack sites. For WordPress.com sites this returns the value of the 'podcasting_archive' option.
325 *
326 * @see class.json-api-site-jetpack.php for implementation.
327 */
328 abstract public function get_podcasting_archive();
329
330 /**
331 * Return the last engine used for an import on the site. Not used in Jetpack.
332 *
333 * @see class.json-api-site-jetpack.php for implementation.
334 */
335 abstract public function get_import_engine();
336
337 /**
338 * Returns the front page meta description for current site.
339 *
340 * @see class.json-api-site-jetpack.php for implementation.
341 */
342 abstract public function get_jetpack_seo_front_page_description();
343
344 /**
345 * Returns custom title formats from site option.
346 *
347 * @see class.json-api-site-jetpack.php for implementation.
348 */
349 abstract public function get_jetpack_seo_title_formats();
350
351 /**
352 * Returns website verification codes. Allowed keys include: google, pinterest, bing, yandex, facebook.
353 *
354 * @see class.json-api-site-jetpack.php for implementation.
355 */
356 abstract public function get_verification_services_codes();
357
358 /**
359 * This function is implemented on WPCom sites, where a filter is removed which forces the URL to http.
360 *
361 * @see class.json-api-site-jetpack-base.php and /wpcom/public.api/rest/sal/class.json-api-site-jetpack-shadow.php.
362 */
363 abstract public function before_render();
364
365 /**
366 * If a user has manage options permissions and the site is the main site of the network, make updates visible.
367 *
368 * Called after response_keys have been rendered, which itself is used to return all the necessary information for a site’s response.
369 *
370 * @see class.json-api-site-jetpack-base.php for implementation.
371 *
372 * @param array $response an array of the response keys.
373 */
374 abstract public function after_render( &$response );
375
376 /**
377 * Extends the Jetpack options array with details including site constraints, WordPress and Jetpack versions, and plugins using the Jetpack connection.
378 *
379 * @see class.json-api-site-jetpack-base.php for implementation.
380 * @todo factor this out? Seems an odd thing to have on a site
381 *
382 * @param array $options an array of the Jetpack options.
383 */
384 abstract public function after_render_options( &$options );
385
386 /**
387 * Wrap a WP_Post object with SAL methods, returning a Jetpack_Post object.
388 *
389 * @see class.json-api-site-jetpack.php for implementation.
390 *
391 * @param WP_Post $post A WP_Post object.
392 * @param string $context The post request context (for example 'edit' or 'display').
393 */
394 abstract public function wrap_post( $post, $context );
395
396 /**
397 * For Jetpack sites this will always return false.
398 *
399 * @see class.json-api-site-jetpack-base.php for implementation.
400 *
401 * @param int $post_id The post id.
402 */
403 abstract protected function is_a8c_publication( $post_id );
404
405 /**
406 * Return the user interactions with a site. Not used in Jetpack.
407 *
408 * @see class.json-api-site-jetpack.php for implementation.
409 */
410 abstract public function get_user_interactions();
411
412 /**
413 * Flag a site as deleted. Not used in Jetpack.
414 *
415 * @see class.json-api-site-jetpack.php for implementation.
416 */
417 abstract public function is_deleted();
418
419 /**
420 * Indicates that a site is an A4A client. Not used in Jetpack.
421 *
422 * @see class.json-api-site-jetpack.php for implementation.
423 */
424 abstract public function is_a4a_client();
425
426 /**
427 * Indicates that a site is an A4A dev site.
428 *
429 * @return bool
430 */
431 public function is_a4a_dev_site() {
432 if ( function_exists( 'has_blog_sticker' ) ) {
433 return has_blog_sticker( 'a4a-is-dev-site' );
434 }
435 return false;
436 }
437
438 /**
439 * Return the user interactions with a site. Not used in Jetpack.
440 *
441 * @param string $role The capability to check.
442 * @return bool
443 * @see class.json-api-site-jetpack.php for implementation.
444 * @see class.json-api-site-wpcom.php (on WPCOM) for Simple-site implementation.
445 * @see class.json-api-site-jetpack-shadow.php (on WPCOM) for Atomic-site implementation.
446 */
447 abstract public function current_user_can( $role );
448
449 /**
450 * Defines a filter to set whether a site is an automated_transfer site or not.
451 *
452 * Default is false.
453 *
454 * @return bool
455 */
456 public function is_automated_transfer() {
457 /**
458 * Filter if a site is an automated-transfer site.
459 *
460 * @module json-api
461 *
462 * @since 6.4.0
463 *
464 * @param bool is_automated_transfer( $this->blog_id )
465 * @param int $blog_id Blog identifier.
466 */
467 return apply_filters(
468 'jetpack_site_automated_transfer',
469 false,
470 $this->blog_id
471 );
472 }
473
474 /**
475 * Defaulting to false and not relevant for Jetpack sites, this is expanded on the WordPress.com side for a specific wp.com/start 'WP for teams' flow.
476 *
477 * @see class.json-api-site-jetpack.php for implementation.
478 */
479 abstract public function is_wpforteams_site();
480
481 /**
482 * Get hub blog id for P2 sites.
483 *
484 * @return null
485 */
486 public function get_p2_hub_blog_id() {
487 return null;
488 }
489
490 /**
491 * Getter for the p2 organization ID.
492 *
493 * @return int
494 */
495 public function get_p2_organization_id() {
496 return 0; // WPForTeams\Constants\NO_ORG_ID not loaded.
497 }
498
499 /**
500 * Get details used to render a thumbnail of the site. P2020 themed sites only.
501 *
502 * @return ?array
503 */
504 public function get_p2_thumbnail_elements() {
505 return null;
506 }
507
508 /**
509 * Detect whether a site is a WordPress.com on Atomic site.
510 *
511 * @return bool
512 */
513 public function is_wpcom_atomic() {
514 return ( new Host() )->is_woa_site();
515 }
516
517 /**
518 * Detect whether a site is an automated transfer site and WooCommerce is active.
519 *
520 * @see /wpcom/public.api/rest/sal/class.json-api-site-jetpack-shadow.php.
521 *
522 * @return bool - False for Jetpack-connected sites.
523 */
524 public function is_wpcom_store() {
525 return false;
526 }
527
528 /**
529 * Indicate whether this site was ever a specific trial.
530 *
531 * @param string $trial The trial type to check for.
532 *
533 * @return bool
534 */
535 public function was_trial( $trial ) {
536 if ( function_exists( 'has_blog_sticker' ) ) {
537 return has_blog_sticker( "had-{$trial}-trial" );
538 }
539 return false;
540 }
541
542 /**
543 * Indicate whether this site was upgraded from a trial plan at some point.
544 *
545 * @return bool
546 */
547 public function was_upgraded_from_trial() {
548 if ( function_exists( 'has_blog_sticker' ) ) {
549 return has_blog_sticker( 'has-upgraded-from-ecommerce-trial' );
550 }
551 return false;
552 }
553
554 /**
555 * Detect whether a site has the WooCommerce plugin active.
556 *
557 * @see /wpcom/public.api/rest/sal/class.json-api-site-jetpack-shadow.php.
558 *
559 * @return bool - Default false for Jetpack-connected sites.
560 */
561 public function woocommerce_is_active() {
562 return false;
563 }
564
565 /**
566 * Whether the Editing Toolkit plugin is active (relevant only on WordPress.com).
567 *
568 * @return true
569 */
570 public function editing_toolkit_is_active() {
571 return true;
572 }
573
574 /**
575 * Detect whether a site has access to the Jetpack cloud.
576 *
577 * @see /wpcom/public.api/rest/sal/class.json-api-site-jetpack-shadow.php.
578 *
579 * @return bool - Default false for Jetpack-connected sites.
580 */
581 public function is_cloud_eligible() {
582 return false;
583 }
584
585 /**
586 * Returns an array of WPCOM_Store products.
587 *
588 * @see /wpcom/public.api/rest/sal/class.json-api-site-jetpack-shadow.php.
589 *
590 * @return bool - Default empty array for Jetpack-connected sites.
591 */
592 public function get_products() {
593 return array();
594 }
595
596 /**
597 * Get post by ID
598 *
599 * @param int $post_id The ID of the post.
600 * @param string $context The context by which the post data is required (display or edit).
601 *
602 * @return Jetpack_Post Post object on success, WP_Error object on failure
603 **/
604 public function get_post_by_id( $post_id, $context ) {
605 $post = get_post( $post_id, OBJECT, $context );
606
607 if ( ! $post ) {
608 return new WP_Error( 'unknown_post', 'Unknown post', 404 );
609 }
610
611 $wrapped_post = $this->wrap_post( $post, $context );
612 // validate access
613 return $this->validate_access( $wrapped_post );
614 }
615
616 /**
617 * Validate current user can access the post
618 *
619 * @param Jetpack_Post $post Post object.
620 *
621 * @return WP_Error|Jetpack_Post
622 */
623 private function validate_access( $post ) {
624 $context = $post->context;
625
626 if (
627 ! $this->is_post_type_allowed( $post->post_type )
628 && ! $this->is_a8c_publication( $post->ID )
629 ) {
630 return new WP_Error( 'unknown_post', 'Unknown post', 404 );
631 }
632
633 switch ( $context ) {
634 case 'edit':
635 if ( ! current_user_can( 'edit_post', $post->ID ) ) {
636 return new WP_Error( 'unauthorized', 'User cannot edit post', 403 );
637 }
638 break;
639 case 'display':
640 $can_view = $this->user_can_view_post( $post );
641 if ( is_wp_error( $can_view ) ) {
642 return $can_view;
643 }
644 break;
645 default:
646 return new WP_Error( 'invalid_context', 'Invalid API CONTEXT', 400 );
647 }
648
649 return $post;
650 }
651
652 /**
653 * Validate whether the current user can access the specified post type.
654 *
655 * @param string $post_type The post type to check.
656 * @param string $context The context by which the post data is required (display or edit).
657 *
658 * @return bool
659 */
660 public function current_user_can_access_post_type( $post_type, $context ) {
661 $post_type_object = $this->get_post_type_object( $post_type );
662 if ( ! $post_type_object ) {
663 return false;
664 }
665
666 switch ( $context ) {
667 case 'edit':
668 return current_user_can( $post_type_object->cap->edit_posts );
669 case 'display':
670 return $post_type_object->public || current_user_can( $post_type_object->cap->read_private_posts );
671 default:
672 return false;
673 }
674 }
675
676 /**
677 * Retrieves a post type object by name.
678 *
679 * @param string $post_type The post type to check.
680 *
681 * @return WP_Post_Type|null
682 */
683 protected function get_post_type_object( $post_type ) {
684 return get_post_type_object( $post_type );
685 }
686
687 /**
688 * Is the post type allowed?
689 *
690 * Function copied from class.json-api-endpoints.php.
691 *
692 * @param string $post_type Post type.
693 *
694 * @return bool
695 */
696 public function is_post_type_allowed( $post_type ) {
697 // if the post type is empty, that's fine, WordPress will default to post
698 if ( empty( $post_type ) ) {
699 return true;
700 }
701
702 // allow special 'any' type
703 if ( 'any' === $post_type ) {
704 return true;
705 }
706
707 // check for allowed types
708 if ( in_array( $post_type, $this->get_whitelisted_post_types(), true ) ) {
709 return true;
710 }
711
712 $post_type_object = get_post_type_object( $post_type );
713 if ( $post_type_object ) {
714 if ( ! empty( $post_type_object->show_in_rest ) ) {
715 return $post_type_object->show_in_rest;
716 }
717 if ( ! empty( $post_type_object->publicly_queryable ) ) {
718 return $post_type_object->publicly_queryable;
719 }
720 }
721
722 return ! empty( $post_type_object->public );
723 }
724
725 /**
726 * Gets the whitelisted post types that JP should allow access to.
727 *
728 * Function copied from class.json-api-endpoints.php.
729 *
730 * @return array Whitelisted post types.
731 */
732 public function get_whitelisted_post_types() {
733 $allowed_types = array( 'post', 'page', 'revision' );
734
735 /**
736 * Filter the post types Jetpack has access to, and can synchronize with WordPress.com.
737 *
738 * @module json-api
739 *
740 * @since 2.2.3
741 *
742 * @param array $allowed_types Array of whitelisted post types. Default to `array( 'post', 'page', 'revision' )`.
743 */
744 $allowed_types = apply_filters( 'rest_api_allowed_post_types', $allowed_types );
745
746 return array_unique( $allowed_types );
747 }
748
749 /**
750 * Can the user view the post?
751 *
752 * Function copied from class.json-api-endpoints.php and modified.
753 *
754 * @param Jetpack_Post $post Post object.
755 * @return bool|WP_Error
756 */
757 private function user_can_view_post( $post ) {
758 if ( ! $post || is_wp_error( $post ) ) {
759 return false;
760 }
761 // If the post is of status inherit, check if the parent exists ( different to 0 ) to check for the parent status object.
762 if ( 'inherit' === $post->post_status && 0 !== (int) $post->post_parent ) {
763 $parent_post = get_post( $post->post_parent );
764 $post_status_obj = get_post_status_object( $parent_post->post_status );
765 } else {
766 $post_status_obj = get_post_status_object( $post->post_status );
767 }
768
769 $authorized = (
770 $post_status_obj->public ||
771 ( is_user_logged_in() &&
772 (
773 ( $post_status_obj->protected && current_user_can( 'edit_post', $post->ID ) ) ||
774 ( $post_status_obj->private && current_user_can( 'read_post', $post->ID ) ) ||
775 ( 'trash' === $post->post_status && current_user_can( 'edit_post', $post->ID ) ) ||
776 'auto-draft' === $post->post_status
777 )
778 )
779 );
780
781 if ( ! $authorized ) {
782 return new WP_Error( 'unauthorized', 'User cannot view post', 403 );
783 }
784
785 if (
786 ( new Status() )->is_private_site() &&
787 /**
788 * Filter access to a specific post.
789 *
790 * @module json-api
791 *
792 * @since 3.4.0
793 *
794 * @param bool current_user_can( 'read_post', $post->ID ) Can the current user access the post.
795 * @param WP_Post $post Post data.
796 */
797 ! apply_filters(
798 'wpcom_json_api_user_can_view_post',
799 current_user_can( 'read_post', $post->ID ),
800 $post
801 )
802 ) {
803 return new WP_Error(
804 'unauthorized',
805 'User cannot view post',
806 array(
807 'status_code' => 403,
808 'error' => 'private_blog',
809 )
810 );
811 }
812
813 if ( strlen( $post->post_password ) && ! current_user_can( 'edit_post', $post->ID ) ) {
814 return new WP_Error(
815 'unauthorized',
816 'User cannot view password protected post',
817 array(
818 'status_code' => 403,
819 'error' => 'password_protected',
820 )
821 );
822 }
823
824 return true;
825 }
826
827 /**
828 * Get post ID by name
829 *
830 * Attempts to match name on post title and page path
831 *
832 * @param string $name The post name.
833 *
834 * @return int|WP_Error Post ID on success, WP_Error object on failure
835 */
836 public function get_post_id_by_name( $name ) {
837 $name = sanitize_title( $name );
838
839 if ( ! $name ) {
840 return new WP_Error( 'invalid_post', 'Invalid post', 400 );
841 }
842
843 $posts = get_posts(
844 array(
845 'name' => $name,
846 'numberposts' => 1,
847 'post_type' => $this->get_whitelisted_post_types(),
848 )
849 );
850
851 if ( ! $posts || ! isset( $posts[0]->ID ) || ! $posts[0]->ID ) {
852 $page = get_page_by_path( $name );
853
854 if ( ! $page ) {
855 return new WP_Error( 'unknown_post', 'Unknown post', 404 );
856 }
857
858 return $page->ID;
859 }
860
861 return (int) $posts[0]->ID;
862 }
863
864 /**
865 * Get post by name
866 *
867 * Attempts to match name on post title and page path
868 *
869 * @param string $name The post name.
870 * @param string $context (display or edit).
871 *
872 * @return Jetpack_Post|WP_Error Post object on success, WP_Error object on failure
873 **/
874 public function get_post_by_name( $name, $context ) {
875 $post_id = $this->get_post_id_by_name( $name );
876 if ( is_wp_error( $post_id ) ) {
877 return $post_id;
878 }
879
880 return $this->get_post_by_id( $post_id, $context );
881 }
882
883 /**
884 * Whether or not the current user is an admin (has option management capabilities).
885 *
886 * @return bool
887 **/
888 public function user_can_manage() {
889 return current_user_can( 'manage_options' );
890 }
891
892 /**
893 * Returns the XMLRPC URL - the site URL including the URL scheme that is used when querying your site's REST API endpoint.
894 *
895 * @return string
896 **/
897 public function get_xmlrpc_url() {
898 $xmlrpc_scheme = apply_filters( 'wpcom_json_api_xmlrpc_scheme', wp_parse_url( get_option( 'home' ), PHP_URL_SCHEME ) );
899 return site_url( 'xmlrpc.php', $xmlrpc_scheme );
900 }
901
902 /**
903 * Returns a date/time string with the date the site was registered, or a default date/time string otherwise.
904 *
905 * @return string
906 **/
907 public function get_registered_date() {
908 if ( function_exists( 'get_blog_details' ) ) {
909 $blog_details = get_blog_details();
910 if ( ! empty( $blog_details->registered ) ) {
911 return WPCOM_JSON_API_Date::format_date( $blog_details->registered );
912 }
913 }
914
915 return '0000-00-00T00:00:00+00:00';
916 }
917
918 /**
919 * Returns a date/time string with the date the site was last updated, or a default date/time string otherwise.
920 *
921 * @return string
922 **/
923 public function get_last_update_date() {
924 if ( function_exists( 'get_blog_details' ) ) {
925 $blog_details = get_blog_details();
926 if ( ! empty( $blog_details->last_updated ) ) {
927 return WPCOM_JSON_API_Date::format_date( $blog_details->last_updated );
928 }
929 }
930
931 return '0000-00-00T00:00:00+00:00';
932 }
933
934 /**
935 * Returns an array including the current users relevant capabilities.
936 *
937 * @return array
938 **/
939 public function get_capabilities() {
940 $is_wpcom_blog_owner = wpcom_get_blog_owner() === (int) get_current_user_id();
941
942 return array(
943 'edit_pages' => $this->current_user_can( 'edit_pages' ),
944 'edit_posts' => $this->current_user_can( 'edit_posts' ),
945 'edit_others_posts' => $this->current_user_can( 'edit_others_posts' ),
946 'edit_others_pages' => $this->current_user_can( 'edit_others_pages' ),
947 'delete_posts' => $this->current_user_can( 'delete_posts' ),
948 'delete_others_posts' => $this->current_user_can( 'delete_others_posts' ),
949 'edit_theme_options' => $this->current_user_can( 'edit_theme_options' ),
950 'edit_users' => $this->current_user_can( 'edit_users' ),
951 'list_users' => $this->current_user_can( 'list_users' ),
952 'manage_categories' => $this->current_user_can( 'manage_categories' ),
953 'manage_options' => $this->current_user_can( 'manage_options' ),
954 'moderate_comments' => $this->current_user_can( 'moderate_comments' ),
955 'activate_wordads' => $is_wpcom_blog_owner,
956 'promote_users' => $this->current_user_can( 'promote_users' ),
957 'publish_posts' => $this->current_user_can( 'publish_posts' ),
958 'upload_files' => $this->current_user_can( 'upload_files' ),
959 'delete_users' => $this->current_user_can( 'delete_users' ),
960 'remove_users' => $this->current_user_can( 'remove_users' ),
961 'own_site' => $is_wpcom_blog_owner,
962 /**
963 * Filter whether the Hosting section in Calypso should be available for site.
964 *
965 * @module json-api
966 *
967 * @since 8.2.0
968 *
969 * @param bool $view_hosting Can site access Hosting section. Default to false.
970 */
971 'view_hosting' => apply_filters( 'jetpack_json_api_site_can_view_hosting', false ),
972 'view_stats' => stats_is_blog_user( $this->blog_id ),
973 'activate_plugins' => $this->current_user_can( 'activate_plugins' ),
974 'update_plugins' => $this->current_user_can( 'update_plugins' ),
975 'export' => $this->current_user_can( 'export' ),
976 'import' => $this->current_user_can( 'import' ),
977 );
978 }
979
980 /**
981 * Whether or not a site is public.
982 *
983 * @return bool
984 **/
985 public function is_visible() {
986 if ( is_user_logged_in() ) {
987 $current_user = wp_get_current_user();
988 $visible = (array) get_user_meta( $current_user->ID, 'blog_visibility', true );
989
990 $is_visible = true;
991 if ( isset( $visible[ $this->blog_id ] ) ) {
992 $is_visible = (bool) $visible[ $this->blog_id ];
993 }
994
995 // null and true are visible
996 return $is_visible;
997 }
998
999 return null;
1000 }
1001
1002 /**
1003 * Creates and returns an array with logo settings.
1004 *
1005 * @return array
1006 **/
1007 public function get_logo() {
1008 // Set an empty response array.
1009 $logo_setting = array(
1010 'id' => (int) 0,
1011 'sizes' => array(),
1012 'url' => '',
1013 );
1014
1015 // Get current site logo values.
1016 $logo_id = get_option( 'site_logo' );
1017
1018 // Update the response array if there's a site logo currenty active.
1019 if ( $logo_id ) {
1020 $logo_setting['id'] = $logo_id;
1021 $logo_setting['url'] = wp_get_attachment_url( $logo_id );
1022 }
1023
1024 return $logo_setting;
1025 }
1026
1027 /**
1028 * Returns the timezone string from the site's settings (eg. 'Europe/London').
1029 *
1030 * @return string
1031 **/
1032 public function get_timezone() {
1033 return (string) get_option( 'timezone_string' );
1034 }
1035
1036 /**
1037 * Returns the GMT offset from the site's settings (eg. 5.5).
1038 *
1039 * @return float
1040 **/
1041 public function get_gmt_offset() {
1042 return (float) get_option( 'gmt_offset' );
1043 }
1044
1045 /**
1046 * Returns the site's login URL.
1047 *
1048 * @return string
1049 **/
1050 public function get_login_url() {
1051 return wp_login_url();
1052 }
1053
1054 /**
1055 * Returns the URL for a site's admin area.
1056 *
1057 * @return string
1058 **/
1059 public function get_admin_url() {
1060 return get_admin_url();
1061 }
1062
1063 /**
1064 * Returns the theme's slug (eg. 'twentytwentytwo')
1065 *
1066 * @return string
1067 **/
1068 public function get_theme_slug() {
1069 return get_option( 'stylesheet' );
1070 }
1071
1072 /**
1073 * Returns a list of errors for broken themes on the site.
1074 *
1075 * @return array
1076 */
1077 public function get_theme_errors() {
1078 $themes_with_errors = wp_get_themes( array( 'errors' => true ) );
1079 $theme_errors = array();
1080
1081 foreach ( $themes_with_errors as $theme ) {
1082 $errors = $theme->errors();
1083
1084 if ( is_wp_error( $errors ) && ! empty( $errors->get_error_messages() ) ) {
1085 $theme_errors[] = array(
1086 'name' => sanitize_title( $theme->get( 'Name' ) ),
1087 'errors' => (array) $errors->get_error_messages(),
1088 );
1089 }
1090 }
1091
1092 return $theme_errors;
1093 }
1094
1095 /**
1096 * Gets the header image data.
1097 *
1098 * @return bool|object
1099 **/
1100 public function get_header_image() {
1101 return get_theme_mod( 'header_image_data' );
1102 }
1103
1104 /**
1105 * Gets the theme background color.
1106 *
1107 * @return bool|string
1108 **/
1109 public function get_background_color() {
1110 return get_theme_mod( 'background_color' );
1111 }
1112
1113 /**
1114 * Get the image default link type.
1115 *
1116 * @return string
1117 **/
1118 public function get_image_default_link_type() {
1119 return get_option( 'image_default_link_type' );
1120 }
1121
1122 /**
1123 * Gets the image thumbnails width.
1124 *
1125 * @return int
1126 **/
1127 public function get_image_thumbnail_width() {
1128 return (int) get_option( 'thumbnail_size_w' );
1129 }
1130
1131 /**
1132 * Gets the image thumbnails height.
1133 *
1134 * @return int
1135 **/
1136 public function get_image_thumbnail_height() {
1137 return (int) get_option( 'thumbnail_size_h' );
1138 }
1139
1140 /**
1141 * Whether cropping is enabled for thumbnails.
1142 *
1143 * @return string
1144 **/
1145 public function get_image_thumbnail_crop() {
1146 return get_option( 'thumbnail_crop' );
1147 }
1148
1149 /**
1150 * Gets the medium sized image setting's width.
1151 *
1152 * @return int
1153 **/
1154 public function get_image_medium_width() {
1155 return (int) get_option( 'medium_size_w' );
1156 }
1157
1158 /**
1159 * Gets the medium sized image setting's height.
1160 *
1161 * @return int
1162 **/
1163 public function get_image_medium_height() {
1164 return (int) get_option( 'medium_size_h' );
1165 }
1166
1167 /**
1168 * Gets the large sized image setting's width.
1169 *
1170 * @return int
1171 **/
1172 public function get_image_large_width() {
1173 return (int) get_option( 'large_size_w' );
1174 }
1175
1176 /**
1177 * Gets the large sized image setting's height.
1178 *
1179 * @return int
1180 **/
1181 public function get_image_large_height() {
1182 return (int) get_option( 'large_size_h' );
1183 }
1184
1185 /**
1186 * Gets the permalink structure as defined in the site's settings.
1187 *
1188 * @return string
1189 **/
1190 public function get_permalink_structure() {
1191 return get_option( 'permalink_structure' );
1192 }
1193
1194 /**
1195 * Gets the default post format
1196 *
1197 * @return string
1198 **/
1199 public function get_default_post_format() {
1200 return get_option( 'default_post_format' );
1201 }
1202
1203 /**
1204 * Gets the default post category
1205 *
1206 * @return int
1207 **/
1208 public function get_default_category() {
1209 return (int) get_option( 'default_category' );
1210 }
1211
1212 /**
1213 * Returns what should be shown on the front page (eg. page or posts)
1214 *
1215 * @return string
1216 **/
1217 public function get_show_on_front() {
1218 return get_option( 'show_on_front' );
1219 }
1220
1221 /**
1222 * Whether or not the front page is set as 'page' to allow a custom front page
1223 *
1224 * @return bool
1225 **/
1226 public function is_custom_front_page() {
1227 return ( 'page' === $this->get_show_on_front() );
1228 }
1229
1230 /**
1231 * Whether or not likes have been enabled on all site posts
1232 *
1233 * @return bool
1234 **/
1235 public function get_default_likes_enabled() {
1236 return (bool) apply_filters( 'wpl_is_enabled_sitewide', ! get_option( 'disabled_likes' ) );
1237 }
1238
1239 /**
1240 * If sharing has been enabled and there are visible blog services (eg. 'facebook', 'twitter'), returns true.
1241 *
1242 * @return bool
1243 **/
1244 public function get_default_sharing_status() {
1245 $default_sharing_status = false;
1246 if ( class_exists( 'Sharing_Service' ) ) {
1247 $ss = new Sharing_Service();
1248 $blog_services = $ss->get_blog_services();
1249 $default_sharing_status = ! empty( $blog_services['visible'] );
1250 }
1251 return (bool) $default_sharing_status;
1252 }
1253
1254 /**
1255 * Displays the current comment status
1256 *
1257 * @return bool False if closed, true for all other comment statuses.
1258 **/
1259 public function get_default_comment_status() {
1260 return 'closed' !== get_option( 'default_comment_status' );
1261 }
1262
1263 /**
1264 * Displays the current site-wide post ping status (for pingbacks and trackbacks)
1265 *
1266 * @return bool False if closed, true for all other ping statuses.
1267 **/
1268 public function default_ping_status() {
1269 return 'closed' !== get_option( 'default_ping_status' );
1270 }
1271
1272 /**
1273 * Whether or not Publicize has been permanently disabled on the site
1274 *
1275 * @see wpcom/wp-content/admin-plugins/publicize/publicize-wpcom.php
1276 *
1277 * @return bool Default false.
1278 **/
1279 public function is_publicize_permanently_disabled() {
1280 $publicize_permanently_disabled = false;
1281 if ( function_exists( 'is_publicize_permanently_disabled' ) ) {
1282 $publicize_permanently_disabled = is_publicize_permanently_disabled( $this->blog_id );
1283 }
1284 return $publicize_permanently_disabled;
1285 }
1286
1287 /**
1288 * Returns the post ID of the static front page.
1289 *
1290 * @return int
1291 **/
1292 public function get_page_on_front() {
1293 return (int) get_option( 'page_on_front' );
1294 }
1295
1296 /**
1297 * Returns the post ID of the page designated as the posts page.
1298 *
1299 * @return int
1300 **/
1301 public function get_page_for_posts() {
1302 return (int) get_option( 'page_for_posts' );
1303 }
1304
1305 /**
1306 * Whether or not headstart is enabled for the site
1307 *
1308 * @return bool
1309 **/
1310 public function is_headstart() {
1311 return get_option( 'headstart' );
1312 }
1313
1314 /**
1315 * The WordPress version on the site.
1316 *
1317 * @return string
1318 **/
1319 public function get_wordpress_version() {
1320 global $wp_version;
1321 return $wp_version;
1322 }
1323
1324 /**
1325 * Whether or not this is a domain-only site (only relevant on WordPress.com simple sites - false otherwise)
1326 *
1327 * @return bool
1328 **/
1329 public function is_domain_only() {
1330 $options = get_option( 'options' );
1331 return ! empty( $options['is_domain_only'] ) ? (bool) $options['is_domain_only'] : false;
1332 }
1333
1334 /**
1335 * Whether or not the blog is set to public (not hidden from search engines)
1336 *
1337 * @return int 1 for true, 0 for false.
1338 **/
1339 public function get_blog_public() {
1340 return (int) get_option( 'blog_public' );
1341 }
1342
1343 /**
1344 * Whether or not the site is in a 'pending automated transfer' state.
1345 *
1346 * @return bool
1347 **/
1348 public function has_pending_automated_transfer() {
1349 /**
1350 * Filter if a site is in pending automated transfer state.
1351 *
1352 * @module json-api
1353 *
1354 * @since 6.4.0
1355 *
1356 * @param bool has_site_pending_automated_transfer( $this->blog_id )
1357 * @param int $blog_id Blog identifier.
1358 */
1359 return apply_filters(
1360 'jetpack_site_pending_automated_transfer',
1361 false,
1362 $this->blog_id
1363 );
1364 }
1365
1366 /**
1367 * Whether or not the site has a 'designType' option set as 'store'
1368 *
1369 * @return bool
1370 **/
1371 public function signup_is_store() {
1372 return $this->get_design_type() === 'store';
1373 }
1374
1375 /**
1376 * Return a new WP_Roles instance, which implements a user roles API
1377 *
1378 * @return WP_Roles
1379 **/
1380 public function get_roles() {
1381 return new WP_Roles();
1382 }
1383
1384 /**
1385 * Returns the 'designType' option if set (the site design type), null otherwise.
1386 *
1387 * @return string|null
1388 **/
1389 public function get_design_type() {
1390 $options = get_option( 'options' );
1391 return empty( $options['designType'] ) ? null : $options['designType'];
1392 }
1393
1394 /**
1395 * Returns the 'site_goals' option if set (eg. share, promote, educate, sell, showcase).
1396 *
1397 * @return array
1398 **/
1399 public function get_site_goals() {
1400 $site_goals_option = get_option( 'site_goals' );
1401
1402 if ( is_array( $site_goals_option ) ) {
1403 return $site_goals_option;
1404 }
1405
1406 return array();
1407 }
1408 /**
1409 * Return site's launch status. Expanded in class.json-api-site-jetpack.php.
1410 *
1411 * @return bool False in this case.
1412 */
1413 public function get_launch_status() {
1414 return false;
1415 }
1416
1417 /**
1418 * Whether a site has any migration meta details - only applicable on WordPress.com
1419 *
1420 * @see /wpcom/public.api/rest/sal/class.json-api-site-jetpack-shadow.php
1421 *
1422 * @return null
1423 */
1424 public function get_migration_meta() {
1425 return null;
1426 }
1427
1428 /**
1429 * Whether a site has a site segment - only applicable on WordPress.com
1430 *
1431 * @see /wpcom/public.api/rest/sal/class.json-api-site-wpcom.php
1432 *
1433 * @return false
1434 */
1435 public function get_site_segment() {
1436 return false;
1437 }
1438
1439 /**
1440 * Whether a site has Vertical ID (used for Starter Templates) - default to only applicable on WordPress.com
1441 *
1442 * @see /wpcom/public.api/rest/sal/class.json-api-site-wpcom.php
1443 *
1444 * @return false
1445 */
1446 public function get_site_vertical_id() {
1447 return false;
1448 }
1449
1450 /**
1451 * Whether a site has a 'site_creation_flow' option set (eg gutenboarding, mobile) - only applicable on WordPress.com
1452 *
1453 * @see /wpcom-json-endpoints/class.wpcom-json-api-new-site-endpoint.php for more on the option.
1454 *
1455 * @return bool
1456 */
1457 public function get_site_creation_flow() {
1458 return get_option( 'site_creation_flow' );
1459 }
1460
1461 /**
1462 * Whether a site has a 'site_source_slug' option set - only applicable on WordPress.com
1463 *
1464 * @see /wpcom-json-endpoints/class.wpcom-json-api-new-site-endpoint.php for more on the option.
1465 *
1466 * @return bool
1467 */
1468 public function get_site_source_slug() {
1469 return get_option( 'site_source_slug' );
1470 }
1471
1472 /**
1473 * Return any selected features (used to help recommend plans)
1474 *
1475 * @return string
1476 */
1477 public function get_selected_features() {
1478 return get_option( 'selected_features' );
1479 }
1480
1481 /**
1482 * Return true if the site design was created with a Blank Canvas (empty homepage template), false otherwise.
1483 *
1484 * @return bool
1485 */
1486 public function was_created_with_blank_canvas_design() {
1487 return (bool) get_option( 'was_created_with_blank_canvas_design' );
1488 }
1489
1490 /**
1491 * Get the option storing the Anchor podcast ID that identifies a site as a podcasting site.
1492 *
1493 * @return string
1494 */
1495 public function get_anchor_podcast() {
1496 return get_option( 'anchor_podcast' );
1497 }
1498
1499 /**
1500 * Check if the site is currently being built by the DIFM Lite team.
1501 *
1502 * @return bool
1503 */
1504 public function is_difm_lite_in_progress() {
1505 if ( function_exists( 'has_blog_sticker' ) ) {
1506 return has_blog_sticker( 'difm-lite-in-progress' );
1507 } elseif ( function_exists( 'wpcomsh_is_site_sticker_active' ) ) {
1508 // For atomic sites
1509 return wpcomsh_is_site_sticker_active( 'difm-lite-in-progress' );
1510 }
1511 return false;
1512 }
1513
1514 /**
1515 * Get the option of site intent which value is coming from the Hero Flow
1516 *
1517 * @return string
1518 */
1519 public function get_site_intent() {
1520 return get_option( 'site_intent', '' );
1521 }
1522
1523 /**
1524 * Get the option of site partner bundle which value is coming from the Partner Flow
1525 *
1526 * @return string
1527 */
1528 public function get_site_partner_bundle() {
1529 return get_option( 'site_partner_bundle', '' );
1530 }
1531
1532 /**
1533 * Get site option to determine if and how to display launchpad onboarding
1534 *
1535 * @return string
1536 */
1537 public function get_launchpad_screen() {
1538 return get_option( 'launchpad_screen' );
1539 }
1540
1541 /**
1542 * Get the option onboarding_segment coming from the Guided Flow
1543 *
1544 * @return string
1545 */
1546 public function get_onboarding_segment() {
1547 return get_option( 'onboarding_segment', '' );
1548 }
1549
1550 /**
1551 * Get site option for completed launchpad checklist tasks
1552 *
1553 * @return string
1554 */
1555 public function get_launchpad_checklist_tasks_statuses() {
1556 $launchpad_checklist_tasks_statuses_option = get_option( 'launchpad_checklist_tasks_statuses' );
1557
1558 if ( is_array( $launchpad_checklist_tasks_statuses_option ) ) {
1559 return $launchpad_checklist_tasks_statuses_option;
1560 }
1561
1562 return array();
1563 }
1564
1565 /**
1566 * Get site option for migration source site domain
1567 *
1568 * @return string
1569 */
1570 public function get_migration_source_site_domain() {
1571 return get_option( 'migration_source_site_domain', '' );
1572 }
1573
1574 /**
1575 * Detect whether a site is WordPress.com Staging Site.
1576 *
1577 * @see class.json-api-site-jetpack.php for implementation.
1578 */
1579 abstract public function is_wpcom_staging_site();
1580
1581 /**
1582 * Get site option for the production blog id (if is a WP.com Staging Site).
1583 *
1584 * @see class.json-api-site-jetpack.php for implementation.
1585 */
1586 abstract public function get_wpcom_production_blog_id();
1587
1588 /**
1589 * Get site option for the staging blog ids (if it has them)
1590 *
1591 * @see class.json-api-site-jetpack.php for implementation.
1592 */
1593 abstract public function get_wpcom_staging_blog_ids();
1594
1595 /**
1596 * Get the site's Blaze eligibility status.
1597 *
1598 * @return bool
1599 */
1600 public function can_blaze() {
1601 return (bool) Blaze::site_supports_blaze( $this->blog_id );
1602 }
1603
1604 /**
1605 * Return site's setup identifier.
1606 *
1607 * @return string
1608 */
1609 public function get_wpcom_site_setup() {
1610 return get_option( 'wpcom_site_setup' );
1611 }
1612
1613 /**
1614 * Returns whether the site is commercial.
1615 *
1616 * @return mixed
1617 *
1618 * - `true`: the site is commercial
1619 * - `false`: the site is not commercial
1620 * - `null`: the commercial status is not yet determined
1621 */
1622 public function is_commercial() {
1623 // Override if blog has the commercial stickers.
1624 if ( function_exists( 'has_blog_sticker' ) ) {
1625 $has_not_commercial_sticker = has_blog_sticker( 'jetpack-site-is-not-commercial-override', $this->blog_id );
1626 if ( $has_not_commercial_sticker ) {
1627 return false;
1628 }
1629 $has_commercial_sticker = has_blog_sticker( 'jetpack-site-is-commercial-override', $this->blog_id );
1630 if ( $has_commercial_sticker ) {
1631 return true;
1632 }
1633 }
1634
1635 $is_commercial = get_option( '_jetpack_site_is_commercial', null );
1636 return $is_commercial === null ? null : (bool) $is_commercial;
1637 }
1638
1639 /**
1640 * Returns an array of reasons why the site is considered commercial.
1641 *
1642 * @return array|null
1643 */
1644 public function get_is_commercial_reasons() {
1645 $reasons = get_option( '_jetpack_site_is_commercial_reason', array() );
1646
1647 // Add override as reason if blog has the commercial stickers.
1648 if ( empty( $reasons ) && $this->is_commercial() ) {
1649 return array( 'manual-override' );
1650 } elseif ( ! is_array( $reasons ) ) {
1651 return array();
1652 }
1653
1654 return $reasons;
1655 }
1656
1657 /**
1658 * Returns the site's interface selection e.g. calypso vs. wp-admin
1659 *
1660 * @return string
1661 **/
1662 public function get_wpcom_admin_interface() {
1663 return (string) get_option( 'wpcom_admin_interface' );
1664 }
1665
1666 /**
1667 * Returns whether the site is part of the classic view early release.
1668 *
1669 * @return bool
1670 **/
1671 public function get_wpcom_classic_early_release() {
1672 return ! empty( get_option( 'wpcom_classic_early_release' ) );
1673 }
1674
1675 /**
1676 * Get Zendesk site meta.
1677 *
1678 * @return array|null
1679 */
1680 abstract public function get_zendesk_site_meta();
1681
1682 /**
1683 * Detect whether there's a pending plan for this site.
1684 *
1685 * @return bool
1686 */
1687 abstract public function is_pending_plan();
1688 }
1689