summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/jetpack/_inc/lib/core-api')
-rw-r--r--plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-module-endpoints.php4
-rw-r--r--plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-site-endpoints.php75
-rw-r--r--plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/business-hours.php49
-rw-r--r--plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-mailchimp.php79
-rw-r--r--plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/gutenberg-available-extensions.php71
-rw-r--r--plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/publicize-connection-test-results.php4
-rw-r--r--plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/publicize-connections.php8
-rw-r--r--plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/publicize-services.php8
-rw-r--r--plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/service-api-keys.php281
-rw-r--r--plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/subscribers.php62
-rw-r--r--plugins/jetpack/_inc/lib/core-api/wpcom-fields/attachment-fields-videopress.php171
-rw-r--r--plugins/jetpack/_inc/lib/core-api/wpcom-fields/post-fields-publicize-connections.php18
12 files changed, 752 insertions, 78 deletions
diff --git a/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-module-endpoints.php b/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-module-endpoints.php
index 45d10d14..368b381a 100644
--- a/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-module-endpoints.php
+++ b/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-module-endpoints.php
@@ -67,7 +67,7 @@ class Jetpack_Core_API_Module_Toggle_Endpoint
);
}
- if ( ! Jetpack::active_plan_supports( $module_slug ) ) {
+ if ( ! Jetpack_Plan::supports( $module_slug ) ) {
return new WP_Error(
'not_supported',
esc_html__( 'The requested Jetpack module is not supported by your plan.', 'jetpack' ),
@@ -1503,7 +1503,7 @@ class Jetpack_Core_API_Module_Data_Endpoint {
* @type string $date Date range to restrict results to.
* }
*
- * @return int|string Number of spam blocked by Akismet. Otherwise, an error message.
+ * @return WP_Error|WP_HTTP_Response|WP_REST_Response Stats information relayed from WordPress.com.
*/
public function get_stats_data( WP_REST_Request $request ) {
// Get parameters to fetch Stats data.
diff --git a/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-site-endpoints.php b/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-site-endpoints.php
index c8fba69c..68327f51 100644
--- a/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-site-endpoints.php
+++ b/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-site-endpoints.php
@@ -48,69 +48,6 @@ class Jetpack_Core_API_Site_Endpoint {
}
/**
- * Returns the result of `/sites/%s/posts/%d/related` endpoint call.
- * Results are not cached and are retrieved in real time.
- *
- * @since 6.7.0
- *
- * @param int ID of the post to get related posts of
- *
- * @return array
- */
- public static function get_related_posts( $api_request ) {
- $params = $api_request->get_params();
- $post_id = ! empty( $params['post_id'] ) ? absint( $params['post_id'] ) : 0;
-
- if ( ! $post_id ) {
- return new WP_Error(
- 'incorrect_post_id',
- esc_html__( 'You need to specify a correct ID of a post to return related posts for.', 'jetpack' ),
- array( 'status' => 400 )
- );
- }
-
- // Make the API request
- $request = sprintf( '/sites/%d/posts/%d/related', Jetpack_Options::get_option( 'id' ), $post_id );
- $request_args = array(
- 'headers' => array(
- 'Content-Type' => 'application/json',
- ),
- 'timeout' => 10,
- 'method' => 'POST',
- );
- $response = Jetpack_Client::wpcom_json_api_request_as_blog( $request, '1.1', $request_args );
-
- // Bail if there was an error or malformed response
- if ( is_wp_error( $response ) || ! is_array( $response ) || ! isset( $response['body'] ) ) {
- return new WP_Error(
- 'failed_to_fetch_data',
- esc_html__( 'Unable to fetch the requested data.', 'jetpack' ),
- array( 'status' => 400 )
- );
- }
-
- // Decode the results
- $results = json_decode( wp_remote_retrieve_body( $response ), true );
-
- $related_posts = array();
- if ( isset( $results['hits'] ) && is_array( $results['hits'] ) ) {
- $related_posts_ids = array_map( array( 'Jetpack_Core_API_Site_Endpoint', 'get_related_post_id' ), $results['hits'] );
-
- $related_posts_instance = Jetpack_RelatedPosts::init();
- foreach ( $related_posts_ids as $related_post_id ) {
- $related_posts[] = $related_posts_instance->get_related_post_data_for_post( $related_post_id, 0, 0 );
- }
- }
-
- return rest_ensure_response( array(
- 'code' => 'success',
- 'message' => esc_html__( 'Related posts retrieved successfully.', 'jetpack' ),
- 'posts' => $related_posts,
- )
- );
- }
-
- /**
* Check that the current user has permissions to request information about this site.
*
* @since 5.1.0
@@ -120,16 +57,4 @@ class Jetpack_Core_API_Site_Endpoint {
public static function can_request() {
return current_user_can( 'jetpack_manage_modules' );
}
-
- /**
- * Returns the post ID out of a related post entry from the
- * `/sites/%s/posts/%d/related` WP.com endpoint.
- *
- * @since 6.7.0
- *
- * @return int
- */
- public static function get_related_post_id( $item ) {
- return $item['fields']['post_id'];
- }
}
diff --git a/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/business-hours.php b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/business-hours.php
new file mode 100644
index 00000000..2bf80939
--- /dev/null
+++ b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/business-hours.php
@@ -0,0 +1,49 @@
+<?php
+
+/**
+ * Business Hours: Localized week
+ *
+ * @since 7.1
+ */
+class WPCOM_REST_API_V2_Endpoint_Business_Hours extends WP_REST_Controller {
+ function __construct() {
+ $this->namespace = 'wpcom/v2';
+ $this->rest_base = 'business-hours';
+ // This endpoint *does not* need to connect directly to Jetpack sites.
+ add_action( 'rest_api_init', array( $this, 'register_routes' ) );
+ }
+
+ public function register_routes() {
+ // GET /sites/<blog_id>/business-hours/localized-week - Return the localized
+ register_rest_route( $this->namespace, '/' . $this->rest_base . '/localized-week', array(
+ array(
+ 'methods' => WP_REST_Server::READABLE,
+ 'callback' => array( $this, 'get_localized_week' ),
+ )
+ ) );
+ }
+
+ /**
+ * Retreives localized business hours
+ *
+ * @return array data object containing information about business hours
+ */
+ public function get_localized_week() {
+ global $wp_locale;
+
+ return array(
+ 'days' => array(
+ 'Sun' => $wp_locale->get_weekday( 0 ),
+ 'Mon' => $wp_locale->get_weekday( 1 ),
+ 'Tue' => $wp_locale->get_weekday( 2 ),
+ 'Wed' => $wp_locale->get_weekday( 3 ),
+ 'Thu' => $wp_locale->get_weekday( 4 ),
+ 'Fri' => $wp_locale->get_weekday( 5 ),
+ 'Sat' => $wp_locale->get_weekday( 6 ),
+ ),
+ 'startOfWeek' => (int) get_option( 'start_of_week', 0 ),
+ );
+ }
+}
+
+wpcom_rest_api_v2_load_plugin( 'WPCOM_REST_API_V2_Endpoint_Business_Hours' );
diff --git a/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-mailchimp.php b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-mailchimp.php
new file mode 100644
index 00000000..09ef9499
--- /dev/null
+++ b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/class-wpcom-rest-api-v2-endpoint-mailchimp.php
@@ -0,0 +1,79 @@
+<?php
+
+/**
+ * Mailchimp: Get Mailchimp Status.
+ * API to determine if current site has linked Mailchimp account and mailing list selected.
+ * This API is meant to be used in Jetpack and on WPCOM.
+ *
+ * @since 7.1
+ */
+class WPCOM_REST_API_V2_Endpoint_Mailchimp extends WP_REST_Controller {
+ public function __construct() {
+ $this->namespace = 'wpcom/v2';
+ $this->rest_base = 'mailchimp';
+ $this->wpcom_is_wpcom_only_endpoint = true;
+
+ add_action( 'rest_api_init', array( $this, 'register_routes' ) );
+ }
+
+ /**
+ * Called automatically on `rest_api_init()`.
+ */
+ public function register_routes() {
+ register_rest_route(
+ $this->namespace,
+ $this->rest_base,
+ array(
+ array(
+ 'methods' => WP_REST_Server::READABLE,
+ 'callback' => array( $this, 'get_mailchimp_status' ),
+ ),
+ )
+ );
+ }
+
+ /**
+ * Check if MailChimp is set up properly.
+ *
+ * @return bool
+ */
+ private function is_connected() {
+ $option = get_option( 'jetpack_mailchimp' );
+ if ( ! $option ) {
+ return false;
+ }
+ $data = json_decode( $option, true );
+ if ( ! $data ) {
+ return false;
+ }
+ return isset( $data['follower_list_id'], $data['keyring_id'] );
+ }
+
+ /**
+ * Get the status of current blog's Mailchimp connection
+ *
+ * @return mixed
+ * code:string (connected|unconnected),
+ * connect_url:string
+ * site_id:int
+ */
+ public function get_mailchimp_status() {
+ $is_wpcom = ( defined( 'IS_WPCOM' ) && IS_WPCOM );
+ $site_id = $is_wpcom ? get_current_blog_id() : Jetpack_Options::get_option( 'id' );
+ if ( ! $site_id ) {
+ return new WP_Error(
+ 'unavailable_site_id',
+ __( 'Sorry, something is wrong with your Jetpack connection.', 'jetpack' ),
+ 403
+ );
+ }
+ $connect_url = sprintf( 'https://wordpress.com/sharing/%s', rawurlencode( $site_id ) );
+ return array(
+ 'code' => $this->is_connected() ? 'connected' : 'not_connected',
+ 'connect_url' => $connect_url,
+ 'site_id' => $site_id,
+ );
+ }
+}
+
+wpcom_rest_api_v2_load_plugin( 'WPCOM_REST_API_V2_Endpoint_Mailchimp' );
diff --git a/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/gutenberg-available-extensions.php b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/gutenberg-available-extensions.php
new file mode 100644
index 00000000..a10a4056
--- /dev/null
+++ b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/gutenberg-available-extensions.php
@@ -0,0 +1,71 @@
+<?php
+
+/*
+ * Gutenberg: List Available Gutenberg Extensions (Blocks and Plugins)
+ *
+ * [
+ * { # Availabilty Object. See schema for more detail.
+ * available: (boolean) Whether the extension is available
+ * unavailable_reason: (string) Reason for the extension not being available
+ * },
+ * ...
+ * ]
+ *
+ * @since 6.9
+ */
+class WPCOM_REST_API_V2_Endpoint_Gutenberg_Available_Extensions extends WP_REST_Controller {
+ function __construct() {
+ $this->namespace = 'wpcom/v2';
+ $this->rest_base = 'gutenberg';
+ $this->wpcom_is_site_specific_endpoint = true;
+
+ add_action( 'rest_api_init', array( $this, 'register_routes' ) );
+ }
+
+ public function register_routes() {
+ register_rest_route( $this->namespace, $this->rest_base . '/available-extensions', array(
+ array(
+ 'methods' => WP_REST_Server::READABLE,
+ 'callback' => array( 'Jetpack_Gutenberg', 'get_availability' ),
+ 'permission_callback' => array( $this, 'get_items_permission_check' ),
+ ),
+ 'schema' => array( $this, 'get_item_schema' ),
+ ) );
+ }
+
+ /**
+ * Return the available Gutenberg extensions schema
+ *
+ * @return array Available Gutenberg extensions schema
+ */
+ public function get_public_item_schema() {
+ $schema = array(
+ '$schema' => 'http://json-schema.org/draft-04/schema#',
+ 'title' => 'gutenberg-available-extensions',
+ 'type' => 'object',
+ 'properties' => array(
+ 'available' => array(
+ 'description' => __( 'Whether the extension is available', 'jetpack' ),
+ 'type' => 'boolean',
+ ),
+ 'unavailable_reason' => array(
+ 'description' => __( 'Reason for the extension not being available', 'jetpack' ),
+ 'type' => 'string',
+ ),
+ ),
+ );
+
+ return $this->add_additional_fields_schema( $schema );
+ }
+
+ /**
+ * Ensure the user has proper permissions
+ *
+ * @return boolean
+ */
+ public function get_items_permission_check() {
+ return current_user_can( 'edit_posts' );
+ }
+}
+
+wpcom_rest_api_v2_load_plugin( 'WPCOM_REST_API_V2_Endpoint_Gutenberg_Available_Extensions' );
diff --git a/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/publicize-connection-test-results.php b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/publicize-connection-test-results.php
index 86019880..6e04a289 100644
--- a/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/publicize-connection-test-results.php
+++ b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/publicize-connection-test-results.php
@@ -105,6 +105,10 @@ class WPCOM_REST_API_V2_Endpoint_List_Publicize_Connection_Test_Results extends
}
}
+ if ( 'linkedin' === $item['id'] && 'must_reauth' === $test_result['connectionTestPassed'] ) {
+ $item['test_success'] = 'must_reauth';
+ }
+
$response = rest_ensure_response( $items );
$response->header( 'X-WP-Total', count( $items ) );
diff --git a/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/publicize-connections.php b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/publicize-connections.php
index f7e9b351..34d6b2a6 100644
--- a/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/publicize-connections.php
+++ b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/publicize-connections.php
@@ -171,6 +171,14 @@ class WPCOM_REST_API_V2_Endpoint_List_Publicize_Connections extends WP_REST_Cont
public function get_items_permission_check() {
global $publicize;
+ if ( ! $publicize ) {
+ return new WP_Error(
+ 'publicize_not_available',
+ __( 'Sorry, Publicize is not available on your site right now.', 'jetpack' ),
+ array( 'status' => rest_authorization_required_code() )
+ );
+ }
+
if ( $publicize->current_user_can_access_publicize_data() ) {
return true;
}
diff --git a/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/publicize-services.php b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/publicize-services.php
index fb418263..4641b218 100644
--- a/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/publicize-services.php
+++ b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/publicize-services.php
@@ -144,6 +144,14 @@ class WPCOM_REST_API_V2_Endpoint_List_Publicize_Services extends WP_REST_Control
public function get_items_permission_check() {
global $publicize;
+ if ( ! $publicize ) {
+ return new WP_Error(
+ 'publicize_not_available',
+ __( 'Sorry, Publicize is not available on your site right now.', 'jetpack' ),
+ array( 'status' => rest_authorization_required_code() )
+ );
+ }
+
if ( $publicize->current_user_can_access_publicize_data() ) {
return true;
}
diff --git a/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/service-api-keys.php b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/service-api-keys.php
new file mode 100644
index 00000000..05d0ddd3
--- /dev/null
+++ b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/service-api-keys.php
@@ -0,0 +1,281 @@
+<?php
+/*
+ * Service API Keys: Exposes 3rd party api keys that are used on a site.
+ *
+ * [
+ * { # Availabilty Object. See schema for more detail.
+ * code: (string) Displays success if the operation was successfully executed and an error code if it was not
+ * service: (string) The name of the service in question
+ * service_api_key: (string) The API key used by the service empty if one is not set yet
+ * message: (string) User friendly message
+ * },
+ * ...
+ * ]
+ *
+ * @since 6.9
+ */
+class WPCOM_REST_API_V2_Endpoint_Service_API_Keys extends WP_REST_Controller {
+
+ function __construct() {
+ $this->namespace = 'wpcom/v2';
+ $this->rest_base = 'service-api-keys';
+
+ add_action( 'rest_api_init', array( $this, 'register_routes' ) );
+ }
+
+ public function register_routes() {
+ register_rest_route(
+ 'wpcom/v2',
+ '/service-api-keys/(?P<service>[a-z\-_]+)',
+ array(
+ array(
+ 'methods' => WP_REST_Server::READABLE,
+ 'callback' => array( __CLASS__, 'get_service_api_key' ),
+ ),
+ array(
+ 'methods' => WP_REST_Server::EDITABLE,
+ 'callback' => array( __CLASS__, 'update_service_api_key' ),
+ 'permission_callback' => array( __CLASS__, 'edit_others_posts_check' ),
+ 'args' => array(
+ 'service_api_key' => array(
+ 'required' => true,
+ 'type' => 'text',
+ ),
+ ),
+ ),
+ array(
+ 'methods' => WP_REST_Server::DELETABLE,
+ 'callback' => array( __CLASS__, 'delete_service_api_key' ),
+ 'permission_callback' => array( __CLASS__, 'edit_others_posts_check' ),
+ ),
+ )
+ );
+ }
+
+ public static function edit_others_posts_check() {
+ if ( current_user_can( 'edit_others_posts' ) ) {
+ return true;
+ }
+
+ $user_permissions_error_msg = esc_html__(
+ 'You do not have the correct user permissions to perform this action.
+ Please contact your site admin if you think this is a mistake.',
+ 'jetpack'
+ );
+
+ return new WP_Error( 'invalid_user_permission_edit_others_posts', $user_permissions_error_msg, rest_authorization_required_code() );
+ }
+
+ /**
+ * Return the available Gutenberg extensions schema
+ *
+ * @return array Service API Key schema
+ */
+ public function get_public_item_schema() {
+ $schema = array(
+ '$schema' => 'http://json-schema.org/draft-04/schema#',
+ 'title' => 'service-api-keys',
+ 'type' => 'object',
+ 'properties' => array(
+ 'code' => array(
+ 'description' => __( 'Displays success if the operation was successfully executed and an error code if it was not', 'jetpack' ),
+ 'type' => 'string',
+ ),
+ 'service' => array(
+ 'description' => __( 'The name of the service in question', 'jetpack' ),
+ 'type' => 'string',
+ ),
+ 'service_api_key' => array(
+ 'description' => __( 'The API key used by the service. Empty if none has been set yet', 'jetpack' ),
+ 'type' => 'string',
+ ),
+ 'message' => array(
+ 'description' => __( 'User friendly message', 'jetpack' ),
+ 'type' => 'string',
+ ),
+ ),
+ );
+
+ return $this->add_additional_fields_schema( $schema );
+ }
+
+ /**
+ * Get third party plugin API keys.
+ *
+ * @param WP_REST_Request $request {
+ * Array of parameters received by request.
+ *
+ * @type string $slug Plugin slug with the syntax 'plugin-directory/plugin-main-file.php'.
+ * }
+ */
+ public static function get_service_api_key( $request ) {
+
+ $service = self::validate_service_api_service( $request['service'] );
+ if ( ! $service ) {
+ return self::service_api_invalid_service_response();
+ }
+ $option = self::key_for_api_service( $service );
+ $message = esc_html__( 'API key retrieved successfully.', 'jetpack' );
+ return array(
+ 'code' => 'success',
+ 'service' => $service,
+ 'service_api_key' => Jetpack_Options::get_option( $option, '' ),
+ 'message' => $message,
+ );
+ }
+
+ /**
+ * Update third party plugin API keys.
+ *
+ * @param WP_REST_Request $request {
+ * Array of parameters received by request.
+ *
+ * @type string $slug Plugin slug with the syntax 'plugin-directory/plugin-main-file.php'.
+ * }
+ */
+ public static function update_service_api_key( $request ) {
+ $service = self::validate_service_api_service( $request['service'] );
+ if ( ! $service ) {
+ return self::service_api_invalid_service_response();
+ }
+ $json_params = $request->get_json_params();
+ $params = ! empty( $json_params ) ? $json_params : $request->get_body_params();
+ $service_api_key = trim( $params['service_api_key'] );
+ $option = self::key_for_api_service( $service );
+
+ $validation = self::validate_service_api_key( $service_api_key, $service, $params );
+ if ( ! $validation['status'] ) {
+ return new WP_Error( 'invalid_key', esc_html__( 'Invalid API Key', 'jetpack' ), array( 'status' => 404 ) );
+ }
+ $message = esc_html__( 'API key updated successfully.', 'jetpack' );
+ Jetpack_Options::update_option( $option, $service_api_key );
+ return array(
+ 'code' => 'success',
+ 'service' => $service,
+ 'service_api_key' => Jetpack_Options::get_option( $option, '' ),
+ 'message' => $message,
+ );
+ }
+
+ /**
+ * Delete a third party plugin API key.
+ *
+ * @param WP_REST_Request $request {
+ * Array of parameters received by request.
+ *
+ * @type string $slug Plugin slug with the syntax 'plugin-directory/plugin-main-file.php'.
+ * }
+ */
+ public static function delete_service_api_key( $request ) {
+ $service = self::validate_service_api_service( $request['service'] );
+ if ( ! $service ) {
+ return self::service_api_invalid_service_response();
+ }
+ $option = self::key_for_api_service( $service );
+ Jetpack_Options::delete_option( $option );
+ $message = esc_html__( 'API key deleted successfully.', 'jetpack' );
+ return array(
+ 'code' => 'success',
+ 'service' => $service,
+ 'service_api_key' => Jetpack_Options::get_option( $option, '' ),
+ 'message' => $message,
+ );
+ }
+
+ /**
+ * Validate the service provided in /service-api-keys/ endpoints.
+ * To add a service to these endpoints, add the service name to $valid_services
+ * and add '{service name}_api_key' to the non-compact return array in get_option_names(),
+ * in class-jetpack-options.php
+ *
+ * @param string $service The service the API key is for.
+ * @return string Returns the service name if valid, null if invalid.
+ */
+ public static function validate_service_api_service( $service = null ) {
+ $valid_services = array(
+ 'mapbox',
+ );
+ return in_array( $service, $valid_services, true ) ? $service : null;
+ }
+
+ /**
+ * Error response for invalid service API key requests with an invalid service.
+ */
+ public static function service_api_invalid_service_response() {
+ return new WP_Error(
+ 'invalid_service',
+ esc_html__( 'Invalid Service', 'jetpack' ),
+ array( 'status' => 404 )
+ );
+ }
+
+ /**
+ * Validate API Key
+ *
+ * @param string $key The API key to be validated.
+ * @param string $service The service the API key is for.
+ */
+ public static function validate_service_api_key( $key = null, $service = null ) {
+ $validation = false;
+ switch ( $service ) {
+ case 'mapbox':
+ $validation = self::validate_service_api_key_mapbox( $key );
+ break;
+ }
+ return $validation;
+ }
+
+ /**
+ * Validate Mapbox API key
+ * Based loosely on https://github.com/mapbox/geocoding-example/blob/master/php/MapboxTest.php
+ *
+ * @param string $key The API key to be validated.
+ */
+ public static function validate_service_api_key_mapbox( $key ) {
+ $status = true;
+ $msg = null;
+ $mapbox_url = sprintf(
+ 'https://api.mapbox.com?%s',
+ $key
+ );
+ $mapbox_response = wp_safe_remote_get( esc_url_raw( $mapbox_url ) );
+ $mapbox_body = wp_remote_retrieve_body( $mapbox_response );
+ if ( '{"api":"mapbox"}' !== $mapbox_body ) {
+ $status = false;
+ $msg = esc_html__( 'Can\'t connect to Mapbox', 'jetpack' );
+ return array(
+ 'status' => $status,
+ 'error_message' => $msg,
+ );
+ }
+ $mapbox_geocode_url = esc_url_raw(
+ sprintf(
+ 'https://api.mapbox.com/geocoding/v5/mapbox.places/%s.json?access_token=%s',
+ '1+broadway+new+york+ny+usa',
+ $key
+ )
+ );
+ $mapbox_geocode_response = wp_safe_remote_get( esc_url_raw( $mapbox_geocode_url ) );
+ $mapbox_geocode_body = wp_remote_retrieve_body( $mapbox_geocode_response );
+ $mapbox_geocode_json = json_decode( $mapbox_geocode_body );
+ if ( isset( $mapbox_geocode_json->message ) && ! isset( $mapbox_geocode_json->query ) ) {
+ $status = false;
+ $msg = $mapbox_geocode_json->message;
+ }
+ return array(
+ 'status' => $status,
+ 'error_message' => $msg,
+ );
+ }
+
+ /**
+ * Create site option key for service
+ *
+ * @param string $service The service to create key for.
+ */
+ private static function key_for_api_service( $service ) {
+ return $service . '_api_key';
+ }
+}
+
+wpcom_rest_api_v2_load_plugin( 'WPCOM_REST_API_V2_Endpoint_Service_API_Keys' );
diff --git a/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/subscribers.php b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/subscribers.php
new file mode 100644
index 00000000..c1a712bd
--- /dev/null
+++ b/plugins/jetpack/_inc/lib/core-api/wpcom-endpoints/subscribers.php
@@ -0,0 +1,62 @@
+<?php
+
+/**
+ * Subscribers: Get subscriber count
+ *
+ * @since 6.9
+ */
+class WPCOM_REST_API_V2_Endpoint_Subscribers extends WP_REST_Controller {
+ function __construct() {
+ $this->namespace = 'wpcom/v2';
+ $this->rest_base = 'subscribers';
+ // This endpoint *does not* need to connect directly to Jetpack sites.
+ $this->wpcom_is_wpcom_only_endpoint = true;
+ add_action( 'rest_api_init', array( $this, 'register_routes' ) );
+ }
+
+ public function register_routes() {
+ // GET /sites/<blog_id>/subscribers/count - Return number of subscribers for this site.
+ register_rest_route( $this->namespace, '/' . $this->rest_base . '/count', array(
+ array(
+ 'methods' => WP_REST_Server::READABLE,
+ 'callback' => array( $this, 'get_subscriber_count' ),
+ 'permission_callback' => array( $this, 'readable_permission_check' ),
+ )
+ ) );
+ }
+
+ public function readable_permission_check() {
+ if ( ! current_user_can_for_blog( get_current_blog_id(), 'edit_posts' ) ) {
+ return new WP_Error( 'authorization_required', 'Only users with the permission to edit posts can see the subscriber count.', array( 'status' => 401 ) );
+ }
+
+ return true;
+ }
+
+ /**
+ * Retrieves subscriber count
+ *
+ * @param WP_REST_Request $request incoming API request info
+ * @return array data object containing subscriber count
+ */
+ public function get_subscriber_count( $request ) {
+ // Get the most up to date subscriber count when request is not a test
+ if ( ! Jetpack_Constants::is_defined( 'TESTING_IN_JETPACK' ) ) {
+ delete_transient( 'wpcom_subscribers_total' );
+ }
+
+ $subscriber_info = Jetpack_Subscriptions_Widget::fetch_subscriber_count();
+ $subscriber_count = $subscriber_info['value'];
+
+ return array(
+ 'count' => $subscriber_count
+ );
+ }
+}
+
+if (
+ Jetpack::is_module_active( 'subscriptions' ) ||
+ ( Jetpack_Constants::is_defined( 'TESTING_IN_JETPACK' ) && Jetpack_Constants::get_constant( 'TESTING_IN_JETPACK' ) )
+) {
+ wpcom_rest_api_v2_load_plugin( 'WPCOM_REST_API_V2_Endpoint_Subscribers' );
+}
diff --git a/plugins/jetpack/_inc/lib/core-api/wpcom-fields/attachment-fields-videopress.php b/plugins/jetpack/_inc/lib/core-api/wpcom-fields/attachment-fields-videopress.php
new file mode 100644
index 00000000..b615c4e6
--- /dev/null
+++ b/plugins/jetpack/_inc/lib/core-api/wpcom-fields/attachment-fields-videopress.php
@@ -0,0 +1,171 @@
+<?php
+/**
+ * Extend the REST API functionality for VideoPress users.
+ *
+ * @package Jetpack
+ */
+
+/**
+ * Add per-attachment VideoPress data.
+ *
+ * { # Attachment Object
+ * ...
+ * jetpack_videopress_guid: (string) VideoPress identifier
+ * ...
+ * }
+ *
+ * @since 7.1.0
+ */
+class WPCOM_REST_API_V2_Attachment_VideoPress_Field extends WPCOM_REST_API_V2_Field_Controller {
+ /**
+ * The REST Object Type to which the jetpack_videopress_guid field will be added.
+ *
+ * @var string
+ */
+ protected $object_type = 'attachment';
+
+ /**
+ * The name of the REST API field to add.
+ *
+ * @var string $field_name
+ */
+ protected $field_name = 'jetpack_videopress_guid';
+
+ /**
+ * Registers the jetpack_videopress field and adds a filter to remove it for attachments that are not videos.
+ */
+ public function register_fields() {
+ parent::register_fields();
+
+ add_filter( 'rest_prepare_attachment', array( $this, 'remove_field_for_non_videos' ), 10, 2 );
+ }
+
+ /**
+ * Defines data structure and what elements are visible in which contexts
+ */
+ public function get_schema() {
+ return array(
+ '$schema' => 'http://json-schema.org/draft-04/schema#',
+ 'title' => $this->field_name,
+ 'type' => 'string',
+ 'context' => array( 'view', 'edit' ),
+ 'readonly' => true,
+ 'description' => __( 'Unique VideoPress ID', 'jetpack' ),
+ );
+ }
+
+ /**
+ * Getter: Retrieve current VideoPress data for a given attachment.
+ *
+ * @param array $attachment Response from the attachment endpoint.
+ * @param WP_REST_Request $request Request to the attachment endpoint.
+ *
+ * @return string
+ */
+ public function get( $attachment, $request ) {
+ if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
+ $blog_id = get_current_blog_id();
+ } else {
+ $blog_id = Jetpack_Options::get_option( 'id' );
+ }
+
+ $post_id = absint( $attachment['id'] );
+
+ $videopress_guid = $this->get_videopress_guid( $post_id, $blog_id );
+
+ if ( ! $videopress_guid ) {
+ return '';
+ }
+
+ return $videopress_guid;
+ }
+
+ /**
+ * Gets the VideoPress GUID for a given attachment.
+ *
+ * This is pulled out into a separate method to support unit test mocking.
+ *
+ * @param int $attachment_id Attachment ID.
+ * @param int $blog_id Blog ID.
+ *
+ * @return string
+ */
+ public function get_videopress_guid( $attachment_id, $blog_id ) {
+ return video_get_info_by_blogpostid( $blog_id, $attachment_id )->guid;
+ }
+
+ /**
+ * Checks if the given attachment is a video.
+ *
+ * @param object $attachment The attachment object.
+ *
+ * @return false|int
+ */
+ public function is_video( $attachment ) {
+ return wp_startswith( $attachment->post_mime_type, 'video/' );
+ }
+
+ /**
+ * Removes the jetpack_videopress_guid field from the response if the
+ * given attachment is not a video.
+ *
+ * @param WP_REST_Response $response Response from the attachment endpoint.
+ * @param WP_Post $attachment The original attachment object.
+ *
+ * @return mixed
+ */
+ public function remove_field_for_non_videos( $response, $attachment ) {
+ if ( ! $this->is_video( $attachment ) ) {
+ unset( $response->data[ $this->field_name ] );
+ }
+
+ return $response;
+ }
+
+ /**
+ * Setter: It does nothing since `jetpack_videopress` is a read-only field.
+ *
+ * @param mixed $value The new value for the field.
+ * @param WP_Post $object The attachment object.
+ * @param WP_REST_Request $request The request object.
+ *
+ * @return null
+ */
+ public function update( $value, $object, $request ) {
+ return null;
+ }
+
+ /**
+ * Permission Check for the field's getter. Delegate the responsibility to the
+ * attachment endpoint, so it always returns true.
+ *
+ * @param mixed $object Response from the attachment endpoint.
+ * @param WP_REST_Request $request Request to the attachment endpoint.
+ *
+ * @return true
+ */
+ public function get_permission_check( $object, $request ) {
+ return true;
+ }
+
+ /**
+ * Permission Check for the field's setter. Delegate the responsibility to the
+ * attachment endpoint, so it always returns true.
+ *
+ * @param mixed $value The new value for the field.
+ * @param WP_Post $object The attachment object.
+ * @param WP_REST_Request $request Request to the attachment endpoint.
+ *
+ * @return true
+ */
+ public function update_permission_check( $value, $object, $request ) {
+ return true;
+ }
+}
+
+if (
+ ( method_exists( 'Jetpack', 'is_active' ) && Jetpack::is_active() ) ||
+ ( defined( 'IS_WPCOM' ) && IS_WPCOM )
+) {
+ wpcom_rest_api_v2_load_plugin( 'WPCOM_REST_API_V2_Attachment_VideoPress_Field' );
+}
diff --git a/plugins/jetpack/_inc/lib/core-api/wpcom-fields/post-fields-publicize-connections.php b/plugins/jetpack/_inc/lib/core-api/wpcom-fields/post-fields-publicize-connections.php
index 1aa8ec86..c4254a9d 100644
--- a/plugins/jetpack/_inc/lib/core-api/wpcom-fields/post-fields-publicize-connections.php
+++ b/plugins/jetpack/_inc/lib/core-api/wpcom-fields/post-fields-publicize-connections.php
@@ -115,6 +115,14 @@ class WPCOM_REST_API_V2_Post_Publicize_Connections_Field extends WPCOM_REST_API_
function permission_check( $post_id ) {
global $publicize;
+ if ( ! $publicize ) {
+ return new WP_Error(
+ 'publicize_not_available',
+ __( 'Sorry, Publicize is not available on your site right now.', 'jetpack' ),
+ array( 'status' => rest_authorization_required_code() )
+ );
+ }
+
if ( $publicize->current_user_can_access_publicize_data( $post_id ) ) {
return true;
}
@@ -160,6 +168,10 @@ class WPCOM_REST_API_V2_Post_Publicize_Connections_Field extends WPCOM_REST_API_
public function get( $post_array, $request ) {
global $publicize;
+ if ( ! $publicize ) {
+ return array();
+ }
+
$schema = $this->post_connection_schema();
$properties = array_keys( $schema['properties'] );
@@ -238,6 +250,10 @@ class WPCOM_REST_API_V2_Post_Publicize_Connections_Field extends WPCOM_REST_API_
protected function get_meta_to_update( $requested_connections, $post_id = 0 ) {
global $publicize;
+ if ( ! $publicize ) {
+ return array();
+ }
+
if ( isset( $this->memoized_updates[$post_id] ) ) {
return $this->memoized_updates[$post_id];
}
@@ -334,4 +350,4 @@ class WPCOM_REST_API_V2_Post_Publicize_Connections_Field extends WPCOM_REST_API_
if ( Jetpack::is_module_active( 'publicize' ) ) {
wpcom_rest_api_v2_load_plugin( 'WPCOM_REST_API_V2_Post_Publicize_Connections_Field' );
-} \ No newline at end of file
+}