diff options
Diffstat (limited to 'plugins/jetpack/json-endpoints')
66 files changed, 3045 insertions, 1949 deletions
diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-autosave-post-v1-1-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-autosave-post-v1-1-endpoint.php index 7108741e..f0968188 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-autosave-post-v1-1-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-autosave-post-v1-1-endpoint.php @@ -1,49 +1,65 @@ -<?php - -new WPCOM_JSON_API_Autosave_Post_v1_1_Endpoint( array( - 'description' => 'Create a post autosave.', - 'group' => '__do_not_document', - 'stat' => 'posts:autosave', - 'min_version' => '1.1', - 'method' => 'POST', - 'path' => '/sites/%s/posts/%d/autosave', - 'path_labels' => array( - '$site' => '(int|string) Site ID or domain', - '$post_ID' => '(int) The post ID', - ), - 'request_format' => array( - 'content' => '(HTML) The post content.', - 'title' => '(HTML) The post title.', - 'excerpt' => '(HTML) The post excerpt.', - ), - 'response_format' => array( - 'ID' => '(int) autodraft post ID', - 'post_ID' => '(int) post ID', - 'preview_URL' => '(string) preview URL for the post', - 'modified' => '(ISO 8601 datetime) modified time', - ), - - 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/82974409/posts/1/autosave', - - 'example_request_data' => array( - 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' +<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName +/** + * WPCOM_JSON_API_Autosave_Post_v1_1_Endpoint + * + * @package automattic/jetpack + */ + +new WPCOM_JSON_API_Autosave_Post_v1_1_Endpoint( + array( + 'description' => 'Create a post autosave.', + 'group' => '__do_not_document', + 'stat' => 'posts:autosave', + 'min_version' => '1.1', + 'method' => 'POST', + 'path' => '/sites/%s/posts/%d/autosave', + 'path_labels' => array( + '$site' => '(int|string) Site ID or domain', + '$post_ID' => '(int) The post ID', ), + 'request_format' => array( + 'content' => '(HTML) The post content.', + 'title' => '(HTML) The post title.', + 'excerpt' => '(HTML) The post excerpt.', + ), + 'response_format' => array( + 'ID' => '(int) autodraft post ID', + 'post_ID' => '(int) post ID', + 'preview_URL' => '(string) preview URL for the post', + 'modified' => '(ISO 8601 datetime) modified time', + ), + + 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/82974409/posts/1/autosave', - 'body' => array( - 'title' => 'Howdy', - 'content' => 'Hello. I am a test post. I was created by the API', - ) + 'example_request_data' => array( + 'headers' => array( + 'authorization' => 'Bearer YOUR_API_TOKEN', + ), + + 'body' => array( + 'title' => 'Howdy', + 'content' => 'Hello. I am a test post. I was created by the API', + ), + ), ) -) ); +); +// phpcs:disable PEAR.NamingConventions.ValidClassName.Invalid + +/** + * Class WPCOM_JSON_API_Autosave_Post_v1_1_Endpoint + */ class WPCOM_JSON_API_Autosave_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_Endpoint { - function __construct( $args ) { - parent::__construct( $args ); - } - // /sites/%s/posts/%d/autosave -> $blog_id, $post_id - function callback( $path = '', $blog_id = 0, $post_id = 0 ) { + /** + * Autosave Post callback. + * /sites/%s/posts/%d/autosave -> $blog_id, $post_id + * + * @param string $path Path. + * @param int $blog_id Blog ID. + * @param int $post_id Post ID. + */ + public function callback( $path = '', $blog_id = 0, $post_id = 0 ) { if ( ! defined( 'DOING_AUTOSAVE' ) ) { define( 'DOING_AUTOSAVE', true ); } @@ -53,8 +69,6 @@ class WPCOM_JSON_API_Autosave_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_ return $blog_id; } - $args = $this->query_args(); - $input = $this->input( false ); if ( ! is_array( $input ) || ! $input ) { @@ -76,7 +90,7 @@ class WPCOM_JSON_API_Autosave_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_ return new WP_Error( 'unauthorized', 'User cannot edit post', 403 ); } - $post_data = array ( + $post_data = array( 'post_ID' => $post_id, 'post_type' => $post->post_type, 'post_title' => $input['title'], @@ -87,26 +101,32 @@ class WPCOM_JSON_API_Autosave_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_ $preview_url = add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ); if ( ! wp_check_post_lock( $post->ID ) && - get_current_user_id() == $post->post_author && - ( 'auto-draft' == $post->post_status || 'draft' == $post->post_status ) + get_current_user_id() === (int) $post->post_author && + ( 'auto-draft' === $post->post_status || 'draft' === $post->post_status ) ) { - // Drafts and auto-drafts are just overwritten by autosave for the same user if the post is not locked - $auto_ID = edit_post( wp_slash( $post_data ) ); + // Drafts and auto-drafts are just overwritten by autosave for the same user if the post is not locked. + $auto_id = edit_post( wp_slash( $post_data ) ); } else { // Non drafts or other users drafts are not overwritten. The autosave is stored in a special post revision for each user. - $auto_ID = wp_create_post_autosave( wp_slash( $post_data ) ); - $nonce = wp_create_nonce( 'post_preview_' . $post->ID ); - $preview_url = add_query_arg( array( 'preview_id' => $auto_ID, 'preview_nonce' => $nonce ), $preview_url ); + $auto_id = wp_create_post_autosave( wp_slash( $post_data ) ); + $nonce = wp_create_nonce( 'post_preview_' . $post->ID ); + $preview_url = add_query_arg( + array( + 'preview_id' => $post->ID, + 'preview_nonce' => $nonce, + ), + $preview_url + ); } - $updated_post = get_post( $auto_ID ); + $updated_post = get_post( $auto_id ); if ( $updated_post && $updated_post->ID && $updated_post->post_modified ) { return array( - 'ID' => $auto_ID, + 'ID' => $auto_id, 'post_ID' => $post->ID, 'modified' => $this->format_date( $updated_post->post_modified_gmt, $updated_post->post_modified ), - 'preview_URL' => $preview_url + 'preview_URL' => $preview_url, ); } else { return new WP_Error( 'autosave_error', __( 'Autosave encountered an unexpected error', 'jetpack' ), 500 ); diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-comment-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-comment-endpoint.php index 20aee2b8..bb270d39 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-comment-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-comment-endpoint.php @@ -29,6 +29,7 @@ abstract class WPCOM_JSON_API_Comment_Endpoint extends WPCOM_JSON_API_Endpoint { 'i_like' => '(bool) Does the current user like this comment?', 'meta' => '(object) Meta data', 'can_moderate' => '(bool) Whether current user can moderate the comment.', + 'i_replied' => '(bool) Has the current user replied to this comment?', ); // public $response_format =& $this->comment_object_format; @@ -197,6 +198,15 @@ abstract class WPCOM_JSON_API_Comment_Endpoint extends WPCOM_JSON_API_Endpoint { case 'can_moderate': $response[ $key ] = (bool) current_user_can( 'edit_comment', $comment_id ); break; + case 'i_replied': + $response[ $key ] = (bool) 0 < get_comments( + array( + 'user_id' => get_current_user_id(), + 'parent' => $comment->comment_ID, + 'count' => true, + ) + ); + break; } } diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-autosave-v1-1-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-autosave-v1-1-endpoint.php index 9970120a..51ffba52 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-autosave-v1-1-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-autosave-v1-1-endpoint.php @@ -1,37 +1,53 @@ -<?php +<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName +/** + * WPCOM_JSON_API_Get_Autosave_v1_1_Endpoint + * + * @package automattic/jetpack + */ -new WPCOM_JSON_API_Get_Autosave_v1_1_Endpoint( array( - 'description' => 'Get the most recent autosave for a post.', - 'group' => '__do_not_document', - 'stat' => 'posts:autosave', - 'min_version' => '1.1', - 'method' => 'GET', - 'path' => '/sites/%s/posts/%d/autosave', - 'path_labels' => array( - '$site' => '(int|string) Site ID or domain', - '$post_ID' => '(int) The post ID', - ), - 'response_format' => array( - 'ID' => '(int) autodraft post ID', - 'post_ID' => '(int) post ID', - 'author_ID' => '(int) author ID', - 'title' => '(HTML) The post title.', - 'content' => '(HTML) The post content.', - 'excerpt' => '(HTML) The post excerpt.', - 'preview_URL' => '(string) preview URL for the post', - 'modified' => '(ISO 8601 datetime) modified time', - ), +new WPCOM_JSON_API_Get_Autosave_v1_1_Endpoint( + array( + 'description' => 'Get the most recent autosave for a post.', + 'group' => '__do_not_document', + 'stat' => 'posts:autosave', + 'min_version' => '1.1', + 'method' => 'GET', + 'path' => '/sites/%s/posts/%d/autosave', + 'path_labels' => array( + '$site' => '(int|string) Site ID or domain', + '$post_ID' => '(int) The post ID', + ), + 'response_format' => array( + 'ID' => '(int) autodraft post ID', + 'post_ID' => '(int) post ID', + 'author_ID' => '(int) author ID', + 'title' => '(HTML) The post title.', + 'content' => '(HTML) The post content.', + 'excerpt' => '(HTML) The post excerpt.', + 'preview_URL' => '(string) preview URL for the post', + 'modified' => '(ISO 8601 datetime) modified time', + ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/82974409/posts/1/autosave', -) ); + 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/82974409/posts/1/autosave', + ) +); +// phpcs:disable PEAR.NamingConventions.ValidClassName.Invalid +/** + * Class WPCOM_JSON_API_Get_Autosave_v1_1_Endpoint + */ class WPCOM_JSON_API_Get_Autosave_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_Endpoint { - function __construct( $args ) { - parent::__construct( $args ); - } - - // /sites/%s/posts/%d/autosave -> $blog_id, $post_id - function callback( $path = '', $blog_id = 0, $post_id = 0 ) { + /** + * Get Autosave callback + * /sites/%s/posts/%d/autosave -> $blog_id, $post_id + * + * @param string $path Path. + * @param int $blog_id Blog ID. + * @param int $post_id Post ID. + * + * @return array|int|mixed|WP_Error + */ + public function callback( $path = '', $blog_id = 0, $post_id = 0 ) { $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) ); if ( is_wp_error( $blog_id ) ) { @@ -52,8 +68,14 @@ class WPCOM_JSON_API_Get_Autosave_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1 if ( $autosave ) { $preview_url = add_query_arg( 'preview', 'true', get_permalink( $post->ID ) ); - $nonce = wp_create_nonce( 'post_preview_' . $post->ID ); - $preview_url = add_query_arg( array( 'preview_id' => $auto_ID, 'preview_nonce' => $nonce ), $preview_url ); + $nonce = wp_create_nonce( 'post_preview_' . $post->ID ); + $preview_url = add_query_arg( + array( + 'preview_id' => $post->ID, + 'preview_nonce' => $nonce, + ), + $preview_url + ); return array( 'ID' => $autosave->ID, @@ -63,7 +85,7 @@ class WPCOM_JSON_API_Get_Autosave_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1 'content' => $autosave->post_content, 'excerpt' => $autosave->post_excerpt, 'preview_URL' => $preview_url, - 'modified' => $this->format_date( $autosave->post_modified_gmt, $autosave->post_modified ) + 'modified' => $this->format_date( $autosave->post_modified_gmt, $autosave->post_modified ), ); } else { return new WP_Error( 'not_found', 'No autosaves exist for this post', 404 ); diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comment-counts-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comment-counts-endpoint.php index 705f2e61..f92fe7eb 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comment-counts-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comment-counts-endpoint.php @@ -48,7 +48,7 @@ class WPCOM_JSON_API_GET_Comment_Counts_Endpoint extends WPCOM_JSON_API_Endpoint $args = $this->query_args(); // If 0 is passed wp_count_comments will default to fetching counts for the whole site. - $post_id = ! empty( $args['post_id'] ) ? intval( $args['post_id'] ) : 0; + $post_id = ! empty( $args['post_id'] ) ? (int) $args['post_id'] : 0; // Check if post with given id exists. if ( ! empty( $post_id ) && ! is_object( get_post( $post_id ) ) ) { diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comment-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comment-endpoint.php index 3a928bfd..f536a22a 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comment-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comment-endpoint.php @@ -12,6 +12,8 @@ new WPCOM_JSON_API_Get_Comment_Endpoint( array( '$comment_ID' => '(int) The comment ID' ), + 'allow_fallback_to_jetpack_blog_token' => true, + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/en.blog.wordpress.com/comments/147564' ) ); diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comment-history-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comment-history-endpoint.php index 37aa9206..1fa0e1d1 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comment-history-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comment-history-endpoint.php @@ -45,7 +45,7 @@ class WPCOM_JSON_API_GET_Comment_History_Endpoint extends WPCOM_JSON_API_Endpoin foreach ( $comment_history as &$item ) { // Times are stored as floating point values in microseconds. // We don't need that precision on the client so let's get rid of the decimal part. - $item['time'] = intval( $item['time'] ); + $item['time'] = (int) $item['time']; } return array( 'comment_history' => $comment_history ); diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comments-tree-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comments-tree-endpoint.php index fdc3bee7..ad48b46b 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comments-tree-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comments-tree-endpoint.php @@ -102,10 +102,9 @@ class WPCOM_JSON_API_Get_Comments_Tree_Endpoint extends WPCOM_JSON_API_Endpoint */ function get_site_tree_total_count( $status, $type ) { global $wpdb; + $db_status = $this->get_comment_db_status( $status ); - $type = $this->get_sanitized_comment_type( $type ); - // An empty value in the comments_type column denotes a regular comment. - $type = ( 'comment' === $type ) ? '' : $type; + $type = $this->get_sanitized_comment_type( $type ); $result = $wpdb->get_var( $wpdb->prepare( @@ -113,10 +112,12 @@ class WPCOM_JSON_API_Get_Comments_Tree_Endpoint extends WPCOM_JSON_API_Endpoint "FROM $wpdb->comments AS comments " . "INNER JOIN $wpdb->posts AS posts ON comments.comment_post_ID = posts.ID " . "WHERE comment_type = %s AND ( %s = 'all' OR comment_approved = %s )", - $type, $db_status, $db_status + $type, + $db_status, + $db_status ) ); - return intval( $result ); + return (int) $result; } /** diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comments-tree-v1-1-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comments-tree-v1-1-endpoint.php index 82124992..6052863b 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comments-tree-v1-1-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comments-tree-v1-1-endpoint.php @@ -58,9 +58,9 @@ class WPCOM_JSON_API_Get_Comments_Tree_v1_1_Endpoint extends WPCOM_JSON_API_Get_ $trackbacks = array(); $pingbacks = array(); foreach ( $db_comment_rows as $row ) { - $comment_id = intval( $row[0] ); - $comment_post_id = intval( $row[1] ); - $comment_parent_id = intval( $row[2] ); + $comment_id = (int) $row[0]; + $comment_post_id = (int) $row[1]; + $comment_parent_id = (int) $row[2]; if ( ! isset( $comments[ $comment_post_id ] ) ) { $comments[ $comment_post_id ] = array( array(), array() ); } diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comments-tree-v1-2-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comments-tree-v1-2-endpoint.php index 0537279d..a4b09853 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comments-tree-v1-2-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-comments-tree-v1-2-endpoint.php @@ -82,9 +82,9 @@ class WPCOM_JSON_API_Get_Comments_Tree_v1_2_Endpoint extends WPCOM_JSON_API_Get_ $trackbacks = array(); $pingbacks = array(); foreach ( $db_comment_rows as $row ) { - $comment_id = intval( $row[0] ); - $comment_parent_id = intval( $row[1] ); - $comment_post_id = isset( $args['post_id'] ) ? intval( $args['post_id'] ) : intval( $row[3] ); + $comment_id = (int) $row[0]; + $comment_parent_id = (int) $row[1]; + $comment_post_id = isset( $args['post_id'] ) ? (int) $args['post_id'] : (int) $row[3]; if ( ! isset( $comments[ $comment_post_id ] ) ) { $comments[ $comment_post_id ] = array( array(), array() ); diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-media-v1-1-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-media-v1-1-endpoint.php index 62d8681e..b1968f22 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-media-v1-1-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-media-v1-1-endpoint.php @@ -1,47 +1,52 @@ <?php -new WPCOM_JSON_API_Get_Media_v1_1_Endpoint( array( - 'description' => 'Get a single media item (by ID).', - 'group' => 'media', - 'stat' => 'media:1', - 'min_version' => '1.1', - 'max_version' => '1.1', - 'method' => 'GET', - 'path' => '/sites/%s/media/%d', - 'path_labels' => array( - '$site' => '(int|string) Site ID or domain', - '$media_ID' => '(int) The ID of the media item', - ), - 'response_format' => array( - 'ID' => '(int) The ID of the media item', - 'date' => '(ISO 8601 datetime) The date the media was uploaded', - 'post_ID' => '(int) ID of the post this media is attached to', - 'author_ID' => '(int) ID of the user who uploaded the media', - 'URL' => '(string) URL to the file', - 'guid' => '(string) Unique identifier', - 'file' => '(string) Filename', - 'extension' => '(string) File extension', - 'mime_type' => '(string) File MIME type', - 'title' => '(string) Filename', - 'caption' => '(string) User-provided caption of the file', - 'description' => '(string) Description of the file', - 'alt' => '(string) Alternative text for image files.', - 'thumbnails' => '(object) Media item thumbnail URL options', - 'height' => '(int) (Image & video only) Height of the media item', - 'width' => '(int) (Image & video only) Width of the media item', - 'length' => '(int) (Video & audio only) Duration of the media item, in seconds', - 'exif' => '(array) (Image & audio only) Exif (meta) information about the media item', - 'videopress_guid' => '(string) (Video only) VideoPress GUID of the video when uploaded on a blog with VideoPress', - 'videopress_processing_done' => '(bool) (Video only) If the video is uploaded on a blog with VideoPress, this will return the status of processing on the video.' - ), +new WPCOM_JSON_API_Get_Media_v1_1_Endpoint( + array( + 'description' => 'Get a single media item (by ID).', + 'group' => 'media', + 'stat' => 'media:1', + 'min_version' => '1.1', + 'max_version' => '1.1', + 'method' => 'GET', + 'path' => '/sites/%s/media/%d', + 'path_labels' => array( + '$site' => '(int|string) Site ID or domain', + '$media_ID' => '(int) The ID of the media item', + ), + 'response_format' => array( + 'ID' => '(int) The ID of the media item', + 'date' => '(ISO 8601 datetime) The date the media was uploaded', + 'post_ID' => '(int) ID of the post this media is attached to', + 'author_ID' => '(int) ID of the user who uploaded the media', + 'URL' => '(string) URL to the file', + 'guid' => '(string) Unique identifier', + 'file' => '(string) Filename', + 'extension' => '(string) File extension', + 'mime_type' => '(string) File MIME type', + 'title' => '(string) Filename', + 'caption' => '(string) User-provided caption of the file', + 'description' => '(string) Description of the file', + 'alt' => '(string) Alternative text for image files.', + 'thumbnails' => '(object) Media item thumbnail URL options', + 'height' => '(int) (Image & video only) Height of the media item', + 'width' => '(int) (Image & video only) Width of the media item', + 'length' => '(int) (Video & audio only) Duration of the media item, in seconds', + 'exif' => '(array) (Image & audio only) Exif (meta) information about the media item', + 'rating' => '(string) (Video only) VideoPress rating of the video', + 'display_embed' => '(string) Video only. Whether to share or not the video.', + 'allow_download' => '(string) Video only. Whether the video can be downloaded or not.', + 'videopress_guid' => '(string) (Video only) VideoPress GUID of the video when uploaded on a blog with VideoPress', + 'videopress_processing_done' => '(bool) (Video only) If the video is uploaded on a blog with VideoPress, this will return the status of processing on the video.', + ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/82974409/media/934', - 'example_request_data' => array( - 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' - ) + 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/82974409/media/934', + 'example_request_data' => array( + 'headers' => array( + 'authorization' => 'Bearer YOUR_API_TOKEN', + ), + ), ) -) ); +); class WPCOM_JSON_API_Get_Media_v1_1_Endpoint extends WPCOM_JSON_API_Endpoint { function callback( $path = '', $blog_id = 0, $media_id = 0 ) { diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-media-v1-2-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-media-v1-2-endpoint.php index 413e3b94..3dc7724f 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-media-v1-2-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-media-v1-2-endpoint.php @@ -2,52 +2,57 @@ jetpack_require_lib( 'class.media' ); -new WPCOM_JSON_API_Get_Media_v1_2_Endpoint( array( - 'description' => 'Get a single media item (by ID).', - 'group' => 'media', - 'stat' => 'media:1', - 'min_version' => '1.2', - 'max_version' => '1.2', - 'method' => 'GET', - 'path' => '/sites/%s/media/%d', - 'path_labels' => array( - '$site' => '(int|string) Site ID or domain', - '$media_ID' => '(int) The ID of the media item', - ), - 'response_format' => array( - 'ID' => '(int) The ID of the media item', - 'date' => '(ISO 8601 datetime) The date the media was uploaded', - 'post_ID' => '(int) ID of the post this media is attached to', - 'author_ID' => '(int) ID of the user who uploaded the media', - 'URL' => '(string) URL to the file', - 'guid' => '(string) Unique identifier', - 'file' => '(string) Filename', - 'extension' => '(string) File extension', - 'mime_type' => '(string) File MIME type', - 'title' => '(string) Filename', - 'caption' => '(string) User-provided caption of the file', - 'description' => '(string) Description of the file', - 'alt' => '(string) Alternative text for image files.', - 'thumbnails' => '(object) Media item thumbnail URL options', - 'height' => '(int) (Image & video only) Height of the media item', - 'width' => '(int) (Image & video only) Width of the media item', - 'length' => '(int) (Video & audio only) Duration of the media item, in seconds', - 'exif' => '(array) (Image & audio only) Exif (meta) information about the media item', - 'videopress_guid' => '(string) (Video only) VideoPress GUID of the video when uploaded on a blog with VideoPress', - 'videopress_processing_done' => '(bool) (Video only) If the video is uploaded on a blog with VideoPress, this will return the status of processing on the video.', - 'revision_history' => '(object) An object with `items` and `original` keys. ' . - '`original` is an object with data about the original image. ' . - '`items` is an array of snapshots of the previous images of this Media. ' . - 'Each item has the `URL`, `file, `extension`, `date`, and `mime_type` fields.' - ), +new WPCOM_JSON_API_Get_Media_v1_2_Endpoint( + array( + 'description' => 'Get a single media item (by ID).', + 'group' => 'media', + 'stat' => 'media:1', + 'min_version' => '1.2', + 'max_version' => '1.2', + 'method' => 'GET', + 'path' => '/sites/%s/media/%d', + 'path_labels' => array( + '$site' => '(int|string) Site ID or domain', + '$media_ID' => '(int) The ID of the media item', + ), + 'response_format' => array( + 'ID' => '(int) The ID of the media item', + 'date' => '(ISO 8601 datetime) The date the media was uploaded', + 'post_ID' => '(int) ID of the post this media is attached to', + 'author_ID' => '(int) ID of the user who uploaded the media', + 'URL' => '(string) URL to the file', + 'guid' => '(string) Unique identifier', + 'file' => '(string) Filename', + 'extension' => '(string) File extension', + 'mime_type' => '(string) File MIME type', + 'title' => '(string) Filename', + 'caption' => '(string) User-provided caption of the file', + 'description' => '(string) Description of the file', + 'alt' => '(string) Alternative text for image files.', + 'thumbnails' => '(object) Media item thumbnail URL options', + 'height' => '(int) (Image & video only) Height of the media item', + 'width' => '(int) (Image & video only) Width of the media item', + 'length' => '(int) (Video & audio only) Duration of the media item, in seconds', + 'exif' => '(array) (Image & audio only) Exif (meta) information about the media item', + 'rating' => '(string) (Video only) VideoPress rating of the video', + 'display_embed' => '(string) Video only. Whether to share or not the video.', + 'allow_download' => '(string) Video only. Whether the video can be downloaded or not.', + 'videopress_guid' => '(string) (Video only) VideoPress GUID of the video when uploaded on a blog with VideoPress', + 'videopress_processing_done' => '(bool) (Video only) If the video is uploaded on a blog with VideoPress, this will return the status of processing on the video.', + 'revision_history' => '(object) An object with `items` and `original` keys. ' . + '`original` is an object with data about the original image. ' . + '`items` is an array of snapshots of the previous images of this Media. ' . + 'Each item has the `URL`, `file, `extension`, `date`, and `mime_type` fields.', + ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.2/sites/82974409/media/934', - 'example_request_data' => array( - 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' - ) + 'example_request' => 'https://public-api.wordpress.com/rest/v1.2/sites/82974409/media/934', + 'example_request_data' => array( + 'headers' => array( + 'authorization' => 'Bearer YOUR_API_TOKEN', + ), + ), ) -) ); +); class WPCOM_JSON_API_Get_Media_v1_2_Endpoint extends WPCOM_JSON_API_Get_Media_v1_1_Endpoint { function callback( $path = '', $blog_id = 0, $media_id = 0 ) { @@ -57,10 +62,10 @@ class WPCOM_JSON_API_Get_Media_v1_2_Endpoint extends WPCOM_JSON_API_Get_Media_v1 return $response; } - $media_item = get_post( $media_id ); + $media_item = get_post( $media_id ); $response->modified = (string) $this->format_date( $media_item->post_modified_gmt, $media_item->post_modified ); - // expose `revision_history` object + // expose `revision_history` object. $response->revision_history = (object) array( 'items' => (array) Jetpack_Media::get_revision_history( $media_id ), 'original' => (object) Jetpack_Media::get_original_media( $media_id ) diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-post-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-post-endpoint.php index f82b2f43..f3e927ac 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-post-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-post-endpoint.php @@ -13,6 +13,8 @@ new WPCOM_JSON_API_Get_Post_Endpoint( array( '$post_ID' => '(int) The post ID', ), + 'allow_fallback_to_jetpack_blog_token' => true, + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/en.blog.wordpress.com/posts/7' ) ); @@ -43,6 +45,8 @@ new WPCOM_JSON_API_Get_Post_Endpoint( array( '$post_slug' => '(string) The post slug (a.k.a. sanitized name)', ), + 'allow_fallback_to_jetpack_blog_token' => true, + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/en.blog.wordpress.com/posts/slug:blogging-and-stuff', ) ); diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-post-v1-1-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-post-v1-1-endpoint.php index 572567d7..dd437a2f 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-post-v1-1-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-post-v1-1-endpoint.php @@ -12,6 +12,9 @@ new WPCOM_JSON_API_Get_Post_v1_1_Endpoint( array( '$site' => '(int|string) Site ID or domain', '$post_ID' => '(int) The post ID', ), + + 'allow_fallback_to_jetpack_blog_token' => true, + 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/en.blog.wordpress.com/posts/7' ) ); @@ -27,6 +30,9 @@ new WPCOM_JSON_API_Get_Post_v1_1_Endpoint( array( '$site' => '(int|string) Site ID or domain', '$post_slug' => '(string) The post slug (a.k.a. sanitized name)', ), + + 'allow_fallback_to_jetpack_blog_token' => true, + 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/en.blog.wordpress.com/posts/slug:blogging-and-stuff', ) ); diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-site-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-site-endpoint.php index 044afeb7..6dfa5f7a 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-site-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-site-endpoint.php @@ -13,6 +13,9 @@ new WPCOM_JSON_API_GET_Site_Endpoint( array( '$site' => '(int|string) Site ID or domain', ), 'allow_jetpack_site_auth' => true, + + 'allow_fallback_to_jetpack_blog_token' => true, + 'query_parameters' => array( 'context' => false, 'options' => '(string) Optional. Returns specified options only. Comma-separated list. Example: options=login_url,timezone', @@ -26,35 +29,40 @@ new WPCOM_JSON_API_GET_Site_Endpoint( array( class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { public static $site_format = array( - 'ID' => '(int) Site ID', - 'name' => '(string) Title of site', - 'description' => '(string) Tagline or description of site', - 'URL' => '(string) Full URL to the site', - 'user_can_manage' => '(bool) The current user can manage this site', // deprecated - 'capabilities' => '(array) Array of capabilities for the current user on this site.', - 'jetpack' => '(bool) Whether the site is a Jetpack site or not', - 'is_multisite' => '(bool) Whether the site is a Multisite site or not. Always true for WP.com sites.', - 'post_count' => '(int) The number of posts the site has', - 'subscribers_count' => '(int) The number of subscribers the site has', - 'lang' => '(string) Primary language code of the site', - 'icon' => '(array) An array of icon formats for the site', - 'logo' => '(array) The site logo, set in the Customizer', - 'visible' => '(bool) If this site is visible in the user\'s site list', - 'is_private' => '(bool) If the site is a private site or not', - 'is_coming_soon' => '(bool) If the site is marked as "coming soon" or not', - 'single_user_site' => '(bool) Whether the site is single user. Only returned for WP.com sites and for Jetpack sites with version 3.4 or higher.', - 'is_vip' => '(bool) If the site is a VIP site or not.', - 'is_following' => '(bool) If the current user is subscribed to this site in the reader', - 'options' => '(array) An array of options/settings for the blog. Only viewable by users with post editing rights to the site. Note: Post formats is deprecated, please see /sites/$id/post-formats/', - 'plan' => '(array) Details of the current plan for this site.', - 'updates' => '(array) An array of available updates for plugins, themes, wordpress, and languages.', - 'jetpack_modules' => '(array) A list of active Jetpack modules.', - 'meta' => '(object) Meta data', - 'quota' => '(array) An array describing how much space a user has left for uploads', - 'launch_status' => '(string) A string describing the launch status of a site', - 'migration_status' => '(string) A string describing the migration status of the site.', - 'is_fse_active' => '(bool) If the site has Full Site Editing active or not.', - 'is_fse_eligible' => '(bool) If the site is capable of Full Site Editing or not', + 'ID' => '(int) Site ID', + 'name' => '(string) Title of site', + 'description' => '(string) Tagline or description of site', + 'URL' => '(string) Full URL to the site', + 'user_can_manage' => '(bool) The current user can manage this site', // deprecated. + 'capabilities' => '(array) Array of capabilities for the current user on this site.', + 'jetpack' => '(bool) Whether the site is a Jetpack site or not', + 'jetpack_connection' => '(bool) Whether the site is connected to WP.com via `jetpack-connection`', + 'is_multisite' => '(bool) Whether the site is a Multisite site or not. Always true for WP.com sites.', + 'site_owner' => '(int) User ID of the site owner', + 'post_count' => '(int) The number of posts the site has', + 'subscribers_count' => '(int) The number of subscribers the site has', + 'lang' => '(string) Primary language code of the site', + 'icon' => '(array) An array of icon formats for the site', + 'logo' => '(array) The site logo, set in the Customizer', + 'visible' => '(bool) If this site is visible in the user\'s site list', + 'is_private' => '(bool) If the site is a private site or not', + 'is_coming_soon' => '(bool) If the site is marked as "coming soon" or not', + 'single_user_site' => '(bool) Whether the site is single user. Only returned for WP.com sites and for Jetpack sites with version 3.4 or higher.', + 'is_vip' => '(bool) If the site is a VIP site or not.', + 'is_following' => '(bool) If the current user is subscribed to this site in the reader', + 'organization_id' => '(int) P2 Organization identifier.', + 'options' => '(array) An array of options/settings for the blog. Only viewable by users with post editing rights to the site. Note: Post formats is deprecated, please see /sites/$id/post-formats/', + 'plan' => '(array) Details of the current plan for this site.', + 'updates' => '(array) An array of available updates for plugins, themes, wordpress, and languages.', + 'jetpack_modules' => '(array) A list of active Jetpack modules.', + 'meta' => '(object) Meta data', + 'quota' => '(array) An array describing how much space a user has left for uploads', + 'launch_status' => '(string) A string describing the launch status of a site', + 'site_migration' => '(array) Data about any migration into the site.', + 'is_fse_active' => '(bool) If the site has Full Site Editing active or not.', + 'is_fse_eligible' => '(bool) If the site is capable of Full Site Editing or not', + 'is_core_site_editor_enabled' => '(bool) If the site has the core site editor enabled.', + 'is_wpcom_atomic' => '(bool) If the site is a WP.com Atomic one.', ); protected static $no_member_fields = array( @@ -63,6 +71,7 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { 'description', 'URL', 'jetpack', + 'jetpack_connection', 'post_count', 'subscribers_count', 'lang', @@ -75,9 +84,11 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { 'is_following', 'meta', 'launch_status', - 'migration_status', + 'site_migration', 'is_fse_active', 'is_fse_eligible', + 'is_core_site_editor_enabled', + 'is_wpcom_atomic', ); protected static $site_options_format = array( @@ -140,16 +151,26 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { 'site_goals', 'site_segment', 'import_engine', + 'is_wpforteams_site', + 'p2_hub_blog_id', + 'site_creation_flow', + 'is_cloud_eligible', + 'selected_features', + 'anchor_podcast', + 'is_difm_lite_in_progress', + 'site_intent', ); protected static $jetpack_response_field_additions = array( 'subscribers_count', - 'migration_status', + 'site_migration', ); protected static $jetpack_response_field_member_additions = array( 'capabilities', 'plan', + 'products', + 'zendesk_site_meta', ); protected static $jetpack_response_option_additions = array( @@ -313,7 +334,10 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { break; case 'is_coming_soon' : // This option is stored on wp.com for both simple and atomic sites. @see mu-plugins/private-blog.php - $response[ $key ] = $this->site->is_private() && get_option( 'wpcom_coming_soon' ); + $response[ $key ] = $this->site->is_coming_soon();; + break; + case 'launch_status' : + $response[ $key ] = $this->site->get_launch_status(); break; case 'visible' : $response[ $key ] = $this->site->is_visible(); @@ -362,9 +386,12 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { case 'locale' : $response[ $key ] = $is_user_logged_in ? $this->site->get_locale() : false; break; - case 'jetpack' : + case 'jetpack': $response[ $key ] = $this->site->is_jetpack(); break; + case 'jetpack_connection': + $response[ $key ] = $this->site->is_jetpack_connection(); + break; case 'single_user_site' : $response[ $key ] = $this->site->is_single_user_site(); break; @@ -374,6 +401,13 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { case 'is_multisite' : $response[ $key ] = $this->site->is_multisite(); break; + case 'site_owner': + $response[ $key ] = $this->site->get_site_owner(); + break; + case 'organization_id': + $response[ $key ] = $this->site->get_p2_organization_id(); + break; + case 'capabilities' : $response[ $key ] = $this->site->get_capabilities(); break; @@ -385,14 +419,17 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { case 'plan' : $response[ $key ] = $this->site->get_plan(); break; + case 'products' : + $response[ $key ] = $this->site->get_products(); + break; + case 'zendesk_site_meta': + $response[ $key ] = $this->site->get_zendesk_site_meta(); + break; case 'quota' : $response[ $key ] = $this->site->get_quota(); break; - case 'launch_status' : - $response[ $key ] = $this->site->get_launch_status(); - break; - case 'migration_status' : - $response[ $key ] = $this->site->get_migration_status(); + case 'site_migration' : + $response[ $key ] = $this->site->get_migration_meta(); break; case 'is_fse_active': $response[ $key ] = $this->site->is_fse_active(); @@ -400,6 +437,12 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { case 'is_fse_eligible': $response[ $key ] = $this->site->is_fse_eligible(); break; + case 'is_core_site_editor_enabled': + $response[ $key ] = $this->site->is_core_site_editor_enabled(); + break; + case 'is_wpcom_atomic': + $response[ $key ] = $this->site->is_wpcom_atomic(); + break; } do_action( 'post_render_site_response_key', $key ); @@ -602,6 +645,38 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { case 'import_engine': $options[ $key ] = $site->get_import_engine(); break; + + case 'is_wpforteams_site': + $options[ $key ] = $site->is_wpforteams_site(); + break; + case 'p2_hub_blog_id': + $options[ $key ] = $site->get_p2_hub_blog_id(); + break; + + case 'site_creation_flow': + $site_creation_flow = $site->get_site_creation_flow(); + if ( $site_creation_flow ) { + $options[ $key ] = $site_creation_flow; + } + break; + case 'is_cloud_eligible': + $options[ $key ] = $site->is_cloud_eligible(); + break; + case 'selected_features': + $selected_features = $site->get_selected_features(); + if ( $selected_features ) { + $options[ $key ] = $selected_features; + } + break; + case 'anchor_podcast': + $options[ $key ] = $site->get_anchor_podcast(); + break; + case 'is_difm_lite_in_progress': + $options[ $key ] = $site->is_difm_lite_in_progress(); + break; + case 'site_intent': + $options[ $key ] = $site->get_site_intent(); + break; } } @@ -632,9 +707,6 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { $this->site = $this->get_platform()->get_site( $response->ID ); switch_to_blog( $this->site->get_id() ); - // ensure the response is marked as being from Jetpack - $response->jetpack = true; - $wpcom_response = $this->render_response_keys( self::$jetpack_response_field_additions ); foreach( $wpcom_response as $key => $value ) { @@ -658,7 +730,10 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { unset( $response->lang ); unset( $response->user_can_manage ); unset( $response->is_multisite ); + unset( $response->site_owner ); unset( $response->plan ); + unset( $response->products ); + unset( $response->zendesk_site_meta ); } // render additional options @@ -690,6 +765,8 @@ new WPCOM_JSON_API_List_Post_Formats_Endpoint( array( 'context' => false, ), + 'allow_fallback_to_jetpack_blog_token' => true, + 'response_format' => array( 'formats' => '(object) An object of supported post formats, each key a supported format slug mapped to its display string.', ) diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-site-v1-2-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-site-v1-2-endpoint.php index 5bcdf7a4..3531e5e8 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-site-v1-2-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-site-v1-2-endpoint.php @@ -12,6 +12,8 @@ new WPCOM_JSON_API_GET_Site_V1_2_Endpoint( array( '$site' => '(int|string) Site ID or domain', ), + 'allow_fallback_to_jetpack_blog_token' => true, + 'query_parameters' => array( 'context' => false, ), @@ -24,34 +26,38 @@ new WPCOM_JSON_API_GET_Site_V1_2_Endpoint( array( class WPCOM_JSON_API_GET_Site_V1_2_Endpoint extends WPCOM_JSON_API_GET_Site_Endpoint { public static $site_format = array( - 'ID' => '(int) Site ID', - 'name' => '(string) Title of site', - 'description' => '(string) Tagline or description of site', - 'URL' => '(string) Full URL to the site', - 'capabilities' => '(array) Array of capabilities for the current user on this site.', - 'jetpack' => '(bool) Whether the site is a Jetpack site or not', - 'is_multisite' => '(bool) Whether the site is a Multisite site or not. Always true for WP.com sites.', - 'post_count' => '(int) The number of posts the site has', - 'subscribers_count' => '(int) The number of subscribers the site has', - 'locale' => '(string) Primary locale code of the site', - 'icon' => '(array) An array of icon formats for the site', - 'logo' => '(array) The site logo, set in the Customizer', - 'visible' => '(bool) If this site is visible in the user\'s site list', - 'is_private' => '(bool) If the site is a private site or not', - 'is_coming_soon' => '(bool) If the site is a "coming soon" site or not', - 'single_user_site' => '(bool) Whether the site is single user. Only returned for WP.com sites and for Jetpack sites with version 3.4 or higher.', - 'is_vip' => '(bool) If the site is a VIP site or not.', - 'is_following' => '(bool) If the current user is subscribed to this site in the reader', - 'options' => '(array) An array of options/settings for the blog. Only viewable by users with post editing rights to the site. Note: Post formats is deprecated, please see /sites/$id/post-formats/', - 'plan' => '(array) Details of the current plan for this site.', - 'updates' => '(array) An array of available updates for plugins, themes, wordpress, and languages.', - 'jetpack_modules' => '(array) A list of active Jetpack modules.', - 'meta' => '(object) Meta data', - 'quota' => '(array) An array describing how much space a user has left for uploads', - 'launch_status' => '(string) A string describing the launch status of a site', - 'migration_status' => '(string) A string describing the migration status of the site.', - 'is_fse_active' => '(bool) If the site has Full Site Editing active or not.', - 'is_fse_eligible' => '(bool) If the site is capable of Full Site Editing or not', + 'ID' => '(int) Site ID', + 'name' => '(string) Title of site', + 'description' => '(string) Tagline or description of site', + 'URL' => '(string) Full URL to the site', + 'capabilities' => '(array) Array of capabilities for the current user on this site.', + 'jetpack' => '(bool) Whether the site is a Jetpack site or not', + 'jetpack_connection' => '(bool) Whether the site is connected to WP.com via `jetpack-connection`', + 'is_multisite' => '(bool) Whether the site is a Multisite site or not. Always true for WP.com sites.', + 'site_owner' => '(int) User ID of the site owner', + 'post_count' => '(int) The number of posts the site has', + 'subscribers_count' => '(int) The number of subscribers the site has', + 'locale' => '(string) Primary locale code of the site', + 'icon' => '(array) An array of icon formats for the site', + 'logo' => '(array) The site logo, set in the Customizer', + 'visible' => '(bool) If this site is visible in the user\'s site list', + 'is_private' => '(bool) If the site is a private site or not', + 'is_coming_soon' => '(bool) If the site is a "coming soon" site or not', + 'single_user_site' => '(bool) Whether the site is single user. Only returned for WP.com sites and for Jetpack sites with version 3.4 or higher.', + 'is_vip' => '(bool) If the site is a VIP site or not.', + 'is_following' => '(bool) If the current user is subscribed to this site in the reader', + 'options' => '(array) An array of options/settings for the blog. Only viewable by users with post editing rights to the site. Note: Post formats is deprecated, please see /sites/$id/post-formats/', + 'plan' => '(array) Details of the current plan for this site.', + 'updates' => '(array) An array of available updates for plugins, themes, wordpress, and languages.', + 'jetpack_modules' => '(array) A list of active Jetpack modules.', + 'meta' => '(object) Meta data', + 'quota' => '(array) An array describing how much space a user has left for uploads', + 'launch_status' => '(string) A string describing the launch status of a site', + 'site_migration' => '(array) Data about any migration into the site.', + 'is_fse_active' => '(bool) If the site has Full Site Editing active or not.', + 'is_fse_eligible' => '(bool) If the site is capable of Full Site Editing or not', + 'is_core_site_editor_enabled' => '(bool) If the site has the core site editor enabled.', + 'is_wpcom_atomic' => '(bool) If the site is a WP.com Atomic one.', ); diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-taxonomies-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-taxonomies-endpoint.php index 80b2469b..80e0506f 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-taxonomies-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-taxonomies-endpoint.php @@ -27,6 +27,9 @@ new WPCOM_JSON_API_Get_Taxonomies_Endpoint( array( 'found' => '(int) The number of categories returned.', 'categories' => '(array) Array of category objects.', ), + + 'allow_fallback_to_jetpack_blog_token' => true, + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/en.blog.wordpress.com/categories/?number=5' ) ); @@ -53,6 +56,9 @@ new WPCOM_JSON_API_Get_Taxonomies_Endpoint( array( 'count' => 'Order by the number of posts in each tag.', ), ), + + 'allow_fallback_to_jetpack_blog_token' => true, + 'response_format' => array( 'found' => '(int) The number of tags returned.', 'tags' => '(array) Array of tag objects.', diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-taxonomy-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-taxonomy-endpoint.php index 728fe463..548aa5f8 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-taxonomy-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-taxonomy-endpoint.php @@ -12,6 +12,8 @@ new WPCOM_JSON_API_Get_Taxonomy_Endpoint( array( '$category' => '(string) The category slug' ), + 'allow_fallback_to_jetpack_blog_token' => true, + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/en.blog.wordpress.com/categories/slug:community' ) ); @@ -27,6 +29,8 @@ new WPCOM_JSON_API_Get_Taxonomy_Endpoint( array( '$tag' => '(string) The tag slug' ), + 'allow_fallback_to_jetpack_blog_token' => true, + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/en.blog.wordpress.com/tags/slug:wordpresscom' ) ); diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-term-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-term-endpoint.php index 6546af74..0c5ec3f2 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-term-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-term-endpoint.php @@ -19,7 +19,10 @@ new WPCOM_JSON_API_Get_Term_Endpoint( array( 'post_count' => '(int) The number of posts using this term.', 'parent' => '(int) The parent ID for the term, if hierarchical.', ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/en.blog.wordpress.com/taxonomies/post_tag/terms/slug:wordpresscom' + + 'allow_fallback_to_jetpack_blog_token' => true, + + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/en.blog.wordpress.com/taxonomies/post_tag/terms/slug:wordpresscom', ) ); class WPCOM_JSON_API_Get_Term_Endpoint extends WPCOM_JSON_API_Endpoint { @@ -35,7 +38,7 @@ class WPCOM_JSON_API_Get_Term_Endpoint extends WPCOM_JSON_API_Endpoint { } $taxonomy_meta = get_taxonomy( $taxonomy ); - if ( false === $taxonomy_meta || ( ! $taxonomy_meta->public && + if ( false === $taxonomy_meta || ( ! $taxonomy_meta->public && ! current_user_can( $taxonomy_meta->cap->assign_terms ) ) ) { return new WP_Error( 'invalid_taxonomy', 'The taxonomy does not exist', 400 ); } diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-comments-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-comments-endpoint.php index 429e0161..f74869d1 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-comments-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-comments-endpoint.php @@ -72,7 +72,9 @@ new WPCOM_JSON_API_List_Comments_Endpoint( array( '$site' => '(int|string) Site ID or domain', ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/en.blog.wordpress.com/comments/?number=2' + 'allow_fallback_to_jetpack_blog_token' => true, + + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/en.blog.wordpress.com/comments/?number=2', ) ); new WPCOM_JSON_API_List_Comments_Endpoint( array( @@ -87,7 +89,9 @@ new WPCOM_JSON_API_List_Comments_Endpoint( array( '$post_ID' => '(int) The post ID', ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/en.blog.wordpress.com/posts/7/replies/?number=2' + 'allow_fallback_to_jetpack_blog_token' => true, + + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/en.blog.wordpress.com/posts/7/replies/?number=2', ) ); // @todo permissions diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-media-v1-1-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-media-v1-1-endpoint.php index 712909d9..1e084592 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-media-v1-1-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-media-v1-1-endpoint.php @@ -92,6 +92,12 @@ class WPCOM_JSON_API_List_Media_v1_1_Endpoint extends WPCOM_JSON_API_Endpoint { 'order' => isset( $args['order'] ) ? $args['order'] : 'DESC', 'orderby' => isset( $args['order_by'] ) ? $args['order_by'] : 'date', 's' => isset( $args['search'] ) ? $args['search'] : null, + 'meta_query' => array( + array( + 'key' => 'videopress_poster_image', + 'compare' => 'NOT EXISTS', + ), + ), ); if ( isset( $args['page'] ) ) { diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-post-types-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-post-types-endpoint.php index eb05630e..9d7adb98 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-post-types-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-post-types-endpoint.php @@ -11,6 +11,8 @@ new WPCOM_JSON_API_List_Post_Types_Endpoint( array ( '$site' => '(int|string) Site ID or domain', ), + 'allow_fallback_to_jetpack_blog_token' => true, + 'query_parameters' => array( 'api_queryable' => '(bool) If true, only queryable post types are returned', ), diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-posts-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-posts-endpoint.php index 2299124e..7f65a2e7 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-posts-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-posts-endpoint.php @@ -13,6 +13,8 @@ new WPCOM_JSON_API_List_Posts_Endpoint( array( '$site' => '(int|string) Site ID or domain', ), + 'allow_fallback_to_jetpack_blog_token' => true, + 'query_parameters' => array( 'number' => '(int=20) The number of posts to return. Limit: 100.', 'offset' => '(int=0) 0-indexed offset.', @@ -235,7 +237,7 @@ class WPCOM_JSON_API_List_Posts_Endpoint extends WPCOM_JSON_API_Post_Endpoint { $query['tax_query'] = array(); foreach ( $args['term'] as $taxonomy => $slug ) { $taxonomy_object = get_taxonomy( $taxonomy ); - if ( false === $taxonomy_object || ( ! $taxonomy_object->public && + if ( false === $taxonomy_object || ( ! $taxonomy_object->public && ! current_user_can( $taxonomy_object->cap->assign_terms ) ) ) { continue; } @@ -244,7 +246,7 @@ class WPCOM_JSON_API_List_Posts_Endpoint extends WPCOM_JSON_API_Post_Endpoint { 'taxonomy' => $taxonomy, 'field' => 'slug', 'terms' => explode( ',', $slug ) - ); + ); } } diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-posts-v1-1-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-posts-v1-1-endpoint.php index 36e99804..04d7ec02 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-posts-v1-1-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-posts-v1-1-endpoint.php @@ -1,71 +1,75 @@ <?php -new WPCOM_JSON_API_List_Posts_v1_1_Endpoint( array( - 'description' => 'Get a list of matching posts.', - 'min_version' => '1.1', - 'max_version' => '1.1', - - 'group' => 'posts', - 'stat' => 'posts', - - 'method' => 'GET', - 'path' => '/sites/%s/posts/', - 'path_labels' => array( - '$site' => '(int|string) Site ID or domain', - ), - - 'query_parameters' => array( - 'number' => '(int=20) The number of posts to return. Limit: 100.', - 'offset' => '(int=0) 0-indexed offset.', - 'page' => '(int) Return the Nth 1-indexed page of posts. Takes precedence over the <code>offset</code> parameter.', - 'page_handle' => '(string) A page handle, returned from a previous API call as a <code>meta.next_page</code> property. This is the most efficient way to fetch the next page of results.', - 'order' => array( - 'DESC' => 'Return posts in descending order. For dates, that means newest to oldest.', - 'ASC' => 'Return posts in ascending order. For dates, that means oldest to newest.', +new WPCOM_JSON_API_List_Posts_v1_1_Endpoint( + array( + 'description' => 'Get a list of matching posts.', + 'min_version' => '1.1', + 'max_version' => '1.1', + + 'group' => 'posts', + 'stat' => 'posts', + + 'method' => 'GET', + 'path' => '/sites/%s/posts/', + 'path_labels' => array( + '$site' => '(int|string) Site ID or domain', ), - 'order_by' => array( - 'date' => 'Order by the created time of each post.', - 'modified' => 'Order by the modified time of each post.', - 'title' => "Order lexicographically by the posts' titles.", - 'comment_count' => 'Order by the number of comments for each post.', - 'ID' => 'Order by post ID.', - ), - 'after' => '(ISO 8601 datetime) Return posts dated after the specified datetime.', - 'before' => '(ISO 8601 datetime) Return posts dated before the specified datetime.', - 'modified_after' => '(ISO 8601 datetime) Return posts modified after the specified datetime.', - 'modified_before' => '(ISO 8601 datetime) Return posts modified before the specified datetime.', - 'tag' => '(string) Specify the tag name or slug.', - 'category' => '(string) Specify the category name or slug.', - 'term' => '(object:string) Specify comma-separated term slugs to search within, indexed by taxonomy slug.', - 'type' => "(string) Specify the post type. Defaults to 'post', use 'any' to query for both posts and pages. Post types besides post and page need to be whitelisted using the <code>rest_api_allowed_post_types</code> filter.", - 'parent_id' => '(int) Returns only posts which are children of the specified post. Applies only to hierarchical post types.', - 'exclude' => '(array:int|int) Excludes the specified post ID(s) from the response', - 'exclude_tree' => '(int) Excludes the specified post and all of its descendants from the response. Applies only to hierarchical post types.', - 'status' => '(string) Comma-separated list of statuses for which to query, including any of: "publish", "private", "draft", "pending", "future", and "trash", or simply "any". Defaults to "publish"', - 'sticky' => array( - 'include' => 'Sticky posts are not excluded from the list.', - 'exclude' => 'Sticky posts are excluded from the list.', - 'require' => 'Only include sticky posts', + + 'allow_fallback_to_jetpack_blog_token' => true, + + 'query_parameters' => array( + 'number' => '(int=20) The number of posts to return. Limit: 100.', + 'offset' => '(int=0) 0-indexed offset.', + 'page' => '(int) Return the Nth 1-indexed page of posts. Takes precedence over the <code>offset</code> parameter.', + 'page_handle' => '(string) A page handle, returned from a previous API call as a <code>meta.next_page</code> property. This is the most efficient way to fetch the next page of results.', + 'order' => array( + 'DESC' => 'Return posts in descending order. For dates, that means newest to oldest.', + 'ASC' => 'Return posts in ascending order. For dates, that means oldest to newest.', + ), + 'order_by' => array( + 'date' => 'Order by the created time of each post.', + 'modified' => 'Order by the modified time of each post.', + 'title' => "Order lexicographically by the posts' titles.", + 'comment_count' => 'Order by the number of comments for each post.', + 'ID' => 'Order by post ID.', + ), + 'after' => '(ISO 8601 datetime) Return posts dated after the specified datetime.', + 'before' => '(ISO 8601 datetime) Return posts dated before the specified datetime.', + 'modified_after' => '(ISO 8601 datetime) Return posts modified after the specified datetime.', + 'modified_before' => '(ISO 8601 datetime) Return posts modified before the specified datetime.', + 'tag' => '(string) Specify the tag name or slug.', + 'category' => '(string) Specify the category name or slug.', + 'term' => '(object:string) Specify comma-separated term slugs to search within, indexed by taxonomy slug.', + 'type' => "(string) Specify the post type. Defaults to 'post', use 'any' to query for both posts and pages. Post types besides post and page need to be whitelisted using the <code>rest_api_allowed_post_types</code> filter.", + 'parent_id' => '(int) Returns only posts which are children of the specified post. Applies only to hierarchical post types.', + 'exclude' => '(array:int|int) Excludes the specified post ID(s) from the response', + 'exclude_tree' => '(int) Excludes the specified post and all of its descendants from the response. Applies only to hierarchical post types.', + 'status' => '(string) Comma-separated list of statuses for which to query, including any of: "publish", "private", "draft", "pending", "future", and "trash", or simply "any". Defaults to "publish"', + 'sticky' => array( + 'include' => 'Sticky posts are not excluded from the list.', + 'exclude' => 'Sticky posts are excluded from the list.', + 'require' => 'Only include sticky posts', + ), + 'author' => "(int) Author's user ID", + 'search' => '(string) Search query', + 'meta_key' => '(string) Metadata key that the post should contain', + 'meta_value' => '(string) Metadata value that the post should contain. Will only be applied if a `meta_key` is also given', ), - 'author' => "(int) Author's user ID", - 'search' => '(string) Search query', - 'meta_key' => '(string) Metadata key that the post should contain', - 'meta_value' => '(string) Metadata value that the post should contain. Will only be applied if a `meta_key` is also given', - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/en.blog.wordpress.com/posts/?number=2' -) ); + 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/en.blog.wordpress.com/posts/?number=2', + ) +); class WPCOM_JSON_API_List_Posts_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_Endpoint { - public $date_range = array(); - public $modified_range = array(); - public $page_handle = array(); + public $date_range = array(); + public $modified_range = array(); + public $page_handle = array(); public $performed_query = null; public $response_format = array( - 'found' => '(int) The total number of posts found that match the request (ignoring limits, offsets, and pagination).', - 'posts' => '(array:post) An array of post objects.', - 'meta' => '(object) Meta data', + 'found' => '(int) The total number of posts found that match the request (ignoring limits, offsets, and pagination).', + 'posts' => '(array:post) An array of post objects.', + 'meta' => '(object) Meta data', ); // /sites/%s/posts/ -> $blog_id @@ -75,14 +79,14 @@ class WPCOM_JSON_API_List_Posts_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_E return $blog_id; } - $args = $this->query_args(); + $args = $this->query_args(); $is_eligible_for_page_handle = true; - $site = $this->get_platform()->get_site( $blog_id ); + $site = $this->get_platform()->get_site( $blog_id ); if ( $args['number'] < 1 ) { $args['number'] = 20; } elseif ( 100 < $args['number'] ) { - return new WP_Error( 'invalid_number', 'The NUMBER parameter must be less than or equal to 100.', 400 ); + return new WP_Error( 'invalid_number', 'The NUMBER parameter must be less than or equal to 100.', 400 ); } if ( isset( $args['type'] ) && @@ -116,15 +120,18 @@ class WPCOM_JSON_API_List_Posts_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_E 'trash', 'any', ); - $status = array_intersect( $status, $statuses_whitelist ); + $status = array_intersect( $status, $statuses_whitelist ); } else { // logged-out users can see only published posts $statuses_whitelist = array( 'publish', 'any' ); - $status = array_intersect( $status, $statuses_whitelist ); + $status = array_intersect( $status, $statuses_whitelist ); if ( empty( $status ) ) { // requested only protected statuses? nothing for you here - return array( 'found' => 0, 'posts' => array() ); + return array( + 'found' => 0, + 'posts' => array(), + ); } // clear it (AKA published only) because "any" includes protected $status = array(); @@ -138,22 +145,26 @@ class WPCOM_JSON_API_List_Posts_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_E $allowed_types = array(); foreach ( $args['type'] as $post_type ) { if ( $site->current_user_can_access_post_type( $post_type, $args['context'] ) ) { - $allowed_types[] = $post_type; + $allowed_types[] = $post_type; } } if ( empty( $allowed_types ) ) { - return array( 'found' => 0, 'posts' => array() ); + return array( + 'found' => 0, + 'posts' => array(), + ); } $args['type'] = $allowed_types; - } - else { + } else { if ( ! $site->current_user_can_access_post_type( $args['type'], $args['context'] ) ) { - return array( 'found' => 0, 'posts' => array() ); + return array( + 'found' => 0, + 'posts' => array(), + ); } } - $query = array( 'posts_per_page' => $args['number'], 'order' => $args['order'], @@ -166,57 +177,64 @@ class WPCOM_JSON_API_List_Posts_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_E 'fields' => 'ids', ); - if ( ! is_user_logged_in () ) { + if ( ! is_user_logged_in() ) { $query['has_password'] = false; } if ( isset( $args['meta_key'] ) ) { $show = false; - if ( WPCOM_JSON_API_Metadata::is_public( $args['meta_key'] ) ) + if ( WPCOM_JSON_API_Metadata::is_public( $args['meta_key'] ) ) { $show = true; - if ( current_user_can( 'edit_post_meta', $query['post_type'], $args['meta_key'] ) ) + } + if ( current_user_can( 'edit_post_meta', $query['post_type'], $args['meta_key'] ) ) { $show = true; + } - if ( is_protected_meta( $args['meta_key'], 'post' ) && ! $show ) + if ( is_protected_meta( $args['meta_key'], 'post' ) && ! $show ) { return new WP_Error( 'invalid_meta_key', 'Invalid meta key', 404 ); + } $meta = array( 'key' => $args['meta_key'] ); - if ( isset( $args['meta_value'] ) ) + if ( isset( $args['meta_value'] ) ) { $meta['value'] = $args['meta_value']; + } $query['meta_query'] = array( $meta ); } if ( $args['sticky'] === 'include' ) { $query['ignore_sticky_posts'] = 1; - } else if ( $args['sticky'] === 'exclude' ) { + } elseif ( $args['sticky'] === 'exclude' ) { $sticky = get_option( 'sticky_posts' ); if ( is_array( $sticky ) ) { $query['post__not_in'] = $sticky; } - } else if ( $args['sticky'] === 'require' ) { + } elseif ( $args['sticky'] === 'require' ) { $sticky = get_option( 'sticky_posts' ); if ( is_array( $sticky ) && ! empty( $sticky ) ) { $query['post__in'] = $sticky; } else { // no sticky posts exist - return array( 'found' => 0, 'posts' => array() ); + return array( + 'found' => 0, + 'posts' => array(), + ); } } if ( isset( $args['exclude'] ) ) { - $excluded_ids = (array) $args['exclude']; + $excluded_ids = (array) $args['exclude']; $query['post__not_in'] = isset( $query['post__not_in'] ) ? array_merge( $query['post__not_in'], $excluded_ids ) : $excluded_ids; } if ( isset( $args['exclude_tree'] ) && is_post_type_hierarchical( $args['type'] ) ) { // get_page_children is a misnomer; it supports all hierarchical post types - $page_args = array( - 'child_of' => $args['exclude_tree'], - 'post_type' => $args['type'], - // since we're looking for things to exclude, be aggressive - 'post_status' => 'publish,draft,pending,private,future,trash', - ); + $page_args = array( + 'child_of' => $args['exclude_tree'], + 'post_type' => $args['type'], + // since we're looking for things to exclude, be aggressive + 'post_status' => 'publish,draft,pending,private,future,trash', + ); $post_descendants = get_pages( $page_args ); $exclude_tree = array( $args['exclude_tree'] ); @@ -229,7 +247,7 @@ class WPCOM_JSON_API_List_Posts_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_E if ( isset( $args['category'] ) ) { $category = get_term_by( 'slug', $args['category'], 'category' ); - if ( $category === false) { + if ( $category === false ) { $query['category_name'] = $args['category']; } else { $query['cat'] = $category->term_id; @@ -244,16 +262,16 @@ class WPCOM_JSON_API_List_Posts_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_E $query['tax_query'] = array(); foreach ( $args['term'] as $taxonomy => $slug ) { $taxonomy_object = get_taxonomy( $taxonomy ); - if ( false === $taxonomy_object || ( ! $taxonomy_object->public && + if ( false === $taxonomy_object || ( ! $taxonomy_object->public && ! current_user_can( $taxonomy_object->cap->assign_terms ) ) ) { continue; } $query['tax_query'][] = array( 'taxonomy' => $taxonomy, - 'field' => 'slug', - 'terms' => explode( ',', $slug ) - ); + 'field' => 'slug', + 'terms' => explode( ',', $slug ), + ); } } @@ -340,59 +358,62 @@ class WPCOM_JSON_API_List_Posts_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_E } - $return = array(); + $return = array(); $excluded_count = 0; foreach ( array_keys( $this->response_format ) as $key ) { switch ( $key ) { - case 'found' : - $return[$key] = (int) $wp_query->found_posts; - break; - case 'posts' : - $posts = array(); - foreach ( $wp_query->posts as $post_ID ) { - $the_post = $this->get_post_by( 'ID', $post_ID, $args['context'] ); - if ( $the_post && ! is_wp_error( $the_post ) ) { - $posts[] = $the_post; - } else { - $excluded_count++; + case 'found': + $return[ $key ] = (int) $wp_query->found_posts; + break; + case 'posts': + $posts = array(); + foreach ( $wp_query->posts as $post_ID ) { + $the_post = $this->get_post_by( 'ID', $post_ID, $args['context'] ); + if ( $the_post && ! is_wp_error( $the_post ) ) { + $posts[] = $the_post; + } else { + $excluded_count++; + } } - } - if ( $posts ) { - /** This action is documented in json-endpoints/class.wpcom-json-api-site-settings-endpoint.php */ - do_action( 'wpcom_json_api_objects', 'posts', count( $posts ) ); - } + if ( $posts ) { + /** This action is documented in json-endpoints/class.wpcom-json-api-site-settings-endpoint.php */ + do_action( 'wpcom_json_api_objects', 'posts', count( $posts ) ); + } - $return[$key] = $posts; - break; + $return[ $key ] = $posts; + break; - case 'meta' : - if ( ! is_array( $args['type'] ) ) { - $return[$key] = (object) array( - 'links' => (object) array( - 'counts' => (string) $this->links->get_site_link( $blog_id, 'post-counts/' . $args['type'] ), - ) - ); - } + case 'meta': + if ( ! is_array( $args['type'] ) ) { + $return[ $key ] = (object) array( + 'links' => (object) array( + 'counts' => (string) $this->links->get_site_link( $blog_id, 'post-counts/' . $args['type'] ), + ), + ); + } - if ( $is_eligible_for_page_handle && $return['posts'] ) { - $last_post = end( $return['posts'] ); - reset( $return['posts'] ); - if ( ( $return['found'] > count( $return['posts'] ) ) && $last_post ) { - if ( ! isset( $return[$key] ) ) { - $return[$key] = (object) array(); + if ( $is_eligible_for_page_handle && $return['posts'] ) { + $last_post = end( $return['posts'] ); + reset( $return['posts'] ); + if ( ( $return['found'] > count( $return['posts'] ) ) && $last_post ) { + if ( ! isset( $return[ $key ] ) ) { + $return[ $key ] = (object) array(); + } + if ( isset( $last_post['ID'] ) ) { + $return[ $key ]->next_page = $this->build_page_handle( $last_post, $query ); + } } - $return[$key]->next_page = $this->build_page_handle( $last_post, $query ); } - } - if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { - if ( !isset( $return[$key] ) ) - $return[$key] = new stdClass; - $return[$key]->wpcom = true; - } + if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { + if ( ! isset( $return[ $key ] ) ) { + $return[ $key ] = new stdClass(); + } + $return[ $key ]->wpcom = true; + } - break; + break; } } @@ -406,21 +427,26 @@ class WPCOM_JSON_API_List_Posts_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_E if ( ! $column ) { $column = 'date'; } - return build_query( array( 'value' => urlencode($post[$column]), 'id' => $post['ID'] ) ); + return build_query( + array( + 'value' => urlencode( $post[ $column ] ), + 'id' => $post['ID'], + ) + ); } function _build_date_range_query( $column, $range, $where ) { global $wpdb; switch ( count( $range ) ) { - case 2 : + case 2: $where .= $wpdb->prepare( " AND `$wpdb->posts`.$column >= CAST( %s AS DATETIME ) AND `$wpdb->posts`.$column < CAST( %s AS DATETIME ) ", $range['after'], $range['before'] ); break; - case 1 : + case 1: if ( isset( $range['before'] ) ) { $where .= $wpdb->prepare( " AND `$wpdb->posts`.$column < CAST( %s AS DATETIME ) ", @@ -467,31 +493,31 @@ class WPCOM_JSON_API_List_Posts_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_E } $db_column = ''; - $db_value = ''; - switch( $column ) { + $db_value = ''; + switch ( $column ) { case 'ID': $db_column = 'ID'; - $db_value = '%d'; + $db_value = '%d'; break; case 'title': $db_column = 'post_title'; - $db_value = '%s'; + $db_value = '%s'; break; case 'date': $db_column = 'post_date'; - $db_value = 'CAST( %s as DATETIME )'; + $db_value = 'CAST( %s as DATETIME )'; break; case 'modified': $db_column = 'post_modified'; - $db_value = 'CAST( %s as DATETIME )'; + $db_value = 'CAST( %s as DATETIME )'; break; case 'comment_count': $db_column = 'comment_count'; - $db_value = '%d'; + $db_value = '%d'; break; } - if ( 'DESC'=== $order ) { + if ( 'DESC' === $order ) { $db_order = '<'; } else { $db_order = '>'; diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-posts-v1-2-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-posts-v1-2-endpoint.php index 7b01d2f2..e4f7bd55 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-posts-v1-2-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-posts-v1-2-endpoint.php @@ -1,61 +1,65 @@ <?php -new WPCOM_JSON_API_List_Posts_v1_2_Endpoint( array( - 'description' => 'Get a list of matching posts.', - 'min_version' => '1.2', - 'max_version' => '1.2', - - 'group' => 'posts', - 'stat' => 'posts', - - 'method' => 'GET', - 'path' => '/sites/%s/posts/', - 'path_labels' => array( - '$site' => '(int|string) Site ID or domain', - ), - - 'query_parameters' => array( - 'number' => '(int=20) The number of posts to return. Limit: 100.', - 'offset' => '(int=0) 0-indexed offset.', - 'page' => '(int) Return the Nth 1-indexed page of posts. Takes precedence over the <code>offset</code> parameter.', - 'page_handle' => '(string) A page handle, returned from a previous API call as a <code>meta.next_page</code> property. This is the most efficient way to fetch the next page of results.', - 'order' => array( - 'DESC' => 'Return posts in descending order. For dates, that means newest to oldest.', - 'ASC' => 'Return posts in ascending order. For dates, that means oldest to newest.', +new WPCOM_JSON_API_List_Posts_v1_2_Endpoint( + array( + 'description' => 'Get a list of matching posts.', + 'min_version' => '1.2', + 'max_version' => '1.2', + + 'group' => 'posts', + 'stat' => 'posts', + + 'method' => 'GET', + 'path' => '/sites/%s/posts/', + 'path_labels' => array( + '$site' => '(int|string) Site ID or domain', ), - 'order_by' => array( - 'date' => 'Order by the created time of each post.', - 'modified' => 'Order by the modified time of each post.', - 'title' => "Order lexicographically by the posts' titles.", - 'comment_count' => 'Order by the number of comments for each post.', - 'ID' => 'Order by post ID.', - ), - 'after' => '(ISO 8601 datetime) Return posts dated after the specified datetime.', - 'before' => '(ISO 8601 datetime) Return posts dated before the specified datetime.', - 'modified_after' => '(ISO 8601 datetime) Return posts modified after the specified datetime.', - 'modified_before' => '(ISO 8601 datetime) Return posts modified before the specified datetime.', - 'tag' => '(string) Specify the tag name or slug.', - 'category' => '(string) Specify the category name or slug.', - 'term' => '(object:string) Specify comma-separated term slugs to search within, indexed by taxonomy slug.', - 'type' => "(string) Specify the post type. Defaults to 'post', use 'any' to query for both posts and pages. Post types besides post and page need to be whitelisted using the <code>rest_api_allowed_post_types</code> filter.", - 'exclude_private_types' => '(bool=false) Use this flag together with `type=any` to get only publicly accessible posts.', - 'parent_id' => '(int) Returns only posts which are children of the specified post. Applies only to hierarchical post types.', - 'exclude' => '(array:int|int) Excludes the specified post ID(s) from the response', - 'exclude_tree' => '(int) Excludes the specified post and all of its descendants from the response. Applies only to hierarchical post types.', - 'status' => '(string) Comma-separated list of statuses for which to query, including any of: "publish", "private", "draft", "pending", "future", and "trash", or simply "any". Defaults to "publish"', - 'sticky' => array( - 'include' => 'Sticky posts are not excluded from the list.', - 'exclude' => 'Sticky posts are excluded from the list.', - 'require' => 'Only include sticky posts', + + 'allow_fallback_to_jetpack_blog_token' => true, + + 'query_parameters' => array( + 'number' => '(int=20) The number of posts to return. Limit: 100.', + 'offset' => '(int=0) 0-indexed offset.', + 'page' => '(int) Return the Nth 1-indexed page of posts. Takes precedence over the <code>offset</code> parameter.', + 'page_handle' => '(string) A page handle, returned from a previous API call as a <code>meta.next_page</code> property. This is the most efficient way to fetch the next page of results.', + 'order' => array( + 'DESC' => 'Return posts in descending order. For dates, that means newest to oldest.', + 'ASC' => 'Return posts in ascending order. For dates, that means oldest to newest.', + ), + 'order_by' => array( + 'date' => 'Order by the created time of each post.', + 'modified' => 'Order by the modified time of each post.', + 'title' => "Order lexicographically by the posts' titles.", + 'comment_count' => 'Order by the number of comments for each post.', + 'ID' => 'Order by post ID.', + ), + 'after' => '(ISO 8601 datetime) Return posts dated after the specified datetime.', + 'before' => '(ISO 8601 datetime) Return posts dated before the specified datetime.', + 'modified_after' => '(ISO 8601 datetime) Return posts modified after the specified datetime.', + 'modified_before' => '(ISO 8601 datetime) Return posts modified before the specified datetime.', + 'tag' => '(string) Specify the tag name or slug.', + 'category' => '(string) Specify the category name or slug.', + 'term' => '(object:string) Specify comma-separated term slugs to search within, indexed by taxonomy slug.', + 'type' => "(string) Specify the post type. Defaults to 'post', use 'any' to query for both posts and pages. Post types besides post and page need to be whitelisted using the <code>rest_api_allowed_post_types</code> filter.", + 'exclude_private_types' => '(bool=false) Use this flag together with `type=any` to get only publicly accessible posts.', + 'parent_id' => '(int) Returns only posts which are children of the specified post. Applies only to hierarchical post types.', + 'exclude' => '(array:int|int) Excludes the specified post ID(s) from the response', + 'exclude_tree' => '(int) Excludes the specified post and all of its descendants from the response. Applies only to hierarchical post types.', + 'status' => '(string) Comma-separated list of statuses for which to query, including any of: "publish", "private", "draft", "pending", "future", and "trash", or simply "any". Defaults to "publish"', + 'sticky' => array( + 'include' => 'Sticky posts are not excluded from the list.', + 'exclude' => 'Sticky posts are excluded from the list.', + 'require' => 'Only include sticky posts', + ), + 'author' => "(int) Author's user ID", + 'search' => '(string) Search query', + 'meta_key' => '(string) Metadata key that the post should contain', + 'meta_value' => '(string) Metadata value that the post should contain. Will only be applied if a `meta_key` is also given', ), - 'author' => "(int) Author's user ID", - 'search' => '(string) Search query', - 'meta_key' => '(string) Metadata key that the post should contain', - 'meta_value' => '(string) Metadata value that the post should contain. Will only be applied if a `meta_key` is also given', - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.2/sites/en.blog.wordpress.com/posts/?number=2' -) ); + 'example_request' => 'https://public-api.wordpress.com/rest/v1.2/sites/en.blog.wordpress.com/posts/?number=2', + ) +); class WPCOM_JSON_API_List_Posts_v1_2_Endpoint extends WPCOM_JSON_API_List_Posts_v1_1_Endpoint { // /sites/%s/posts/ -> $blog_id @@ -65,14 +69,14 @@ class WPCOM_JSON_API_List_Posts_v1_2_Endpoint extends WPCOM_JSON_API_List_Posts_ return $blog_id; } - $args = $this->query_args(); + $args = $this->query_args(); $is_eligible_for_page_handle = true; - $site = $this->get_platform()->get_site( $blog_id ); + $site = $this->get_platform()->get_site( $blog_id ); if ( $args['number'] < 1 ) { $args['number'] = 20; } elseif ( 100 < $args['number'] ) { - return new WP_Error( 'invalid_number', 'The NUMBER parameter must be less than or equal to 100.', 400 ); + return new WP_Error( 'invalid_number', 'The NUMBER parameter must be less than or equal to 100.', 400 ); } if ( isset( $args['type'] ) ) { @@ -91,7 +95,7 @@ class WPCOM_JSON_API_List_Posts_v1_2_Endpoint extends WPCOM_JSON_API_List_Posts_ if ( isset( $args['exclude_private_types'] ) && $args['exclude_private_types'] == true ) { $public_post_types = get_post_types( array( 'public' => true ) ); - $args['type'] = array_intersect( $public_post_types, $whitelisted_post_types ); + $args['type'] = array_intersect( $public_post_types, $whitelisted_post_types ); } else { $args['type'] = $whitelisted_post_types; } @@ -111,13 +115,18 @@ class WPCOM_JSON_API_List_Posts_v1_2_Endpoint extends WPCOM_JSON_API_List_Posts_ } if ( empty( $allowed_types ) ) { - return array( 'found' => 0, 'posts' => array() ); + return array( + 'found' => 0, + 'posts' => array(), + ); } $args['type'] = $allowed_types; - } - else { + } else { if ( ! $site->current_user_can_access_post_type( $args['type'], $args['context'] ) ) { - return array( 'found' => 0, 'posts' => array() ); + return array( + 'found' => 0, + 'posts' => array(), + ); } } @@ -133,15 +142,18 @@ class WPCOM_JSON_API_List_Posts_v1_2_Endpoint extends WPCOM_JSON_API_List_Posts_ 'trash', 'any', ); - $status = array_intersect( $status, $statuses_whitelist ); + $status = array_intersect( $status, $statuses_whitelist ); } else { // logged-out users can see only published posts $statuses_whitelist = array( 'publish', 'any' ); - $status = array_intersect( $status, $statuses_whitelist ); + $status = array_intersect( $status, $statuses_whitelist ); if ( empty( $status ) ) { // requested only protected statuses? nothing for you here - return array( 'found' => 0, 'posts' => array() ); + return array( + 'found' => 0, + 'posts' => array(), + ); } // clear it (AKA published only) because "any" includes protected $status = array(); @@ -159,57 +171,64 @@ class WPCOM_JSON_API_List_Posts_v1_2_Endpoint extends WPCOM_JSON_API_List_Posts_ 'fields' => 'ids', ); - if ( ! is_user_logged_in () ) { + if ( ! is_user_logged_in() ) { $query['has_password'] = false; } if ( isset( $args['meta_key'] ) ) { $show = false; - if ( WPCOM_JSON_API_Metadata::is_public( $args['meta_key'] ) ) + if ( WPCOM_JSON_API_Metadata::is_public( $args['meta_key'] ) ) { $show = true; - if ( current_user_can( 'edit_post_meta', $query['post_type'], $args['meta_key'] ) ) + } + if ( current_user_can( 'edit_post_meta', $query['post_type'], $args['meta_key'] ) ) { $show = true; + } - if ( is_protected_meta( $args['meta_key'], 'post' ) && ! $show ) + if ( is_protected_meta( $args['meta_key'], 'post' ) && ! $show ) { return new WP_Error( 'invalid_meta_key', 'Invalid meta key', 404 ); + } $meta = array( 'key' => $args['meta_key'] ); - if ( isset( $args['meta_value'] ) ) + if ( isset( $args['meta_value'] ) ) { $meta['value'] = $args['meta_value']; + } $query['meta_query'] = array( $meta ); } if ( $args['sticky'] === 'include' ) { $query['ignore_sticky_posts'] = 1; - } else if ( $args['sticky'] === 'exclude' ) { + } elseif ( $args['sticky'] === 'exclude' ) { $sticky = get_option( 'sticky_posts' ); if ( is_array( $sticky ) ) { $query['post__not_in'] = $sticky; } - } else if ( $args['sticky'] === 'require' ) { + } elseif ( $args['sticky'] === 'require' ) { $sticky = get_option( 'sticky_posts' ); if ( is_array( $sticky ) && ! empty( $sticky ) ) { $query['post__in'] = $sticky; } else { // no sticky posts exist - return array( 'found' => 0, 'posts' => array() ); + return array( + 'found' => 0, + 'posts' => array(), + ); } } if ( isset( $args['exclude'] ) ) { - $excluded_ids = (array) $args['exclude']; + $excluded_ids = (array) $args['exclude']; $query['post__not_in'] = isset( $query['post__not_in'] ) ? array_merge( $query['post__not_in'], $excluded_ids ) : $excluded_ids; } if ( isset( $args['exclude_tree'] ) && is_post_type_hierarchical( $args['type'] ) ) { // get_page_children is a misnomer; it supports all hierarchical post types - $page_args = array( - 'child_of' => $args['exclude_tree'], - 'post_type' => $args['type'], - // since we're looking for things to exclude, be aggressive - 'post_status' => 'publish,draft,pending,private,future,trash', - ); + $page_args = array( + 'child_of' => $args['exclude_tree'], + 'post_type' => $args['type'], + // since we're looking for things to exclude, be aggressive + 'post_status' => 'publish,draft,pending,private,future,trash', + ); $post_descendants = get_pages( $page_args ); $exclude_tree = array( $args['exclude_tree'] ); @@ -222,7 +241,7 @@ class WPCOM_JSON_API_List_Posts_v1_2_Endpoint extends WPCOM_JSON_API_List_Posts_ if ( isset( $args['category'] ) ) { $category = get_term_by( 'slug', $args['category'], 'category' ); - if ( $category === false) { + if ( $category === false ) { $query['category_name'] = $args['category']; } else { $query['cat'] = $category->term_id; @@ -244,8 +263,8 @@ class WPCOM_JSON_API_List_Posts_v1_2_Endpoint extends WPCOM_JSON_API_List_Posts_ $query['tax_query'][] = array( 'taxonomy' => $taxonomy, - 'field' => 'slug', - 'terms' => explode( ',', $slug ) + 'field' => 'slug', + 'terms' => explode( ',', $slug ), ); } } @@ -333,59 +352,63 @@ class WPCOM_JSON_API_List_Posts_v1_2_Endpoint extends WPCOM_JSON_API_List_Posts_ } - $return = array(); + $return = array(); $excluded_count = 0; foreach ( array_keys( $this->response_format ) as $key ) { switch ( $key ) { - case 'found' : - $return[$key] = (int) $wp_query->found_posts; - break; - case 'posts' : - $posts = array(); - foreach ( $wp_query->posts as $post_ID ) { - $the_post = $this->get_post_by( 'ID', $post_ID, $args['context'] ); - if ( $the_post && ! is_wp_error( $the_post ) ) { - $posts[] = $the_post; - } else { - $excluded_count++; + case 'found': + $return[ $key ] = (int) $wp_query->found_posts; + break; + case 'posts': + $posts = array(); + foreach ( $wp_query->posts as $post_ID ) { + $the_post = $this->get_post_by( 'ID', $post_ID, $args['context'] ); + if ( $the_post && ! is_wp_error( $the_post ) ) { + $posts[] = $the_post; + } else { + $excluded_count++; + } } - } - if ( $posts ) { - /** This action is documented in json-endpoints/class.wpcom-json-api-site-settings-endpoint.php */ - do_action( 'wpcom_json_api_objects', 'posts', count( $posts ) ); - } + if ( $posts ) { + /** This action is documented in json-endpoints/class.wpcom-json-api-site-settings-endpoint.php */ + do_action( 'wpcom_json_api_objects', 'posts', count( $posts ) ); + } - $return[$key] = $posts; - break; + $return[ $key ] = $posts; + break; - case 'meta' : - if ( ! is_array( $args['type'] ) ) { - $return[$key] = (object) array( - 'links' => (object) array( - 'counts' => (string) $this->links->get_site_link( $blog_id, 'post-counts/' . $args['type'] ), - ) - ); - } + case 'meta': + if ( ! is_array( $args['type'] ) ) { + $return[ $key ] = (object) array( + 'links' => (object) array( + 'counts' => (string) $this->links->get_site_link( $blog_id, 'post-counts/' . $args['type'] ), + ), + ); + } - if ( $is_eligible_for_page_handle && $return['posts'] ) { - $last_post = end( $return['posts'] ); - reset( $return['posts'] ); - if ( ( $return['found'] > count( $return['posts'] ) ) && $last_post ) { - if ( ! isset( $return[$key] ) ) { - $return[$key] = (object) array(); + if ( $is_eligible_for_page_handle && $return['posts'] ) { + $last_post = end( $return['posts'] ); + reset( $return['posts'] ); + if ( ( $return['found'] > count( $return['posts'] ) ) && $last_post ) { + if ( ! isset( $return[ $key ] ) ) { + $return[ $key ] = (object) array(); + } + + if ( isset( $last_post['ID'] ) ) { + $return[ $key ]->next_page = $this->build_page_handle( $last_post, $query ); + } } - $return[$key]->next_page = $this->build_page_handle( $last_post, $query ); } - } - if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { - if ( !isset( $return[$key] ) ) - $return[$key] = new stdClass; - $return[$key]->wpcom = true; - } + if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { + if ( ! isset( $return[ $key ] ) ) { + $return[ $key ] = new stdClass(); + } + $return[ $key ]->wpcom = true; + } - break; + break; } } @@ -399,21 +422,26 @@ class WPCOM_JSON_API_List_Posts_v1_2_Endpoint extends WPCOM_JSON_API_List_Posts_ if ( ! $column ) { $column = 'date'; } - return build_query( array( 'value' => urlencode($post[$column]), 'id' => $post['ID'] ) ); + return build_query( + array( + 'value' => urlencode( $post[ $column ] ), + 'id' => $post['ID'], + ) + ); } function _build_date_range_query( $column, $range, $where ) { global $wpdb; switch ( count( $range ) ) { - case 2 : + case 2: $where .= $wpdb->prepare( " AND `$wpdb->posts`.$column >= CAST( %s AS DATETIME ) AND `$wpdb->posts`.$column < CAST( %s AS DATETIME ) ", $range['after'], $range['before'] ); break; - case 1 : + case 1: if ( isset( $range['before'] ) ) { $where .= $wpdb->prepare( " AND `$wpdb->posts`.$column < CAST( %s AS DATETIME ) ", diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-roles-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-roles-endpoint.php index 733f26f7..f40429b9 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-roles-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-roles-endpoint.php @@ -130,6 +130,17 @@ class WPCOM_JSON_API_List_Roles_Endpoint extends WPCOM_JSON_API_Endpoint { // Sort the array so roles with the most number of capabilities comes first, then the next role, and so on usort( $roles, array( 'self', 'role_sort' ) ); + /** + * Filter for curating the list of roles available for a wpcom site. + * + * @module json-api + * + * @since 8.7.0 + * + * @param array $roles List of role objects available to the site. + */ + $roles = apply_filters( 'wpcom_api_site_roles', $roles ); + return array( 'roles' => $roles ); } } diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-terms-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-terms-endpoint.php index 83edcfc9..f05d852e 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-terms-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-terms-endpoint.php @@ -24,6 +24,9 @@ new WPCOM_JSON_API_List_Terms_Endpoint( array( 'count' => 'Order by the number of posts in each tag.', ), ), + + 'allow_fallback_to_jetpack_blog_token' => true, + 'response_format' => array( 'found' => '(int) The number of terms returned.', 'terms' => '(array) Array of tag objects.', @@ -44,7 +47,7 @@ class WPCOM_JSON_API_List_Terms_Endpoint extends WPCOM_JSON_API_Endpoint { } $taxonomy_meta = get_taxonomy( $taxonomy ); - if ( false === $taxonomy_meta || ( ! $taxonomy_meta->public && + if ( false === $taxonomy_meta || ( ! $taxonomy_meta->public && ! current_user_can( $taxonomy_meta->cap->assign_terms ) ) ) { return new WP_Error( 'invalid_taxonomy', 'The taxonomy does not exist', 400 ); } diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-post-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-post-endpoint.php index 917c7d7a..6b1b1dd1 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-post-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-post-endpoint.php @@ -416,7 +416,6 @@ abstract class WPCOM_JSON_API_Post_Endpoint extends WPCOM_JSON_API_Endpoint { if ( current_user_can( 'edit_post_meta', $post_id , $meta['meta_key'] ) ) $show = true; - // Only business plan subscribers can view custom meta description. if ( Jetpack_SEO_Posts::DESCRIPTION_META_KEY === $meta['meta_key'] && ! Jetpack_SEO_Utils::is_enabled_jetpack_seo() ) { $show = false; } @@ -534,40 +533,77 @@ abstract class WPCOM_JSON_API_Post_Endpoint extends WPCOM_JSON_API_Endpoint { unset( $attr['orderby'] ); } - extract( shortcode_atts( array( - 'order' => 'ASC', - 'orderby' => 'menu_order ID', - 'id' => $post->ID, - 'include' => '', - 'exclude' => '', - 'slideshow' => false - ), $attr, 'gallery' ) ); + $atts = shortcode_atts( + array( + 'order' => 'ASC', + 'orderby' => 'menu_order ID', + 'id' => $post->ID, + 'include' => '', + 'exclude' => '', + 'slideshow' => false, + ), + $attr, + 'gallery' + ); + $id = ! empty( $atts['id'] ) ? (int) $atts['id'] : 0; - // Custom image size and always use it + // Custom image size and always use it. add_image_size( 'win8app-column', 480 ); $size = 'win8app-column'; - $id = intval( $id ); - if ( 'RAND' === $order ) + if ( 'RAND' === $atts['order'] ) { $orderby = 'none'; + } else { + $orderby = $atts['orderby']; + } - if ( !empty( $include ) ) { - $include = preg_replace( '/[^0-9,]+/', '', $include ); - $_attachments = get_posts( array( 'include' => $include, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby ) ); + if ( ! empty( $atts['include'] ) ) { + $include = preg_replace( '/[^0-9,]+/', '', $atts['include'] ); + $_attachments = get_posts( + array( + 'include' => $include, + 'post_status' => 'inherit', + 'post_type' => 'attachment', + 'post_mime_type' => 'image', + 'order' => $atts['order'], + 'orderby' => $orderby, + ) + ); $attachments = array(); foreach ( $_attachments as $key => $val ) { - $attachments[$val->ID] = $_attachments[$key]; + $attachments[ $val->ID ] = $_attachments[ $key ]; } - } elseif ( !empty( $exclude ) ) { - $exclude = preg_replace( '/[^0-9,]+/', '', $exclude ); - $attachments = get_children( array( 'post_parent' => $id, 'exclude' => $exclude, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby ) ); + } elseif ( ! empty( $atts['exclude'] ) ) { + $exclude = preg_replace( '/[^0-9,]+/', '', $atts['exclude'] ); + $attachments = get_children( + array( + 'post_parent' => $id, + 'exclude' => $exclude, + 'post_status' => 'inherit', + 'post_type' => 'attachment', + 'post_mime_type' => 'image', + 'order' => $atts['order'], + 'orderby' => $orderby, + ) + ); } else { - $attachments = get_children( array( 'post_parent' => $id, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby ) ); + $attachments = get_children( + array( + 'post_parent' => $id, + 'post_status' => 'inherit', + 'post_type' => 'attachment', + 'post_mime_type' => 'image', + 'order' => $atts['order'], + 'orderby' => $orderby, + ) + ); } if ( ! empty( $attachments ) ) { foreach ( $attachments as $id => $attachment ) { - $link = isset( $attr['link'] ) && 'file' === $attr['link'] ? wp_get_attachment_link( $id, $size, false, false ) : wp_get_attachment_link( $id, $size, true, false ); + $link = isset( $attr['link'] ) && 'file' === $attr['link'] + ? wp_get_attachment_link( $id, $size, false, false ) + : wp_get_attachment_link( $id, $size, true, false ); if ( $captiontag && trim($attachment->post_excerpt) ) { $output .= "<div class='wp-caption aligncenter'>$link diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-post-v1-1-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-post-v1-1-endpoint.php index febf76bd..73f5f559 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-post-v1-1-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-post-v1-1-endpoint.php @@ -339,40 +339,77 @@ abstract class WPCOM_JSON_API_Post_v1_1_Endpoint extends WPCOM_JSON_API_Endpoint unset( $attr['orderby'] ); } - extract( shortcode_atts( array( - 'order' => 'ASC', - 'orderby' => 'menu_order ID', - 'id' => $post->ID, - 'include' => '', - 'exclude' => '', - 'slideshow' => false - ), $attr, 'gallery' ) ); - - // Custom image size and always use it + $atts = shortcode_atts( + array( + 'order' => 'ASC', + 'orderby' => 'menu_order ID', + 'id' => $post->ID, + 'include' => '', + 'exclude' => '', + 'slideshow' => false, + ), + $attr, + 'gallery' + ); + $id = ! empty( $atts['id'] ) ? (int) $atts['id'] : 0; + + // Custom image size and always use it. add_image_size( 'win8app-column', 480 ); $size = 'win8app-column'; - $id = intval( $id ); - if ( 'RAND' === $order ) + if ( 'RAND' === $atts['order'] ) { $orderby = 'none'; + } else { + $orderby = $atts['orderby']; + } - if ( !empty( $include ) ) { - $include = preg_replace( '/[^0-9,]+/', '', $include ); - $_attachments = get_posts( array( 'include' => $include, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby ) ); + if ( ! empty( $atts['include'] ) ) { + $include = preg_replace( '/[^0-9,]+/', '', $atts['include'] ); + $_attachments = get_posts( + array( + 'include' => $include, + 'post_status' => 'inherit', + 'post_type' => 'attachment', + 'post_mime_type' => 'image', + 'order' => $atts['order'], + 'orderby' => $orderby, + ) + ); $attachments = array(); foreach ( $_attachments as $key => $val ) { - $attachments[$val->ID] = $_attachments[$key]; + $attachments[ $val->ID ] = $_attachments[ $key ]; } - } elseif ( !empty( $exclude ) ) { - $exclude = preg_replace( '/[^0-9,]+/', '', $exclude ); - $attachments = get_children( array( 'post_parent' => $id, 'exclude' => $exclude, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby ) ); + } elseif ( ! empty( $atts['exclude'] ) ) { + $exclude = preg_replace( '/[^0-9,]+/', '', $atts['exclude'] ); + $attachments = get_children( + array( + 'post_parent' => $id, + 'exclude' => $exclude, + 'post_status' => 'inherit', + 'post_type' => 'attachment', + 'post_mime_type' => 'image', + 'order' => $atts['order'], + 'orderby' => $orderby, + ) + ); } else { - $attachments = get_children( array( 'post_parent' => $id, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'order' => $order, 'orderby' => $orderby ) ); + $attachments = get_children( + array( + 'post_parent' => $id, + 'post_status' => 'inherit', + 'post_type' => 'attachment', + 'post_mime_type' => 'image', + 'order' => $atts['order'], + 'orderby' => $orderby, + ) + ); } if ( ! empty( $attachments ) ) { foreach ( $attachments as $id => $attachment ) { - $link = isset( $attr['link'] ) && 'file' === $attr['link'] ? wp_get_attachment_link( $id, $size, false, false ) : wp_get_attachment_link( $id, $size, true, false ); + $link = isset( $attr['link'] ) && 'file' === $attr['link'] + ? wp_get_attachment_link( $id, $size, false, false ) + : wp_get_attachment_link( $id, $size, true, false ); if ( $captiontag && trim($attachment->post_excerpt) ) { $output .= "<div class='wp-caption aligncenter'>$link diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-render-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-render-endpoint.php index f2de7fc3..fa8562bf 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-render-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-render-endpoint.php @@ -15,6 +15,10 @@ abstract class WPCOM_JSON_API_Render_Endpoint extends WPCOM_JSON_API_Endpoint { function process_render( $callback, $callback_arg ) { global $wp_scripts, $wp_styles; + if ( false === defined( 'STYLESHEETPATH' ) ) { + wp_templating_constants(); + } + // initial scripts & styles (to subtract) ob_start(); wp_head(); @@ -142,4 +146,4 @@ abstract class WPCOM_JSON_API_Render_Endpoint extends WPCOM_JSON_API_Endpoint { global $wp_embed; return $wp_embed->shortcode( array(), $embed_url ); } -}
\ No newline at end of file +} diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-settings-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-settings-endpoint.php index d55a7e9b..ca8e1ec3 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-settings-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-settings-endpoint.php @@ -1,146 +1,172 @@ -<?php - -new WPCOM_JSON_API_Site_Settings_Endpoint( array( - 'description' => 'Get detailed settings information about a site.', - 'group' => '__do_not_document', - 'stat' => 'sites:X', - 'max_version' => '1.1', - 'new_version' => '1.2', - 'method' => 'GET', - 'path' => '/sites/%s/settings', - 'path_labels' => array( - '$site' => '(int|string) Site ID or domain', - ), - - 'query_parameters' => array( - 'context' => false, - ), - - 'response_format' => WPCOM_JSON_API_Site_Settings_Endpoint::$site_format, - - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/en.blog.wordpress.com/settings', -) ); - -new WPCOM_JSON_API_Site_Settings_Endpoint( array( - 'description' => 'Update settings for a site.', - 'group' => '__do_not_document', - 'stat' => 'sites:X', - 'max_version' => '1.1', - 'new_version' => '1.2', - 'method' => 'POST', - 'path' => '/sites/%s/settings', - 'path_labels' => array( - '$site' => '(int|string) Site ID or domain', - ), - - 'request_format' => array( - 'blogname' => '(string) Blog name', - 'blogdescription' => '(string) Blog description', - 'default_pingback_flag' => '(bool) Notify blogs linked from article?', - 'default_ping_status' => '(bool) Allow link notifications from other blogs?', - 'default_comment_status' => '(bool) Allow comments on new articles?', - 'blog_public' => '(string) Site visibility; -1: private, 0: discourage search engines, 1: allow search engines', - 'jetpack_sync_non_public_post_stati' => '(bool) allow sync of post and pages with non-public posts stati', - 'jetpack_relatedposts_enabled' => '(bool) Enable related posts?', - 'jetpack_relatedposts_show_headline' => '(bool) Show headline in related posts?', - 'jetpack_relatedposts_show_thumbnails' => '(bool) Show thumbnails in related posts?', - 'jetpack_protect_whitelist' => '(array) List of IP addresses to whitelist', - 'jetpack_search_enabled' => '(bool) Enable Jetpack Search', - 'jetpack_search_supported' => '(bool) Jetpack Search is supported', - 'infinite_scroll' => '(bool) Support infinite scroll of posts?', - 'default_category' => '(int) Default post category', - 'default_post_format' => '(string) Default post format', - 'require_name_email' => '(bool) Require comment authors to fill out name and email?', - 'comment_registration' => '(bool) Require users to be registered and logged in to comment?', - 'close_comments_for_old_posts' => '(bool) Automatically close comments on old posts?', - 'close_comments_days_old' => '(int) Age at which to close comments', - 'thread_comments' => '(bool) Enable threaded comments?', - 'thread_comments_depth' => '(int) Depth to thread comments', - 'page_comments' => '(bool) Break comments into pages?', - 'comments_per_page' => '(int) Number of comments to display per page', - 'default_comments_page' => '(string) newest|oldest Which page of comments to display first', - 'comment_order' => '(string) asc|desc Order to display comments within page', - 'comments_notify' => '(bool) Email me when someone comments?', - 'moderation_notify' => '(bool) Email me when a comment is helf for moderation?', - 'social_notifications_like' => '(bool) Email me when someone likes my post?', - 'social_notifications_reblog' => '(bool) Email me when someone reblogs my post?', - 'social_notifications_subscribe' => '(bool) Email me when someone follows my blog?', - 'comment_moderation' => '(bool) Moderate comments for manual approval?', - 'comment_whitelist' => '(bool) Moderate comments unless author has a previously-approved comment?', - 'comment_max_links' => '(int) Moderate comments that contain X or more links', - 'moderation_keys' => '(string) Words or phrases that trigger comment moderation, one per line', - 'blacklist_keys' => '(string) Words or phrases that mark comment spam, one per line', - 'lang_id' => '(int) ID for language blog is written in', - 'wga' => '(array) Google Analytics Settings', - 'disabled_likes' => '(bool) Are likes globally disabled (they can still be turned on per post)?', - 'disabled_reblogs' => '(bool) Are reblogs disabled on posts?', - 'jetpack_comment_likes_enabled' => '(bool) Are comment likes enabled for all comments?', - 'sharing_button_style' => '(string) Style to use for sharing buttons (icon-text, icon, text, or official)', - 'sharing_label' => '(string) Label to use for sharing buttons, e.g. "Share this:"', - 'sharing_show' => '(string|array:string) Post type or array of types where sharing buttons are to be displayed', - 'sharing_open_links' => '(string) Link target for sharing buttons (same or new)', - 'twitter_via' => '(string) Twitter username to include in tweets when people share using the Twitter button', - 'jetpack-twitter-cards-site-tag' => '(string) The Twitter username of the owner of the site\'s domain.', - 'eventbrite_api_token' => '(int) The Keyring token ID for an Eventbrite token to associate with the site', - 'timezone_string' => '(string) PHP-compatible timezone string like \'UTC-5\'', - 'gmt_offset' => '(int) Site offset from UTC in hours', - 'date_format' => '(string) PHP Date-compatible date format', - 'time_format' => '(string) PHP Date-compatible time format', - 'start_of_week' => '(int) Starting day of week (0 = Sunday, 6 = Saturday)', - 'jetpack_testimonial' => '(bool) Whether testimonial custom post type is enabled for the site', - 'jetpack_testimonial_posts_per_page' => '(int) Number of testimonials to show per page', - 'jetpack_portfolio' => '(bool) Whether portfolio custom post type is enabled for the site', - 'jetpack_portfolio_posts_per_page' => '(int) Number of portfolio projects to show per page', - Jetpack_SEO_Utils::FRONT_PAGE_META_OPTION => '(string) The seo meta description for the site.', - Jetpack_SEO_Titles::TITLE_FORMATS_OPTION => '(array) SEO meta title formats. Allowed keys: front_page, posts, pages, groups, archives', - 'verification_services_codes' => '(array) Website verification codes. Allowed keys: google, pinterest, bing, yandex', - 'markdown_supported' => '(bool) Whether markdown is supported for this site', - 'wpcom_publish_posts_with_markdown' => '(bool) Whether markdown is enabled for posts', - 'wpcom_publish_comments_with_markdown' => '(bool) Whether markdown is enabled for comments', - 'amp_is_enabled' => '(bool) Whether AMP is enabled for this site', - 'site_icon' => '(int) Media attachment ID to use as site icon. Set to zero or an otherwise empty value to clear', - 'api_cache' => '(bool) Turn on/off the Jetpack JSON API cache', - 'posts_per_page' => '(int) Number of posts to show on blog pages', - 'posts_per_rss' => '(int) Number of posts to show in the RSS feed', - 'rss_use_excerpt' => '(bool) Whether the RSS feed will use post excerpts', - ), - - 'response_format' => array( - 'updated' => '(array)' - ), - - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/en.blog.wordpress.com/settings', -) ); - +<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName +/** + * Manage settings via the WordPress.com REST API. + * + * @package automattic/jetpack + */ + +new WPCOM_JSON_API_Site_Settings_Endpoint( + array( + 'description' => 'Get detailed settings information about a site.', + 'group' => '__do_not_document', + 'stat' => 'sites:X', + 'max_version' => '1.1', + 'new_version' => '1.2', + 'method' => 'GET', + 'path' => '/sites/%s/settings', + 'path_labels' => array( + '$site' => '(int|string) Site ID or domain', + ), + + 'query_parameters' => array( + 'context' => false, + ), + + 'response_format' => WPCOM_JSON_API_Site_Settings_Endpoint::$site_format, + + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/en.blog.wordpress.com/settings', + ) +); + +new WPCOM_JSON_API_Site_Settings_Endpoint( + array( + 'description' => 'Update settings for a site.', + 'group' => '__do_not_document', + 'stat' => 'sites:X', + 'max_version' => '1.1', + 'new_version' => '1.2', + 'method' => 'POST', + 'path' => '/sites/%s/settings', + 'a_new_very_long_key' => 'blabla', + 'path_labels' => array( + '$site' => '(int|string) Site ID or domain', + ), + + 'request_format' => array( + 'blogname' => '(string) Blog name', + 'blogdescription' => '(string) Blog description', + 'default_pingback_flag' => '(bool) Notify blogs linked from article?', + 'default_ping_status' => '(bool) Allow link notifications from other blogs?', + 'default_comment_status' => '(bool) Allow comments on new articles?', + 'blog_public' => '(string) Site visibility; -1: private, 0: discourage search engines, 1: allow search engines', + 'jetpack_sync_non_public_post_stati' => '(bool) allow sync of post and pages with non-public posts stati', + 'jetpack_relatedposts_enabled' => '(bool) Enable related posts?', + 'jetpack_relatedposts_show_headline' => '(bool) Show headline in related posts?', + 'jetpack_relatedposts_show_thumbnails' => '(bool) Show thumbnails in related posts?', + 'jetpack_protect_whitelist' => '(array) List of IP addresses to whitelist', + 'instant_search_enabled' => '(bool) Enable the new Jetpack Instant Search interface', + 'jetpack_search_enabled' => '(bool) Enable Jetpack Search', + 'jetpack_search_supported' => '(bool) Jetpack Search is supported', + 'infinite_scroll' => '(bool) Support infinite scroll of posts?', + 'default_category' => '(int) Default post category', + 'default_post_format' => '(string) Default post format', + 'require_name_email' => '(bool) Require comment authors to fill out name and email?', + 'comment_registration' => '(bool) Require users to be registered and logged in to comment?', + 'close_comments_for_old_posts' => '(bool) Automatically close comments on old posts?', + 'close_comments_days_old' => '(int) Age at which to close comments', + 'thread_comments' => '(bool) Enable threaded comments?', + 'thread_comments_depth' => '(int) Depth to thread comments', + 'page_comments' => '(bool) Break comments into pages?', + 'comments_per_page' => '(int) Number of comments to display per page', + 'default_comments_page' => '(string) newest|oldest Which page of comments to display first', + 'comment_order' => '(string) asc|desc Order to display comments within page', + 'comments_notify' => '(bool) Email me when someone comments?', + 'moderation_notify' => '(bool) Email me when a comment is helf for moderation?', + 'social_notifications_like' => '(bool) Email me when someone likes my post?', + 'social_notifications_reblog' => '(bool) Email me when someone reblogs my post?', + 'social_notifications_subscribe' => '(bool) Email me when someone follows my blog?', + 'comment_moderation' => '(bool) Moderate comments for manual approval?', + 'comment_previously_approved' => '(bool) Moderate comments unless author has a previously-approved comment?', + 'comment_max_links' => '(int) Moderate comments that contain X or more links', + 'moderation_keys' => '(string) Words or phrases that trigger comment moderation, one per line', + 'disallowed_keys' => '(string) Words or phrases that mark comment spam, one per line', + 'lang_id' => '(int) ID for language blog is written in', + 'wga' => '(array) Google Analytics Settings', + 'disabled_likes' => '(bool) Are likes globally disabled (they can still be turned on per post)?', + 'disabled_reblogs' => '(bool) Are reblogs disabled on posts?', + 'jetpack_comment_likes_enabled' => '(bool) Are comment likes enabled for all comments?', + 'sharing_button_style' => '(string) Style to use for sharing buttons (icon-text, icon, text, or official)', + 'sharing_label' => '(string) Label to use for sharing buttons, e.g. "Share this:"', + 'sharing_show' => '(string|array:string) Post type or array of types where sharing buttons are to be displayed', + 'sharing_open_links' => '(string) Link target for sharing buttons (same or new)', + 'twitter_via' => '(string) Twitter username to include in tweets when people share using the Twitter button', + 'jetpack-twitter-cards-site-tag' => '(string) The Twitter username of the owner of the site\'s domain.', + 'eventbrite_api_token' => '(int) The Keyring token ID for an Eventbrite token to associate with the site', + 'timezone_string' => '(string) PHP-compatible timezone string like \'UTC-5\'', + 'gmt_offset' => '(int) Site offset from UTC in hours', + 'date_format' => '(string) PHP Date-compatible date format', + 'time_format' => '(string) PHP Date-compatible time format', + 'start_of_week' => '(int) Starting day of week (0 = Sunday, 6 = Saturday)', + 'jetpack_testimonial' => '(bool) Whether testimonial custom post type is enabled for the site', + 'jetpack_testimonial_posts_per_page' => '(int) Number of testimonials to show per page', + 'jetpack_portfolio' => '(bool) Whether portfolio custom post type is enabled for the site', + 'jetpack_portfolio_posts_per_page' => '(int) Number of portfolio projects to show per page', + Jetpack_SEO_Utils::FRONT_PAGE_META_OPTION => '(string) The seo meta description for the site.', + Jetpack_SEO_Titles::TITLE_FORMATS_OPTION => '(array) SEO meta title formats. Allowed keys: front_page, posts, pages, groups, archives', + 'verification_services_codes' => '(array) Website verification codes. Allowed keys: google, pinterest, bing, yandex, facebook', + 'markdown_supported' => '(bool) Whether markdown is supported for this site', + 'wpcom_publish_posts_with_markdown' => '(bool) Whether markdown is enabled for posts', + 'wpcom_publish_comments_with_markdown' => '(bool) Whether markdown is enabled for comments', + 'amp_is_enabled' => '(bool) Whether AMP is enabled for this site', + 'site_icon' => '(int) Media attachment ID to use as site icon. Set to zero or an otherwise empty value to clear', + 'api_cache' => '(bool) Turn on/off the Jetpack JSON API cache', + 'posts_per_page' => '(int) Number of posts to show on blog pages', + 'posts_per_rss' => '(int) Number of posts to show in the RSS feed', + 'rss_use_excerpt' => '(bool) Whether the RSS feed will use post excerpts', + ), + + 'response_format' => array( + 'updated' => '(array)', + ), + + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/en.blog.wordpress.com/settings', + ) +); + +/** + * Manage Site settings endpoint. + */ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { + /** + * Site format. + * + * @var array + */ public static $site_format = array( - 'ID' => '(int) Site ID', - 'name' => '(string) Title of site', - 'description' => '(string) Tagline or description of site', - 'URL' => '(string) Full URL to the site', - 'lang' => '(string) Primary language code of the site', - 'locale_variant' => '(string) Locale variant code for the site, if set', - 'settings' => '(array) An array of options/settings for the blog. Only viewable by users with post editing rights to the site.', + 'ID' => '(int) Site ID', + 'name' => '(string) Title of site', + 'description' => '(string) Tagline or description of site', + 'URL' => '(string) Full URL to the site', + 'lang' => '(string) Primary language code of the site', + 'locale_variant' => '(string) Locale variant code for the site, if set', + 'settings' => '(array) An array of options/settings for the blog. Only viewable by users with post editing rights to the site.', ); - // GET /sites/%s/settings - // POST /sites/%s/settings - function callback( $path = '', $blog_id = 0 ) { + /** + * Endpoint response + * + * GET /sites/%s/settings + * POST /sites/%s/settings + * + * @param string $path Path. + * @param int $blog_id Blog ID. + */ + public function callback( $path = '', $blog_id = 0 ) { $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) ); if ( is_wp_error( $blog_id ) ) { return $blog_id; } if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { - // Source & include the infinite scroll compatibility files prior to loading theme functions + // Source & include the infinite scroll compatibility files prior to loading theme functions. add_filter( 'restapi_theme_action_copy_dirs', array( 'WPCOM_JSON_API_Site_Settings_Endpoint', 'wpcom_restapi_copy_theme_plugin_actions' ) ); $this->load_theme_functions(); } if ( ! is_user_logged_in() ) { return new WP_Error( 'Unauthorized', 'You must be logged-in to manage settings.', 401 ); - } else if ( ! current_user_can( 'manage_options' ) ) { + } elseif ( ! current_user_can( 'manage_options' ) ) { return new WP_Error( 'Forbidden', 'You do not have the capability to manage settings for this site.', 403 ); } @@ -156,7 +182,7 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { */ do_action( 'wpcom_json_api_objects', 'sites' ); return $this->get_settings_response(); - } else if ( 'POST' === $this->api->method ) { + } elseif ( 'POST' === $this->api->method ) { return $this->update_settings(); } else { return new WP_Error( 'bad_request', 'An unsupported request method was used.' ); @@ -170,9 +196,11 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { * * @see WPCOM_JSON_API_Endpoint#load_theme_functions * @see the_neverending_home_page_theme_support + * + * @param array $copy_dirs Array of files to be included in theme context. */ - function wpcom_restapi_copy_theme_plugin_actions( $copy_dirs ) { - $theme_name = get_stylesheet(); + public function wpcom_restapi_copy_theme_plugin_actions( $copy_dirs ) { + $theme_name = get_stylesheet(); $default_file_name = WP_CONTENT_DIR . "/mu-plugins/infinity/themes/{$theme_name}.php"; /** @@ -207,18 +235,20 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { 'Opti', 'Currents', ); - return ( ! in_array( wp_get_theme()->get( 'Name' ), $wpcom_related_posts_theme_blacklist ) ); + return ( ! in_array( wp_get_theme()->get( 'Name' ), $wpcom_related_posts_theme_blacklist, true ) ); } /** * Returns category details * + * @param WP_Term $category Category object. + * * @return array */ public function get_category_details( $category ) { return array( 'value' => $category->term_id, - 'name' => $category->name + 'name' => $category->name, ); } @@ -226,9 +256,10 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { * Returns an option value as the result of the callable being applied to * it if a value is set, otherwise null. * - * @param string $option_name Option name - * @param callable $cast_callable Callable to invoke on option value - * @return int|null Numeric option value or null + * @param string $option_name Option name. + * @param callable $cast_callable Callable to invoke on option value. + * + * @return int|null Numeric option value or null. */ protected function get_cast_option_value_or_null( $option_name, $cast_callable ) { $option_value = get_option( $option_name, null ); @@ -245,8 +276,9 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { * @return array */ public function get_settings_response() { + $response = array(); - // Allow update in later versions + // Allow update in later versions. /** * Filter the structure of site settings to return. * @@ -264,200 +296,209 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { foreach ( array_keys( $response_format ) as $key ) { - // refactoring to change lang parameter to locale in 1.2 - if ( $lang_or_locale = $this->get_locale( $key ) ) { - $response[$key] = $lang_or_locale; + // refactoring to change lang parameter to locale in 1.2. + $lang_or_locale = $this->get_locale( $key ); + if ( $lang_or_locale ) { + $response[ $key ] = $lang_or_locale; continue; } switch ( $key ) { - case 'ID' : - $response[$key] = $blog_id; - break; - case 'name' : - $response[$key] = (string) htmlspecialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ); - break; - case 'description' : - $response[$key] = (string) htmlspecialchars_decode( get_bloginfo( 'description' ), ENT_QUOTES ); - break; - case 'URL' : - $response[$key] = (string) home_url(); - break; - case 'locale_variant': - if ( function_exists( 'wpcom_l10n_get_blog_locale_variant' ) ) { - $blog_locale_variant = wpcom_l10n_get_blog_locale_variant(); - if ( $blog_locale_variant ) { - $response[$key] = $blog_locale_variant; + case 'ID': + $response[ $key ] = $blog_id; + break; + case 'name': + $response[ $key ] = (string) htmlspecialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ); + break; + case 'description': + $response[ $key ] = (string) htmlspecialchars_decode( get_bloginfo( 'description' ), ENT_QUOTES ); + break; + case 'URL': + $response[ $key ] = (string) home_url(); + break; + case 'locale_variant': + if ( function_exists( 'wpcom_l10n_get_blog_locale_variant' ) ) { + $blog_locale_variant = wpcom_l10n_get_blog_locale_variant(); + if ( $blog_locale_variant ) { + $response[ $key ] = $blog_locale_variant; + } } - } - break; - case 'settings': - - $jetpack_relatedposts_options = Jetpack_Options::get_option( 'relatedposts', array() ); - // If the option's enabled key is NOT SET, it is considered enabled by the plugin - if ( ! isset( $jetpack_relatedposts_options['enabled'] ) ) { - $jetpack_relatedposts_options['enabled'] = true; - } - - if ( method_exists( 'Jetpack', 'is_module_active' ) ) { - $jetpack_relatedposts_options[ 'enabled' ] = Jetpack::is_module_active( 'related-posts' ); - } - - $jetpack_search_supported = false; - if ( function_exists( 'wpcom_is_jetpack_search_supported' ) ) { - $jetpack_search_supported = wpcom_is_jetpack_search_supported( $blog_id ); - } - - $jetpack_search_active = false; - if ( method_exists( 'Jetpack', 'is_module_active' ) ) { - $jetpack_search_active = Jetpack::is_module_active( 'search' ); - } - if ( function_exists( 'is_jetpack_module_active' ) ) { - $jetpack_search_active = is_jetpack_module_active( 'search', $blog_id ); - } - - // array_values() is necessary to ensure the array starts at index 0. - $post_categories = array_values( - array_map( - array( $this, 'get_category_details' ), - get_categories( array( 'hide_empty' => false ) ) - ) - ); - - $api_cache = $is_jetpack ? (bool) get_option( 'jetpack_api_cache_enabled' ) : true; - - $response[ $key ] = array( - - // also exists as "options" - 'admin_url' => get_admin_url(), - 'default_ping_status' => (bool) ( 'closed' != get_option( 'default_ping_status' ) ), - 'default_comment_status' => (bool) ( 'closed' != get_option( 'default_comment_status' ) ), - - // new stuff starts here - 'blog_public' => (int) get_option( 'blog_public' ), - 'jetpack_sync_non_public_post_stati' => (bool) Jetpack_Options::get_option( 'sync_non_public_post_stati' ), - 'jetpack_relatedposts_allowed' => (bool) $this->jetpack_relatedposts_supported(), - 'jetpack_relatedposts_enabled' => (bool) $jetpack_relatedposts_options[ 'enabled' ], - 'jetpack_relatedposts_show_headline' => (bool) isset( $jetpack_relatedposts_options[ 'show_headline' ] ) ? $jetpack_relatedposts_options[ 'show_headline' ] : false, - 'jetpack_relatedposts_show_thumbnails' => (bool) isset( $jetpack_relatedposts_options[ 'show_thumbnails' ] ) ? $jetpack_relatedposts_options[ 'show_thumbnails' ] : false, - 'jetpack_search_enabled' => (bool) $jetpack_search_active, - 'jetpack_search_supported'=> (bool) $jetpack_search_supported, - 'default_category' => (int) get_option('default_category'), - 'post_categories' => (array) $post_categories, - 'default_post_format' => get_option( 'default_post_format' ), - 'default_pingback_flag' => (bool) get_option( 'default_pingback_flag' ), - 'require_name_email' => (bool) get_option( 'require_name_email' ), - 'comment_registration' => (bool) get_option( 'comment_registration' ), - 'close_comments_for_old_posts' => (bool) get_option( 'close_comments_for_old_posts' ), - 'close_comments_days_old' => (int) get_option( 'close_comments_days_old' ), - 'thread_comments' => (bool) get_option( 'thread_comments' ), - 'thread_comments_depth' => (int) get_option( 'thread_comments_depth' ), - 'page_comments' => (bool) get_option( 'page_comments' ), - 'comments_per_page' => (int) get_option( 'comments_per_page' ), - 'default_comments_page' => get_option( 'default_comments_page' ), - 'comment_order' => get_option( 'comment_order' ), - 'comments_notify' => (bool) get_option( 'comments_notify' ), - 'moderation_notify' => (bool) get_option( 'moderation_notify' ), - 'social_notifications_like' => ( "on" == get_option( 'social_notifications_like' ) ), - 'social_notifications_reblog' => ( "on" == get_option( 'social_notifications_reblog' ) ), - 'social_notifications_subscribe' => ( "on" == get_option( 'social_notifications_subscribe' ) ), - 'comment_moderation' => (bool) get_option( 'comment_moderation' ), - 'comment_whitelist' => (bool) get_option( 'comment_whitelist' ), - 'comment_max_links' => (int) get_option( 'comment_max_links' ), - 'moderation_keys' => get_option( 'moderation_keys' ), - 'blacklist_keys' => get_option( 'blacklist_keys' ), - 'lang_id' => defined( 'IS_WPCOM' ) && IS_WPCOM + break; + case 'settings': + $jetpack_relatedposts_options = Jetpack_Options::get_option( 'relatedposts', array() ); + // If the option's enabled key is NOT SET, it is considered enabled by the plugin. + if ( ! isset( $jetpack_relatedposts_options['enabled'] ) ) { + $jetpack_relatedposts_options['enabled'] = true; + } + + if ( method_exists( 'Jetpack', 'is_module_active' ) ) { + $jetpack_relatedposts_options['enabled'] = Jetpack::is_module_active( 'related-posts' ); + } + + $jetpack_search_supported = false; + if ( function_exists( 'wpcom_is_jetpack_search_supported' ) ) { + $jetpack_search_supported = wpcom_is_jetpack_search_supported( $blog_id ); + } + + $jetpack_search_active = false; + if ( method_exists( 'Jetpack', 'is_module_active' ) ) { + $jetpack_search_active = Jetpack::is_module_active( 'search' ); + } + if ( function_exists( 'is_jetpack_module_active' ) ) { + $jetpack_search_active = is_jetpack_module_active( 'search', $blog_id ); + } + + // array_values() is necessary to ensure the array starts at index 0. + $post_categories = array_values( + array_map( + array( $this, 'get_category_details' ), + get_categories( array( 'hide_empty' => false ) ) + ) + ); + + $api_cache = $is_jetpack ? (bool) get_option( 'jetpack_api_cache_enabled' ) : true; + + $response[ $key ] = array( + // also exists as "options". + 'admin_url' => get_admin_url(), + 'default_ping_status' => (bool) ( 'closed' !== get_option( 'default_ping_status' ) ), + 'default_comment_status' => (bool) ( 'closed' !== get_option( 'default_comment_status' ) ), + + // new stuff starts here. + 'instant_search_enabled' => (bool) get_option( 'instant_search_enabled' ), + 'blog_public' => (int) get_option( 'blog_public' ), + 'jetpack_sync_non_public_post_stati' => (bool) Jetpack_Options::get_option( 'sync_non_public_post_stati' ), + 'jetpack_relatedposts_allowed' => (bool) $this->jetpack_relatedposts_supported(), + 'jetpack_relatedposts_enabled' => (bool) $jetpack_relatedposts_options['enabled'], + 'jetpack_relatedposts_show_headline' => (bool) isset( $jetpack_relatedposts_options['show_headline'] ) ? $jetpack_relatedposts_options['show_headline'] : false, + 'jetpack_relatedposts_show_thumbnails' => (bool) isset( $jetpack_relatedposts_options['show_thumbnails'] ) ? $jetpack_relatedposts_options['show_thumbnails'] : false, + 'jetpack_search_enabled' => (bool) $jetpack_search_active, + 'jetpack_search_supported' => (bool) $jetpack_search_supported, + 'default_category' => (int) get_option( 'default_category' ), + 'post_categories' => (array) $post_categories, + 'default_post_format' => get_option( 'default_post_format' ), + 'default_pingback_flag' => (bool) get_option( 'default_pingback_flag' ), + 'require_name_email' => (bool) get_option( 'require_name_email' ), + 'comment_registration' => (bool) get_option( 'comment_registration' ), + 'close_comments_for_old_posts' => (bool) get_option( 'close_comments_for_old_posts' ), + 'close_comments_days_old' => (int) get_option( 'close_comments_days_old' ), + 'thread_comments' => (bool) get_option( 'thread_comments' ), + 'thread_comments_depth' => (int) get_option( 'thread_comments_depth' ), + 'page_comments' => (bool) get_option( 'page_comments' ), + 'comments_per_page' => (int) get_option( 'comments_per_page' ), + 'default_comments_page' => get_option( 'default_comments_page' ), + 'comment_order' => get_option( 'comment_order' ), + 'comments_notify' => (bool) get_option( 'comments_notify' ), + 'moderation_notify' => (bool) get_option( 'moderation_notify' ), + 'social_notifications_like' => ( 'on' === get_option( 'social_notifications_like' ) ), + 'social_notifications_reblog' => ( 'on' === get_option( 'social_notifications_reblog' ) ), + 'social_notifications_subscribe' => ( 'on' === get_option( 'social_notifications_subscribe' ) ), + 'comment_moderation' => (bool) get_option( 'comment_moderation' ), + 'comment_whitelist' => (bool) get_option( 'comment_previously_approved' ), + 'comment_previously_approved' => (bool) get_option( 'comment_previously_approved' ), + 'comment_max_links' => (int) get_option( 'comment_max_links' ), + 'moderation_keys' => get_option( 'moderation_keys' ), + 'blacklist_keys' => get_option( 'disallowed_keys' ), + 'disallowed_keys' => get_option( 'disallowed_keys' ), + 'lang_id' => defined( 'IS_WPCOM' ) && IS_WPCOM ? get_lang_id_by_code( wpcom_l10n_get_blog_locale_variant( $blog_id, true ) ) : get_option( 'lang_id' ), - 'wga' => $this->get_google_analytics(), - 'disabled_likes' => (bool) get_option( 'disabled_likes' ), - 'disabled_reblogs' => (bool) get_option( 'disabled_reblogs' ), - 'jetpack_comment_likes_enabled' => (bool) get_option( 'jetpack_comment_likes_enabled', false ), - 'twitter_via' => (string) get_option( 'twitter_via' ), - 'jetpack-twitter-cards-site-tag' => (string) get_option( 'jetpack-twitter-cards-site-tag' ), - 'eventbrite_api_token' => $this->get_cast_option_value_or_null( 'eventbrite_api_token', 'intval' ), - 'gmt_offset' => get_option( 'gmt_offset' ), - 'timezone_string' => get_option( 'timezone_string' ), - 'date_format' => get_option( 'date_format' ), - 'time_format' => get_option( 'time_format' ), - 'start_of_week' => get_option( 'start_of_week' ), - 'jetpack_testimonial' => (bool) get_option( 'jetpack_testimonial', '0' ), - 'jetpack_testimonial_posts_per_page' => (int) get_option( 'jetpack_testimonial_posts_per_page', '10' ), - 'jetpack_portfolio' => (bool) get_option( 'jetpack_portfolio', '0' ), - 'jetpack_portfolio_posts_per_page' => (int) get_option( 'jetpack_portfolio_posts_per_page', '10' ), - 'markdown_supported' => true, - 'site_icon' => $this->get_cast_option_value_or_null( 'site_icon', 'intval' ), - Jetpack_SEO_Utils::FRONT_PAGE_META_OPTION => get_option( Jetpack_SEO_Utils::FRONT_PAGE_META_OPTION, '' ), - Jetpack_SEO_Titles::TITLE_FORMATS_OPTION => get_option( Jetpack_SEO_Titles::TITLE_FORMATS_OPTION, array() ), - 'amp_is_supported' => (bool) function_exists( 'wpcom_is_amp_supported' ) && wpcom_is_amp_supported( $blog_id ), - 'amp_is_enabled' => (bool) function_exists( 'wpcom_is_amp_enabled' ) && wpcom_is_amp_enabled( $blog_id ), - 'api_cache' => $api_cache, - 'posts_per_page' => (int) get_option( 'posts_per_page' ), - 'posts_per_rss' => (int) get_option( 'posts_per_rss' ), - 'rss_use_excerpt' => (bool) get_option( 'rss_use_excerpt' ), - ); - - if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { - $response[ $key ]['wpcom_publish_posts_with_markdown'] = (bool) WPCom_Markdown::is_posting_enabled(); - $response[ $key ]['wpcom_publish_comments_with_markdown'] = (bool) WPCom_Markdown::is_commenting_enabled(); - - // WPCOM-specific Infinite Scroll Settings - if ( is_callable( array( 'The_Neverending_Home_Page', 'get_settings' ) ) ) { - /** - * Clear the cached copy of widget info so it's pulled fresh from blog options. - * It was primed during the initial load under the __REST API site__'s context. - * @see wp_get_sidebars_widgets https://core.trac.wordpress.org/browser/trunk/src/wp-includes/widgets.php?rev=42374#L931 - */ - $GLOBALS['_wp_sidebars_widgets'] = array(); + 'wga' => $this->get_google_analytics(), + 'jetpack_cloudflare_analytics' => get_option( 'jetpack_cloudflare_analytics' ), + 'disabled_likes' => (bool) get_option( 'disabled_likes' ), + 'disabled_reblogs' => (bool) get_option( 'disabled_reblogs' ), + 'jetpack_comment_likes_enabled' => (bool) get_option( 'jetpack_comment_likes_enabled', false ), + 'twitter_via' => (string) get_option( 'twitter_via' ), + 'jetpack-twitter-cards-site-tag' => (string) get_option( 'jetpack-twitter-cards-site-tag' ), + 'eventbrite_api_token' => $this->get_cast_option_value_or_null( 'eventbrite_api_token', 'intval' ), + 'gmt_offset' => get_option( 'gmt_offset' ), + 'timezone_string' => get_option( 'timezone_string' ), + 'date_format' => get_option( 'date_format' ), + 'time_format' => get_option( 'time_format' ), + 'start_of_week' => get_option( 'start_of_week' ), + 'jetpack_testimonial' => (bool) get_option( 'jetpack_testimonial', '0' ), + 'jetpack_testimonial_posts_per_page' => (int) get_option( 'jetpack_testimonial_posts_per_page', '10' ), + 'jetpack_portfolio' => (bool) get_option( 'jetpack_portfolio', '0' ), + 'jetpack_portfolio_posts_per_page' => (int) get_option( 'jetpack_portfolio_posts_per_page', '10' ), + 'markdown_supported' => true, + 'site_icon' => $this->get_cast_option_value_or_null( 'site_icon', 'intval' ), + Jetpack_SEO_Utils::FRONT_PAGE_META_OPTION => get_option( Jetpack_SEO_Utils::FRONT_PAGE_META_OPTION, '' ), + Jetpack_SEO_Titles::TITLE_FORMATS_OPTION => get_option( Jetpack_SEO_Titles::TITLE_FORMATS_OPTION, array() ), + 'amp_is_supported' => (bool) function_exists( 'wpcom_is_amp_supported' ) && wpcom_is_amp_supported( $blog_id ), + 'amp_is_enabled' => (bool) function_exists( 'wpcom_is_amp_enabled' ) && wpcom_is_amp_enabled( $blog_id ), + 'api_cache' => $api_cache, + 'posts_per_page' => (int) get_option( 'posts_per_page' ), + 'posts_per_rss' => (int) get_option( 'posts_per_rss' ), + 'rss_use_excerpt' => (bool) get_option( 'rss_use_excerpt' ), + ); - $infinite_scroll_settings = The_Neverending_Home_Page::get_settings(); - $response[ $key ]['infinite_scroll'] = get_option( 'infinite_scroll', true ) && $infinite_scroll_settings->type === 'scroll'; - if ( $infinite_scroll_settings->footer_widgets || 'click' == $infinite_scroll_settings->requested_type ) { - // The blog has footer widgets -- infinite scroll is blocked - $response[ $key ]['infinite_scroll_blocked'] = 'footer'; - } else { - $response[ $key ]['infinite_scroll_blocked'] = false; + if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { + $response[ $key ]['wpcom_publish_posts_with_markdown'] = (bool) WPCom_Markdown::is_posting_enabled(); + $response[ $key ]['wpcom_publish_comments_with_markdown'] = (bool) WPCom_Markdown::is_commenting_enabled(); + + // WPCOM-specific Infinite Scroll Settings. + if ( is_callable( array( 'The_Neverending_Home_Page', 'get_settings' ) ) ) { + /** + * Clear the cached copy of widget info so it's pulled fresh from blog options. + * It was primed during the initial load under the __REST API site__'s context. + * + * @see wp_get_sidebars_widgets https://core.trac.wordpress.org/browser/trunk/src/wp-includes/widgets.php?rev=42374#L931 + */ + $GLOBALS['_wp_sidebars_widgets'] = array(); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited + + $infinite_scroll_settings = The_Neverending_Home_Page::get_settings(); + $response[ $key ]['infinite_scroll'] = get_option( 'infinite_scroll', true ) && 'scroll' === $infinite_scroll_settings->type; + if ( $infinite_scroll_settings->footer_widgets || 'click' === $infinite_scroll_settings->requested_type ) { + // The blog has footer widgets -- infinite scroll is blocked. + $response[ $key ]['infinite_scroll_blocked'] = 'footer'; + } else { + $response[ $key ]['infinite_scroll_blocked'] = false; + } } } - } - //allow future versions of this endpoint to support additional settings keys - /** - * Filter the current site setting in the returned response. - * - * @module json-api - * - * @since 3.9.3 - * - * @param mixed $response_item A single site setting. - */ - $response[ $key ] = apply_filters( 'site_settings_endpoint_get', $response[ $key ] ); - - if ( class_exists( 'Sharing_Service' ) ) { - $ss = new Sharing_Service(); - $sharing = $ss->get_global_options(); - $response[ $key ]['sharing_button_style'] = (string) $sharing['button_style']; - $response[ $key ]['sharing_label'] = (string) $sharing['sharing_label']; - $response[ $key ]['sharing_show'] = (array) $sharing['show']; - $response[ $key ]['sharing_open_links'] = (string) $sharing['open_links']; - } + // allow future versions of this endpoint to support additional settings keys. + /** + * Filter the current site setting in the returned response. + * + * @module json-api + * + * @since 3.9.3 + * + * @param mixed $response_item A single site setting. + */ + $response[ $key ] = apply_filters( 'site_settings_endpoint_get', $response[ $key ] ); - if ( function_exists( 'jetpack_protect_format_whitelist' ) ) { - $response[ $key ]['jetpack_protect_whitelist'] = jetpack_protect_format_whitelist(); - } + if ( class_exists( 'Sharing_Service' ) ) { + $ss = new Sharing_Service(); + $sharing = $ss->get_global_options(); + $response[ $key ]['sharing_button_style'] = (string) $sharing['button_style']; + $response[ $key ]['sharing_label'] = (string) $sharing['sharing_label']; + $response[ $key ]['sharing_show'] = (array) $sharing['show']; + $response[ $key ]['sharing_open_links'] = (string) $sharing['open_links']; + } + + if ( function_exists( 'jetpack_protect_format_whitelist' ) ) { + $response[ $key ]['jetpack_protect_whitelist'] = jetpack_protect_format_whitelist(); + } - if ( ! current_user_can( 'edit_posts' ) ) - unset( $response[$key] ); - break; + if ( ! current_user_can( 'edit_posts' ) ) { + unset( $response[ $key ] ); + } + break; } } - return $response; } + /** + * Get locale. + * + * @param string $key Language. + */ protected function get_locale( $key ) { - if ( 'lang' == $key ) { + if ( 'lang' === $key ) { if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { return (string) get_blog_lang_code(); } else { @@ -468,7 +509,10 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { return false; } - protected function get_google_analytics () { + /** + * Get GA tracking code. + */ + protected function get_google_analytics() { $option_name = defined( 'IS_WPCOM' ) && IS_WPCOM ? 'wga' : 'jetpack_wga'; return get_option( $option_name ); } @@ -479,9 +523,11 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { * @return array */ public function update_settings() { - // $this->input() retrieves posted arguments whitelisted and casted to the $request_format - // specs that get passed in when this class is instantiated - $input = $this->input(); + /* + * $this->input() retrieves posted arguments whitelisted and casted to the $request_format + * specs that get passed in when this class is instantiated + */ + $input = $this->input(); $unfiltered_input = $this->input( false, false ); /** * Filters the settings to be updated on the site. @@ -501,21 +547,23 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { $blog_id = get_current_blog_id(); $jetpack_relatedposts_options = array(); - $sharing_options = array(); - $updated = array(); + $sharing_options = array(); + $updated = array(); foreach ( $input as $key => $value ) { if ( ! is_array( $value ) ) { $value = trim( $value ); } - $value = wp_unslash( $value ); + // preserve the raw value before unslashing the value. The slashes need to be preserved for date and time formats. + $raw_value = $value; + $value = wp_unslash( $value ); switch ( $key ) { case 'default_ping_status': case 'default_comment_status': - // settings are stored as closed|open + // settings are stored as closed|open. $coerce_value = ( $value ) ? 'open' : 'closed'; if ( update_option( $key, $coerce_value ) ) { $updated[ $key ] = $value; @@ -539,11 +587,11 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { } $is_wpcom = defined( 'IS_WPCOM' ) && IS_WPCOM; if ( $value ) { - $jetpack_search_update_success = $is_wpcom + $is_wpcom ? Jetpack::activate_module( $blog_id, 'search' ) : Jetpack::activate_module( 'search', false, false ); } else { - $jetpack_search_update_success = $is_wpcom + $is_wpcom ? Jetpack::deactivate_module( $blog_id, 'search' ) : Jetpack::deactivate_module( 'search' ); } @@ -556,25 +604,25 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { break; } if ( 'jetpack_relatedposts_enabled' === $key && method_exists( 'Jetpack', 'is_module_active' ) && $this->jetpack_relatedposts_supported() ) { - $before_action = Jetpack::is_module_active('related-posts'); + $before_action = Jetpack::is_module_active( 'related-posts' ); if ( $value ) { Jetpack::activate_module( 'related-posts', false, false ); } else { Jetpack::deactivate_module( 'related-posts' ); } - $after_action = Jetpack::is_module_active('related-posts'); - if ( $after_action == $before_action ) { + $after_action = Jetpack::is_module_active( 'related-posts' ); + if ( $after_action === $before_action ) { break; } } - $just_the_key = substr( $key, 21 ); + $just_the_key = substr( $key, 21 ); $jetpack_relatedposts_options[ $just_the_key ] = $value; - break; + break; case 'social_notifications_like': case 'social_notifications_reblog': case 'social_notifications_subscribe': - // settings are stored as on|off + // settings are stored as on|off. $coerce_value = ( $value ) ? 'on' : 'off'; if ( update_option( $key, $coerce_value ) ) { $updated[ $key ] = $value; @@ -582,15 +630,15 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { break; case 'wga': case 'jetpack_wga': - if ( ! isset( $value['code'] ) || ! preg_match( '/^$|^UA-[\d-]+$/i', $value['code'] ) ) { + if ( ! isset( $value['code'] ) || ! preg_match( '/^$|^(UA-\d+-\d+)|(G-[A-Z0-9]+)$/i', $value['code'] ) ) { return new WP_Error( 'invalid_code', 'Invalid UA ID' ); } - $is_wpcom = defined( 'IS_WPCOM' ) && IS_WPCOM; + $is_wpcom = defined( 'IS_WPCOM' ) && IS_WPCOM; $option_name = $is_wpcom ? 'wga' : 'jetpack_wga'; - $wga = get_option( $option_name, array() ); - $wga['code'] = $value['code']; // maintain compatibility with wp-google-analytics + $wga = get_option( $option_name, array() ); + $wga['code'] = $value['code']; // maintain compatibility with wp-google-analytics. /** * Allow newer versions of this endpoint to filter in additional fields for Google Analytics @@ -617,10 +665,20 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { } break; + case 'jetpack_cloudflare_analytics': + if ( ! isset( $value['code'] ) || ! preg_match( '/^$|^[a-fA-F0-9]+$/i', $value['code'] ) ) { + return new WP_Error( 'invalid_code', __( 'Invalid Cloudflare Analytics ID', 'jetpack' ) ); + } + + if ( update_option( $key, $value ) ) { + $updated[ $key ] = $value; + } + break; + case 'jetpack_testimonial': case 'jetpack_portfolio': case 'jetpack_comment_likes_enabled': - // settings are stored as 1|0 + // settings are stored as 1|0. $coerce_value = (int) $value; if ( update_option( $key, $coerce_value ) ) { $updated[ $key ] = (bool) $value; @@ -629,14 +687,14 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { case 'jetpack_testimonial_posts_per_page': case 'jetpack_portfolio_posts_per_page': - // settings are stored as numeric + // settings are stored as numeric. $coerce_value = (int) $value; if ( update_option( $key, $coerce_value ) ) { $updated[ $key ] = $coerce_value; } break; - // Sharing options + // Sharing options. case 'sharing_button_style': case 'sharing_show': case 'sharing_open_links': @@ -646,15 +704,15 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { $sharing_options[ $key ] = $value; break; - // Keyring token option + // Keyring token option. case 'eventbrite_api_token': - // These options can only be updated for sites hosted on WordPress.com + // These options can only be updated for sites hosted on WordPress.com. if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { if ( empty( $value ) || WPCOM_JSON_API::is_falsy( $value ) ) { if ( delete_option( $key ) ) { $updated[ $key ] = null; } - } else if ( update_option( $key, $value ) ) { + } elseif ( update_option( $key, $value ) ) { $updated[ $key ] = (int) $value; } } @@ -665,25 +723,29 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { if ( delete_option( 'jetpack_api_cache_enabled' ) ) { $updated[ $key ] = false; } - } else if ( update_option( 'jetpack_api_cache_enabled', true ) ) { + } elseif ( update_option( 'jetpack_api_cache_enabled', true ) ) { $updated[ $key ] = true; } break; case 'timezone_string': - // Map UTC+- timezones to gmt_offsets and set timezone_string to empty - // https://github.com/WordPress/WordPress/blob/4.4.2/wp-admin/options.php#L175 + /* + * Map UTC+- timezones to gmt_offsets and set timezone_string to empty + * https://github.com/WordPress/WordPress/blob/4.4.2/wp-admin/options.php#L175 + */ if ( ! empty( $value ) && preg_match( '/^UTC[+-]/', $value ) ) { $gmt_offset = preg_replace( '/UTC\+?/', '', $value ); if ( update_option( 'gmt_offset', $gmt_offset ) ) { - $updated[ 'gmt_offset' ] = $gmt_offset; + $updated['gmt_offset'] = $gmt_offset; } $value = ''; } - // Always set timezone_string either with the given value or with an - // empty string + /* + * Always set timezone_string either with the given value or with an + * empty string + */ if ( update_option( $key, $value ) ) { $updated[ $key ] = $value; } @@ -691,14 +753,16 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { case 'date_format': case 'time_format': - // settings are stored as strings - if ( update_option( $key, sanitize_text_field( $value ) ) ) { - $updated[ $key ] = $value; + // settings are stored as strings. + // raw_value is used to help preserve any escaped characters that might exist in the formatted string. + $sanitized_value = sanitize_text_field( $raw_value ); + if ( update_option( $key, $sanitized_value ) ) { + $updated[ $key ] = $sanitized_value; } break; case 'start_of_week': - // setting is stored as int in 0-6 range (days of week) + // setting is stored as int in 0-6 range (days of week). $coerce_value = (int) $value; $limit_value = ( $coerce_value >= 0 && $coerce_value <= 6 ) ? $coerce_value : 0; if ( update_option( $key, $limit_value ) ) { @@ -707,8 +771,10 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { break; case 'site_icon': - // settings are stored as deletable numeric (all empty - // values as delete intent), validated as media image + /* + * settings are stored as deletable numeric (all empty + * values as delete intent), validated as media image + */ if ( empty( $value ) || WPCOM_JSON_API::is_falsy( $value ) ) { /** * Fallback mechanism to clear a third party site icon setting. Can be used @@ -718,10 +784,10 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { * * @since 4.10 */ - if ( delete_option( $key ) || apply_filters( 'rest_api_site_icon_cleared', false ) ) { + if ( delete_option( $key ) || apply_filters( 'rest_api_site_icon_cleared', false ) ) { $updated[ $key ] = null; } - } else if ( is_numeric( $value ) ) { + } elseif ( is_numeric( $value ) ) { $coerce_value = (int) $value; if ( wp_attachment_is_image( $coerce_value ) && update_option( $key, $coerce_value ) ) { $updated[ $key ] = $coerce_value; @@ -730,7 +796,7 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { break; case Jetpack_SEO_Utils::FRONT_PAGE_META_OPTION: - if ( ! Jetpack_SEO_Utils::is_enabled_jetpack_seo() && ! Jetpack_SEO_Utils::has_grandfathered_front_page_meta() ) { + if ( ! Jetpack_SEO_Utils::is_enabled_jetpack_seo() && ! Jetpack_SEO_Utils::has_legacy_front_page_meta() ) { return new WP_Error( 'unauthorized', __( 'SEO tools are not enabled for this site.', 'jetpack' ), 403 ); } @@ -747,6 +813,9 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { case Jetpack_SEO_Titles::TITLE_FORMATS_OPTION: if ( ! Jetpack_SEO_Utils::is_enabled_jetpack_seo() ) { + if ( Jetpack_SEO_Utils::has_legacy_front_page_meta() ) { + break; + } return new WP_Error( 'unauthorized', __( 'SEO tools are not enabled for this site.', 'jetpack' ), 403 ); } @@ -787,11 +856,28 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { break; case 'rss_use_excerpt': - update_option( 'rss_use_excerpt', (int)(bool) $value ); + update_option( 'rss_use_excerpt', (int) (bool) $value ); + break; + + case 'instant_search_enabled': + update_option( 'instant_search_enabled', (bool) $value ); + $updated[ $key ] = (bool) $value; + break; + + case 'lang_id': + /* + * Due to the fact that locale variants are set in a locale_variant option, + * changing locale from variant to primary + * would look like the same lang_id is being saved and update_option would return false, + * even though the correct options would be set by pre_update_option_lang_id, + * so we should always return lang_id as updated. + */ + update_option( 'lang_id', (int) $value ); + $updated[ $key ] = (int) $value; break; default: - //allow future versions of this endpoint to support additional settings keys + // allow future versions of this endpoint to support additional settings keys. if ( has_filter( 'site_settings_endpoint_update_' . $key ) ) { /** * Filter current site setting value to be updated. @@ -802,12 +888,12 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { * * @param mixed $response_item A single site setting value. */ - $value = apply_filters( 'site_settings_endpoint_update_' . $key, $value ); + $value = apply_filters( 'site_settings_endpoint_update_' . $key, $value ); $updated[ $key ] = $value; break; } - // no worries, we've already whitelisted and casted arguments above + // no worries, we've already whitelisted and casted arguments above. if ( update_option( $key, $value ) ) { $updated[ $key ] = $value; } @@ -815,7 +901,7 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { } if ( count( $jetpack_relatedposts_options ) ) { - // track new jetpack_relatedposts options against old + // track new jetpack_relatedposts options against old. $old_relatedposts_options = Jetpack_Options::get_option( 'relatedposts' ); if ( Jetpack_Options::update_option( 'relatedposts', $jetpack_relatedposts_options ) ) { foreach ( $jetpack_relatedposts_options as $key => $value ) { @@ -829,8 +915,10 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { if ( ! empty( $sharing_options ) && class_exists( 'Sharing_Service' ) ) { $ss = new Sharing_Service(); - // Merge current values with updated, since Sharing_Service expects - // all values to be included when updating + /* + * Merge current values with updated, since Sharing_Service expects + * all values to be included when updating + */ $current_sharing_options = $ss->get_global_options(); foreach ( $current_sharing_options as $key => $val ) { if ( ! isset( $sharing_options[ $key ] ) ) { @@ -844,7 +932,7 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { $updated['sharing_button_style'] = (string) $updated_social_options['button_style']; } if ( isset( $input['sharing_label'] ) ) { - // Sharing_Service won't report label as updated if set to default + // Sharing_Service won't report label as updated if set to default. $updated['sharing_label'] = (string) $sharing_options['sharing_label']; } if ( isset( $input['sharing_show'] ) ) { @@ -856,7 +944,7 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { } return array( - 'updated' => $updated + 'updated' => $updated, ); } diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-settings-v1-2-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-settings-v1-2-endpoint.php index 989bba2e..41889ba3 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-settings-v1-2-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-settings-v1-2-endpoint.php @@ -32,74 +32,75 @@ new WPCOM_JSON_API_Site_Settings_V1_2_Endpoint( array( ), 'request_format' => array( - 'blogname' => '(string) Blog name', - 'blogdescription' => '(string) Blog description', - 'default_pingback_flag' => '(bool) Notify blogs linked from article?', - 'default_ping_status' => '(bool) Allow link notifications from other blogs?', - 'default_comment_status' => '(bool) Allow comments on new articles?', - 'blog_public' => '(string) Site visibility; -1: private, 0: discourage search engines, 1: allow search engines', - 'jetpack_sync_non_public_post_stati' => '(bool) allow sync of post and pages with non-public posts stati', - 'jetpack_relatedposts_enabled' => '(bool) Enable related posts?', - 'jetpack_relatedposts_show_headline' => '(bool) Show headline in related posts?', - 'jetpack_relatedposts_show_thumbnails' => '(bool) Show thumbnails in related posts?', - 'jetpack_search_enabled' => '(bool) Enable Jetpack Search', - 'jetpack_search_supported' => '(bool) Jetpack Search supported', - 'jetpack_protect_whitelist' => '(array) List of IP addresses to whitelist', - 'infinite_scroll' => '(bool) Support infinite scroll of posts?', - 'default_category' => '(int) Default post category', - 'default_post_format' => '(string) Default post format', - 'require_name_email' => '(bool) Require comment authors to fill out name and email?', - 'comment_registration' => '(bool) Require users to be registered and logged in to comment?', - 'close_comments_for_old_posts' => '(bool) Automatically close comments on old posts?', - 'close_comments_days_old' => '(int) Age at which to close comments', - 'thread_comments' => '(bool) Enable threaded comments?', - 'thread_comments_depth' => '(int) Depth to thread comments', - 'page_comments' => '(bool) Break comments into pages?', - 'comments_per_page' => '(int) Number of comments to display per page', - 'default_comments_page' => '(string) newest|oldest Which page of comments to display first', - 'comment_order' => '(string) asc|desc Order to display comments within page', - 'comments_notify' => '(bool) Email me when someone comments?', - 'moderation_notify' => '(bool) Email me when a comment is helf for moderation?', - 'social_notifications_like' => '(bool) Email me when someone likes my post?', - 'social_notifications_reblog' => '(bool) Email me when someone reblogs my post?', - 'social_notifications_subscribe' => '(bool) Email me when someone follows my blog?', - 'comment_moderation' => '(bool) Moderate comments for manual approval?', - 'comment_whitelist' => '(bool) Moderate comments unless author has a previously-approved comment?', - 'comment_max_links' => '(int) Moderate comments that contain X or more links', - 'moderation_keys' => '(string) Words or phrases that trigger comment moderation, one per line', - 'blacklist_keys' => '(string) Words or phrases that mark comment spam, one per line', - 'lang_id' => '(int) ID for language blog is written in', - 'locale' => '(string) locale code for language blog is written in', - 'wga' => '(array) Google Analytics Settings', - 'disabled_likes' => '(bool) Are likes globally disabled (they can still be turned on per post)?', - 'disabled_reblogs' => '(bool) Are reblogs disabled on posts?', - 'jetpack_comment_likes_enabled' => '(bool) Are comment likes enabled for all comments?', - 'sharing_button_style' => '(string) Style to use for sharing buttons (icon-text, icon, text, or official)', - 'sharing_label' => '(string) Label to use for sharing buttons, e.g. "Share this:"', - 'sharing_show' => '(string|array:string) Post type or array of types where sharing buttons are to be displayed', - 'sharing_open_links' => '(string) Link target for sharing buttons (same or new)', - 'twitter_via' => '(string) Twitter username to include in tweets when people share using the Twitter button', - 'jetpack-twitter-cards-site-tag' => '(string) The Twitter username of the owner of the site\'s domain.', - 'eventbrite_api_token' => '(int) The Keyring token ID for an Eventbrite token to associate with the site', - 'timezone_string' => '(string) PHP-compatible timezone string like \'UTC-5\'', - 'gmt_offset' => '(int) Site offset from UTC in hours', - 'date_format' => '(string) PHP Date-compatible date format', - 'time_format' => '(string) PHP Date-compatible time format', - 'start_of_week' => '(int) Starting day of week (0 = Sunday, 6 = Saturday)', - 'jetpack_testimonial' => '(bool) Whether testimonial custom post type is enabled for the site', - 'jetpack_testimonial_posts_per_page' => '(int) Number of testimonials to show per page', - 'jetpack_portfolio' => '(bool) Whether portfolio custom post type is enabled for the site', - 'jetpack_portfolio_posts_per_page' => '(int) Number of portfolio projects to show per page', + 'blogname' => '(string) Blog name', + 'blogdescription' => '(string) Blog description', + 'default_pingback_flag' => '(bool) Notify blogs linked from article?', + 'default_ping_status' => '(bool) Allow link notifications from other blogs?', + 'default_comment_status' => '(bool) Allow comments on new articles?', + 'blog_public' => '(string) Site visibility; -1: private, 0: discourage search engines, 1: allow search engines', + 'jetpack_sync_non_public_post_stati' => '(bool) allow sync of post and pages with non-public posts stati', + 'jetpack_relatedposts_enabled' => '(bool) Enable related posts?', + 'jetpack_relatedposts_show_headline' => '(bool) Show headline in related posts?', + 'jetpack_relatedposts_show_thumbnails' => '(bool) Show thumbnails in related posts?', + 'instant_search_enabled' => '(bool) Enable the new Jetpack Instant Search interface', + 'jetpack_search_enabled' => '(bool) Enable Jetpack Search', + 'jetpack_search_supported' => '(bool) Jetpack Search supported', + 'jetpack_protect_whitelist' => '(array) List of IP addresses to whitelist', + 'infinite_scroll' => '(bool) Support infinite scroll of posts?', + 'default_category' => '(int) Default post category', + 'default_post_format' => '(string) Default post format', + 'require_name_email' => '(bool) Require comment authors to fill out name and email?', + 'comment_registration' => '(bool) Require users to be registered and logged in to comment?', + 'close_comments_for_old_posts' => '(bool) Automatically close comments on old posts?', + 'close_comments_days_old' => '(int) Age at which to close comments', + 'thread_comments' => '(bool) Enable threaded comments?', + 'thread_comments_depth' => '(int) Depth to thread comments', + 'page_comments' => '(bool) Break comments into pages?', + 'comments_per_page' => '(int) Number of comments to display per page', + 'default_comments_page' => '(string) newest|oldest Which page of comments to display first', + 'comment_order' => '(string) asc|desc Order to display comments within page', + 'comments_notify' => '(bool) Email me when someone comments?', + 'moderation_notify' => '(bool) Email me when a comment is helf for moderation?', + 'social_notifications_like' => '(bool) Email me when someone likes my post?', + 'social_notifications_reblog' => '(bool) Email me when someone reblogs my post?', + 'social_notifications_subscribe' => '(bool) Email me when someone follows my blog?', + 'comment_moderation' => '(bool) Moderate comments for manual approval?', + 'comment_previously_approved' => '(bool) Moderate comments unless author has a previously-approved comment?', + 'comment_max_links' => '(int) Moderate comments that contain X or more links', + 'moderation_keys' => '(string) Words or phrases that trigger comment moderation, one per line', + 'disallowed_keys' => '(string) Words or phrases that mark comment spam, one per line', + 'lang_id' => '(int) ID for language blog is written in', + 'locale' => '(string) locale code for language blog is written in', + 'wga' => '(array) Google Analytics Settings', + 'disabled_likes' => '(bool) Are likes globally disabled (they can still be turned on per post)?', + 'disabled_reblogs' => '(bool) Are reblogs disabled on posts?', + 'jetpack_comment_likes_enabled' => '(bool) Are comment likes enabled for all comments?', + 'sharing_button_style' => '(string) Style to use for sharing buttons (icon-text, icon, text, or official)', + 'sharing_label' => '(string) Label to use for sharing buttons, e.g. "Share this:"', + 'sharing_show' => '(string|array:string) Post type or array of types where sharing buttons are to be displayed', + 'sharing_open_links' => '(string) Link target for sharing buttons (same or new)', + 'twitter_via' => '(string) Twitter username to include in tweets when people share using the Twitter button', + 'jetpack-twitter-cards-site-tag' => '(string) The Twitter username of the owner of the site\'s domain.', + 'eventbrite_api_token' => '(int) The Keyring token ID for an Eventbrite token to associate with the site', + 'timezone_string' => '(string) PHP-compatible timezone string like \'UTC-5\'', + 'gmt_offset' => '(int) Site offset from UTC in hours', + 'date_format' => '(string) PHP Date-compatible date format', + 'time_format' => '(string) PHP Date-compatible time format', + 'start_of_week' => '(int) Starting day of week (0 = Sunday, 6 = Saturday)', + 'jetpack_testimonial' => '(bool) Whether testimonial custom post type is enabled for the site', + 'jetpack_testimonial_posts_per_page' => '(int) Number of testimonials to show per page', + 'jetpack_portfolio' => '(bool) Whether portfolio custom post type is enabled for the site', + 'jetpack_portfolio_posts_per_page' => '(int) Number of portfolio projects to show per page', Jetpack_SEO_Utils::FRONT_PAGE_META_OPTION => '(string) The SEO meta description for the site.', - Jetpack_SEO_Titles::TITLE_FORMATS_OPTION => '(array) SEO meta title formats. Allowed keys: front_page, posts, pages, groups, archives', - 'verification_services_codes' => '(array) Website verification codes. Allowed keys: google, pinterest, bing, yandex', - 'amp_is_enabled' => '(bool) Whether AMP is enabled for this site', - 'podcasting_archive' => '(string) The post category, if any, used for publishing podcasts', - 'site_icon' => '(int) Media attachment ID to use as site icon. Set to zero or an otherwise empty value to clear', - 'api_cache' => '(bool) Turn on/off the Jetpack JSON API cache', - 'posts_per_page' => '(int) Number of posts to show on blog pages', - 'posts_per_rss' => '(int) Number of posts to show in the RSS feed', - 'rss_use_excerpt' => '(bool) Whether the RSS feed will use post excerpts', + Jetpack_SEO_Titles::TITLE_FORMATS_OPTION => '(array) SEO meta title formats. Allowed keys: front_page, posts, pages, groups, archives', + 'verification_services_codes' => '(array) Website verification codes. Allowed keys: google, pinterest, bing, yandex, facebook', + 'amp_is_enabled' => '(bool) Whether AMP is enabled for this site', + 'podcasting_archive' => '(string) The post category, if any, used for publishing podcasts', + 'site_icon' => '(int) Media attachment ID to use as site icon. Set to zero or an otherwise empty value to clear', + 'api_cache' => '(bool) Turn on/off the Jetpack JSON API cache', + 'posts_per_page' => '(int) Number of posts to show on blog pages', + 'posts_per_rss' => '(int) Number of posts to show in the RSS feed', + 'rss_use_excerpt' => '(bool) Whether the RSS feed will use post excerpts', ), 'response_format' => array( diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-settings-v1-3-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-settings-v1-3-endpoint.php index 52a3a148..b5b10617 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-settings-v1-3-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-settings-v1-3-endpoint.php @@ -32,74 +32,75 @@ new WPCOM_JSON_API_Site_Settings_V1_3_Endpoint( array( ), 'request_format' => array( - 'blogname' => '(string) Blog name', - 'blogdescription' => '(string) Blog description', - 'default_pingback_flag' => '(bool) Notify blogs linked from article?', - 'default_ping_status' => '(bool) Allow link notifications from other blogs?', - 'default_comment_status' => '(bool) Allow comments on new articles?', - 'blog_public' => '(string) Site visibility; -1: private, 0: discourage search engines, 1: allow search engines', - 'jetpack_sync_non_public_post_stati' => '(bool) allow sync of post and pages with non-public posts stati', - 'jetpack_relatedposts_enabled' => '(bool) Enable related posts?', - 'jetpack_relatedposts_show_headline' => '(bool) Show headline in related posts?', - 'jetpack_relatedposts_show_thumbnails' => '(bool) Show thumbnails in related posts?', - 'jetpack_search_enabled' => '(bool) Enable Jetpack Search', - 'jetpack_search_supported' => '(bool) Jetpack Search supported', - 'jetpack_protect_whitelist' => '(array) List of IP addresses to whitelist', - 'infinite_scroll' => '(bool) Support infinite scroll of posts?', - 'default_category' => '(int) Default post category', - 'default_post_format' => '(string) Default post format', - 'require_name_email' => '(bool) Require comment authors to fill out name and email?', - 'comment_registration' => '(bool) Require users to be registered and logged in to comment?', - 'close_comments_for_old_posts' => '(bool) Automatically close comments on old posts?', - 'close_comments_days_old' => '(int) Age at which to close comments', - 'thread_comments' => '(bool) Enable threaded comments?', - 'thread_comments_depth' => '(int) Depth to thread comments', - 'page_comments' => '(bool) Break comments into pages?', - 'comments_per_page' => '(int) Number of comments to display per page', - 'default_comments_page' => '(string) newest|oldest Which page of comments to display first', - 'comment_order' => '(string) asc|desc Order to display comments within page', - 'comments_notify' => '(bool) Email me when someone comments?', - 'moderation_notify' => '(bool) Email me when a comment is helf for moderation?', - 'social_notifications_like' => '(bool) Email me when someone likes my post?', - 'social_notifications_reblog' => '(bool) Email me when someone reblogs my post?', - 'social_notifications_subscribe' => '(bool) Email me when someone follows my blog?', - 'comment_moderation' => '(bool) Moderate comments for manual approval?', - 'comment_whitelist' => '(bool) Moderate comments unless author has a previously-approved comment?', - 'comment_max_links' => '(int) Moderate comments that contain X or more links', - 'moderation_keys' => '(string) Words or phrases that trigger comment moderation, one per line', - 'blacklist_keys' => '(string) Words or phrases that mark comment spam, one per line', - 'lang_id' => '(int) ID for language blog is written in', - 'locale' => '(string) locale code for language blog is written in', - 'wga' => '(array) Google Analytics Settings', - 'disabled_likes' => '(bool) Are likes globally disabled (they can still be turned on per post)?', - 'disabled_reblogs' => '(bool) Are reblogs disabled on posts?', - 'jetpack_comment_likes_enabled' => '(bool) Are comment likes enabled for all comments?', - 'sharing_button_style' => '(string) Style to use for sharing buttons (icon-text, icon, text, or official)', - 'sharing_label' => '(string) Label to use for sharing buttons, e.g. "Share this:"', - 'sharing_show' => '(string|array:string) Post type or array of types where sharing buttons are to be displayed', - 'sharing_open_links' => '(string) Link target for sharing buttons (same or new)', - 'twitter_via' => '(string) Twitter username to include in tweets when people share using the Twitter button', - 'jetpack-twitter-cards-site-tag' => '(string) The Twitter username of the owner of the site\'s domain.', - 'eventbrite_api_token' => '(int) The Keyring token ID for an Eventbrite token to associate with the site', - 'timezone_string' => '(string) PHP-compatible timezone string like \'UTC-5\'', - 'gmt_offset' => '(int) Site offset from UTC in hours', - 'date_format' => '(string) PHP Date-compatible date format', - 'time_format' => '(string) PHP Date-compatible time format', - 'start_of_week' => '(int) Starting day of week (0 = Sunday, 6 = Saturday)', - 'jetpack_testimonial' => '(bool) Whether testimonial custom post type is enabled for the site', - 'jetpack_testimonial_posts_per_page' => '(int) Number of testimonials to show per page', - 'jetpack_portfolio' => '(bool) Whether portfolio custom post type is enabled for the site', - 'jetpack_portfolio_posts_per_page' => '(int) Number of portfolio projects to show per page', + 'blogname' => '(string) Blog name', + 'blogdescription' => '(string) Blog description', + 'default_pingback_flag' => '(bool) Notify blogs linked from article?', + 'default_ping_status' => '(bool) Allow link notifications from other blogs?', + 'default_comment_status' => '(bool) Allow comments on new articles?', + 'blog_public' => '(string) Site visibility; -1: private, 0: discourage search engines, 1: allow search engines', + 'jetpack_sync_non_public_post_stati' => '(bool) allow sync of post and pages with non-public posts stati', + 'jetpack_relatedposts_enabled' => '(bool) Enable related posts?', + 'jetpack_relatedposts_show_headline' => '(bool) Show headline in related posts?', + 'jetpack_relatedposts_show_thumbnails' => '(bool) Show thumbnails in related posts?', + 'instant_search_enabled' => '(bool) Enable the new Jetpack Instant Search interface', + 'jetpack_search_enabled' => '(bool) Enable Jetpack Search', + 'jetpack_search_supported' => '(bool) Jetpack Search supported', + 'jetpack_protect_whitelist' => '(array) List of IP addresses to whitelist', + 'infinite_scroll' => '(bool) Support infinite scroll of posts?', + 'default_category' => '(int) Default post category', + 'default_post_format' => '(string) Default post format', + 'require_name_email' => '(bool) Require comment authors to fill out name and email?', + 'comment_registration' => '(bool) Require users to be registered and logged in to comment?', + 'close_comments_for_old_posts' => '(bool) Automatically close comments on old posts?', + 'close_comments_days_old' => '(int) Age at which to close comments', + 'thread_comments' => '(bool) Enable threaded comments?', + 'thread_comments_depth' => '(int) Depth to thread comments', + 'page_comments' => '(bool) Break comments into pages?', + 'comments_per_page' => '(int) Number of comments to display per page', + 'default_comments_page' => '(string) newest|oldest Which page of comments to display first', + 'comment_order' => '(string) asc|desc Order to display comments within page', + 'comments_notify' => '(bool) Email me when someone comments?', + 'moderation_notify' => '(bool) Email me when a comment is helf for moderation?', + 'social_notifications_like' => '(bool) Email me when someone likes my post?', + 'social_notifications_reblog' => '(bool) Email me when someone reblogs my post?', + 'social_notifications_subscribe' => '(bool) Email me when someone follows my blog?', + 'comment_moderation' => '(bool) Moderate comments for manual approval?', + 'comment_previously_approved' => '(bool) Moderate comments unless author has a previously-approved comment?', + 'comment_max_links' => '(int) Moderate comments that contain X or more links', + 'moderation_keys' => '(string) Words or phrases that trigger comment moderation, one per line', + 'disallowed_keys' => '(string) Words or phrases that mark comment spam, one per line', + 'lang_id' => '(int) ID for language blog is written in', + 'locale' => '(string) locale code for language blog is written in', + 'wga' => '(array) Google Analytics Settings', + 'disabled_likes' => '(bool) Are likes globally disabled (they can still be turned on per post)?', + 'disabled_reblogs' => '(bool) Are reblogs disabled on posts?', + 'jetpack_comment_likes_enabled' => '(bool) Are comment likes enabled for all comments?', + 'sharing_button_style' => '(string) Style to use for sharing buttons (icon-text, icon, text, or official)', + 'sharing_label' => '(string) Label to use for sharing buttons, e.g. "Share this:"', + 'sharing_show' => '(string|array:string) Post type or array of types where sharing buttons are to be displayed', + 'sharing_open_links' => '(string) Link target for sharing buttons (same or new)', + 'twitter_via' => '(string) Twitter username to include in tweets when people share using the Twitter button', + 'jetpack-twitter-cards-site-tag' => '(string) The Twitter username of the owner of the site\'s domain.', + 'eventbrite_api_token' => '(int) The Keyring token ID for an Eventbrite token to associate with the site', + 'timezone_string' => '(string) PHP-compatible timezone string like \'UTC-5\'', + 'gmt_offset' => '(int) Site offset from UTC in hours', + 'date_format' => '(string) PHP Date-compatible date format', + 'time_format' => '(string) PHP Date-compatible time format', + 'start_of_week' => '(int) Starting day of week (0 = Sunday, 6 = Saturday)', + 'jetpack_testimonial' => '(bool) Whether testimonial custom post type is enabled for the site', + 'jetpack_testimonial_posts_per_page' => '(int) Number of testimonials to show per page', + 'jetpack_portfolio' => '(bool) Whether portfolio custom post type is enabled for the site', + 'jetpack_portfolio_posts_per_page' => '(int) Number of portfolio projects to show per page', Jetpack_SEO_Utils::FRONT_PAGE_META_OPTION => '(string) The SEO meta description for the site.', Jetpack_SEO_Titles::TITLE_FORMATS_OPTION => '(array) SEO meta title formats. Allowed keys: front_page, posts, pages, groups, archives', - 'verification_services_codes' => '(array) Website verification codes. Allowed keys: google, pinterest, bing, yandex', - 'amp_is_enabled' => '(bool) Whether AMP is enabled for this site', - 'podcasting_archive' => '(string) The post category, if any, used for publishing podcasts', - 'site_icon' => '(int) Media attachment ID to use as site icon. Set to zero or an otherwise empty value to clear', - 'api_cache' => '(bool) Turn on/off the Jetpack JSON API cache', - 'posts_per_page' => '(int) Number of posts to show on blog pages', - 'posts_per_rss' => '(int) Number of posts to show in the RSS feed', - 'rss_use_excerpt' => '(bool) Whether the RSS feed will use post excerpts', + 'verification_services_codes' => '(array) Website verification codes. Allowed keys: google, pinterest, bing, yandex, facebook', + 'amp_is_enabled' => '(bool) Whether AMP is enabled for this site', + 'podcasting_archive' => '(string) The post category, if any, used for publishing podcasts', + 'site_icon' => '(int) Media attachment ID to use as site icon. Set to zero or an otherwise empty value to clear', + 'api_cache' => '(bool) Turn on/off the Jetpack JSON API cache', + 'posts_per_page' => '(int) Number of posts to show on blog pages', + 'posts_per_rss' => '(int) Number of posts to show in the RSS feed', + 'rss_use_excerpt' => '(bool) Whether the RSS feed will use post excerpts', ), 'response_format' => array( diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-settings-v1-4-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-settings-v1-4-endpoint.php index ab59ebcc..44a61959 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-settings-v1-4-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-settings-v1-4-endpoint.php @@ -32,74 +32,76 @@ new WPCOM_JSON_API_Site_Settings_V1_4_Endpoint( array( ), 'request_format' => array( - 'blogname' => '(string) Blog name', - 'blogdescription' => '(string) Blog description', - 'default_pingback_flag' => '(bool) Notify blogs linked from article?', - 'default_ping_status' => '(bool) Allow link notifications from other blogs?', - 'default_comment_status' => '(bool) Allow comments on new articles?', - 'blog_public' => '(string) Site visibility; -1: private, 0: discourage search engines, 1: allow search engines', - 'jetpack_sync_non_public_post_stati' => '(bool) allow sync of post and pages with non-public posts stati', - 'jetpack_relatedposts_enabled' => '(bool) Enable related posts?', - 'jetpack_relatedposts_show_headline' => '(bool) Show headline in related posts?', - 'jetpack_relatedposts_show_thumbnails' => '(bool) Show thumbnails in related posts?', - 'jetpack_search_enabled' => '(bool) Enable Jetpack Search', - 'jetpack_search_supported' => '(bool) Jetpack Search supported', - 'jetpack_protect_whitelist' => '(array) List of IP addresses to whitelist', - 'infinite_scroll' => '(bool) Support infinite scroll of posts?', - 'default_category' => '(int) Default post category', - 'default_post_format' => '(string) Default post format', - 'require_name_email' => '(bool) Require comment authors to fill out name and email?', - 'comment_registration' => '(bool) Require users to be registered and logged in to comment?', - 'close_comments_for_old_posts' => '(bool) Automatically close comments on old posts?', - 'close_comments_days_old' => '(int) Age at which to close comments', - 'thread_comments' => '(bool) Enable threaded comments?', - 'thread_comments_depth' => '(int) Depth to thread comments', - 'page_comments' => '(bool) Break comments into pages?', - 'comments_per_page' => '(int) Number of comments to display per page', - 'default_comments_page' => '(string) newest|oldest Which page of comments to display first', - 'comment_order' => '(string) asc|desc Order to display comments within page', - 'comments_notify' => '(bool) Email me when someone comments?', - 'moderation_notify' => '(bool) Email me when a comment is helf for moderation?', - 'social_notifications_like' => '(bool) Email me when someone likes my post?', - 'social_notifications_reblog' => '(bool) Email me when someone reblogs my post?', - 'social_notifications_subscribe' => '(bool) Email me when someone follows my blog?', - 'comment_moderation' => '(bool) Moderate comments for manual approval?', - 'comment_whitelist' => '(bool) Moderate comments unless author has a previously-approved comment?', - 'comment_max_links' => '(int) Moderate comments that contain X or more links', - 'moderation_keys' => '(string) Words or phrases that trigger comment moderation, one per line', - 'blacklist_keys' => '(string) Words or phrases that mark comment spam, one per line', - 'lang_id' => '(int) ID for language blog is written in', - 'locale' => '(string) locale code for language blog is written in', - 'wga' => '(array) Google Analytics Settings', - 'disabled_likes' => '(bool) Are likes globally disabled (they can still be turned on per post)?', - 'disabled_reblogs' => '(bool) Are reblogs disabled on posts?', - 'jetpack_comment_likes_enabled' => '(bool) Are comment likes enabled for all comments?', - 'sharing_button_style' => '(string) Style to use for sharing buttons (icon-text, icon, text, or official)', - 'sharing_label' => '(string) Label to use for sharing buttons, e.g. "Share this:"', - 'sharing_show' => '(string|array:string) Post type or array of types where sharing buttons are to be displayed', - 'sharing_open_links' => '(string) Link target for sharing buttons (same or new)', - 'twitter_via' => '(string) Twitter username to include in tweets when people share using the Twitter button', - 'jetpack-twitter-cards-site-tag' => '(string) The Twitter username of the owner of the site\'s domain.', - 'eventbrite_api_token' => '(int) The Keyring token ID for an Eventbrite token to associate with the site', - 'timezone_string' => '(string) PHP-compatible timezone string like \'UTC-5\'', - 'gmt_offset' => '(int) Site offset from UTC in hours', - 'date_format' => '(string) PHP Date-compatible date format', - 'time_format' => '(string) PHP Date-compatible time format', - 'start_of_week' => '(int) Starting day of week (0 = Sunday, 6 = Saturday)', - 'jetpack_testimonial' => '(bool) Whether testimonial custom post type is enabled for the site', - 'jetpack_testimonial_posts_per_page' => '(int) Number of testimonials to show per page', - 'jetpack_portfolio' => '(bool) Whether portfolio custom post type is enabled for the site', - 'jetpack_portfolio_posts_per_page' => '(int) Number of portfolio projects to show per page', + 'blogname' => '(string) Blog name', + 'blogdescription' => '(string) Blog description', + 'default_pingback_flag' => '(bool) Notify blogs linked from article?', + 'default_ping_status' => '(bool) Allow link notifications from other blogs?', + 'default_comment_status' => '(bool) Allow comments on new articles?', + 'blog_public' => '(string) Site visibility; -1: private, 0: discourage search engines, 1: allow search engines', + 'jetpack_sync_non_public_post_stati' => '(bool) allow sync of post and pages with non-public posts stati', + 'jetpack_relatedposts_enabled' => '(bool) Enable related posts?', + 'jetpack_relatedposts_show_headline' => '(bool) Show headline in related posts?', + 'jetpack_relatedposts_show_thumbnails' => '(bool) Show thumbnails in related posts?', + 'instant_search_enabled' => '(bool) Enable the new Jetpack Instant Search interface', + 'jetpack_search_enabled' => '(bool) Enable Jetpack Search', + 'jetpack_search_supported' => '(bool) Jetpack Search supported', + 'jetpack_protect_whitelist' => '(array) List of IP addresses to whitelist', + 'infinite_scroll' => '(bool) Support infinite scroll of posts?', + 'default_category' => '(int) Default post category', + 'default_post_format' => '(string) Default post format', + 'require_name_email' => '(bool) Require comment authors to fill out name and email?', + 'comment_registration' => '(bool) Require users to be registered and logged in to comment?', + 'close_comments_for_old_posts' => '(bool) Automatically close comments on old posts?', + 'close_comments_days_old' => '(int) Age at which to close comments', + 'thread_comments' => '(bool) Enable threaded comments?', + 'thread_comments_depth' => '(int) Depth to thread comments', + 'page_comments' => '(bool) Break comments into pages?', + 'comments_per_page' => '(int) Number of comments to display per page', + 'default_comments_page' => '(string) newest|oldest Which page of comments to display first', + 'comment_order' => '(string) asc|desc Order to display comments within page', + 'comments_notify' => '(bool) Email me when someone comments?', + 'moderation_notify' => '(bool) Email me when a comment is helf for moderation?', + 'social_notifications_like' => '(bool) Email me when someone likes my post?', + 'social_notifications_reblog' => '(bool) Email me when someone reblogs my post?', + 'social_notifications_subscribe' => '(bool) Email me when someone follows my blog?', + 'comment_moderation' => '(bool) Moderate comments for manual approval?', + 'comment_previously_approved' => '(bool) Moderate comments unless author has a previously-approved comment?', + 'comment_max_links' => '(int) Moderate comments that contain X or more links', + 'moderation_keys' => '(string) Words or phrases that trigger comment moderation, one per line', + 'disallowed_keys' => '(string) Words or phrases that mark comment spam, one per line', + 'lang_id' => '(int) ID for language blog is written in', + 'locale' => '(string) locale code for language blog is written in', + 'wga' => '(array) Google Analytics Settings', + 'jetpack_cloudflare_analytics' => '(array) Cloudflare Analytics Settings', + 'disabled_likes' => '(bool) Are likes globally disabled (they can still be turned on per post)?', + 'disabled_reblogs' => '(bool) Are reblogs disabled on posts?', + 'jetpack_comment_likes_enabled' => '(bool) Are comment likes enabled for all comments?', + 'sharing_button_style' => '(string) Style to use for sharing buttons (icon-text, icon, text, or official)', + 'sharing_label' => '(string) Label to use for sharing buttons, e.g. "Share this:"', + 'sharing_show' => '(string|array:string) Post type or array of types where sharing buttons are to be displayed', + 'sharing_open_links' => '(string) Link target for sharing buttons (same or new)', + 'twitter_via' => '(string) Twitter username to include in tweets when people share using the Twitter button', + 'jetpack-twitter-cards-site-tag' => '(string) The Twitter username of the owner of the site\'s domain.', + 'eventbrite_api_token' => '(int) The Keyring token ID for an Eventbrite token to associate with the site', + 'timezone_string' => '(string) PHP-compatible timezone string like \'UTC-5\'', + 'gmt_offset' => '(int) Site offset from UTC in hours', + 'date_format' => '(string) PHP Date-compatible date format', + 'time_format' => '(string) PHP Date-compatible time format', + 'start_of_week' => '(int) Starting day of week (0 = Sunday, 6 = Saturday)', + 'jetpack_testimonial' => '(bool) Whether testimonial custom post type is enabled for the site', + 'jetpack_testimonial_posts_per_page' => '(int) Number of testimonials to show per page', + 'jetpack_portfolio' => '(bool) Whether portfolio custom post type is enabled for the site', + 'jetpack_portfolio_posts_per_page' => '(int) Number of portfolio projects to show per page', Jetpack_SEO_Utils::FRONT_PAGE_META_OPTION => '(string) The SEO meta description for the site.', Jetpack_SEO_Titles::TITLE_FORMATS_OPTION => '(array) SEO meta title formats. Allowed keys: front_page, posts, pages, groups, archives', - 'verification_services_codes' => '(array) Website verification codes. Allowed keys: google, pinterest, bing, yandex', - 'amp_is_enabled' => '(bool) Whether AMP is enabled for this site', - 'podcasting_archive' => '(string) The post category, if any, used for publishing podcasts', - 'site_icon' => '(int) Media attachment ID to use as site icon. Set to zero or an otherwise empty value to clear', - 'api_cache' => '(bool) Turn on/off the Jetpack JSON API cache', - 'posts_per_page' => '(int) Number of posts to show on blog pages', - 'posts_per_rss' => '(int) Number of posts to show in the RSS feed', - 'rss_use_excerpt' => '(bool) Whether the RSS feed will use post excerpts', + 'verification_services_codes' => '(array) Website verification codes. Allowed keys: google, pinterest, bing, yandex, facebook', + 'amp_is_enabled' => '(bool) Whether AMP is enabled for this site', + 'podcasting_archive' => '(string) The post category, if any, used for publishing podcasts', + 'site_icon' => '(int) Media attachment ID to use as site icon. Set to zero or an otherwise empty value to clear', + 'api_cache' => '(bool) Turn on/off the Jetpack JSON API cache', + 'posts_per_page' => '(int) Number of posts to show on blog pages', + 'posts_per_rss' => '(int) Number of posts to show in the RSS feed', + 'rss_use_excerpt' => '(bool) Whether the RSS feed will use post excerpts', ), 'response_format' => array( diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-comment-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-comment-endpoint.php index d60d541f..a5056472 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-comment-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-comment-endpoint.php @@ -21,6 +21,8 @@ new WPCOM_JSON_API_Update_Comment_Endpoint( array( 'pass_wpcom_user_details' => true, + 'allow_fallback_to_jetpack_blog_token' => true, + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/82974409/posts/843/replies/new/', 'example_request_data' => array( 'headers' => array( @@ -52,6 +54,8 @@ new WPCOM_JSON_API_Update_Comment_Endpoint( array( 'pass_wpcom_user_details' => true, + 'allow_fallback_to_jetpack_blog_token' => true, + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/82974409/comments/29/replies/new', 'example_request_data' => array( 'headers' => array( @@ -227,13 +231,12 @@ class WPCOM_JSON_API_Update_Comment_Endpoint extends WPCOM_JSON_API_Comment_Endp $user->ID = 0; } + $author = get_user_by( 'id', (int) $user->ID ); // If we have a user with an external ID saved, we can use it. if ( ! $auth_required && $user->ID - && ( - $author = get_user_by( 'id', intval( $user->ID ) ) - ) + && $author ) { $user = $author; } @@ -254,7 +257,7 @@ class WPCOM_JSON_API_Update_Comment_Endpoint extends WPCOM_JSON_API_Comment_Endp 'comment_author_url' => $user->user_url, 'comment_content' => $input['content'], 'comment_parent' => $comment_parent_id, - 'comment_type' => '', + 'comment_type' => 'comment', ); if ( $comment_parent_id ) { diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-media-v1-1-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-media-v1-1-endpoint.php index 1284cdcb..5f029269 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-media-v1-1-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-media-v1-1-endpoint.php @@ -1,61 +1,69 @@ <?php -new WPCOM_JSON_API_Update_Media_v1_1_Endpoint( array( - 'description' => 'Edit basic information about a media item.', - 'group' => 'media', - 'stat' => 'media:1:POST', - 'min_version' => '1.1', - 'max_version' => '1.1', - 'method' => 'POST', - 'path' => '/sites/%s/media/%d', - 'path_labels' => array( - '$site' => '(int|string) Site ID or domain', - '$media_ID' => '(int) The ID of the media item', - ), - - 'request_format' => array( - 'parent_id' => '(int) ID of the post this media is attached to', - 'title' => '(string) The file name.', - 'caption' => '(string) File caption.', - 'description' => '(HTML) Description of the file.', - 'alt' => "(string) Alternative text for image files.", - 'artist' => "(string) Audio Only. Artist metadata for the audio track.", - 'album' => "(string) Audio Only. Album metadata for the audio track.", - ), - - 'response_format' => array( - 'ID' => '(int) The ID of the media item', - 'date' => '(ISO 8601 datetime) The date the media was uploaded', - 'post_ID' => '(int) ID of the post this media is attached to', - 'author_ID' => '(int) ID of the user who uploaded the media', - 'URL' => '(string) URL to the file', - 'guid' => '(string) Unique identifier', - 'file' => '(string) File name', - 'extension' => '(string) File extension', - 'mime_type' => '(string) File mime type', - 'title' => '(string) File name', - 'caption' => '(string) User provided caption of the file', - 'description' => '(string) Description of the file', - 'alt' => '(string) Alternative text for image files.', - 'thumbnails' => '(object) Media item thumbnail URL options', - 'height' => '(int) (Image & video only) Height of the media item', - 'width' => '(int) (Image & video only) Width of the media item', - 'length' => '(int) (Video & audio only) Duration of the media item, in seconds', - 'exif' => '(array) (Image & audio only) Exif (meta) information about the media item', - 'videopress_guid' => '(string) (Video only) VideoPress GUID of the video when uploaded on a blog with VideoPress', - 'videopress_processing_done' => '(bool) (Video only) If the video is uploaded on a blog with VideoPress, this will return the status of processing on the video.' - ), - - 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/82974409/media/446', - 'example_request_data' => array( - 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' +new WPCOM_JSON_API_Update_Media_v1_1_Endpoint( + array( + 'description' => 'Edit basic information about a media item.', + 'group' => 'media', + 'stat' => 'media:1:POST', + 'min_version' => '1.1', + 'max_version' => '1.1', + 'method' => 'POST', + 'path' => '/sites/%s/media/%d', + 'path_labels' => array( + '$site' => '(int|string) Site ID or domain', + '$media_ID' => '(int) The ID of the media item', + ), + + 'request_format' => array( + 'parent_id' => '(int) ID of the post this media is attached to', + 'title' => '(string) The file name.', + 'caption' => '(string) File caption.', + 'description' => '(HTML) Description of the file.', + 'alt' => '(string) Alternative text for image files.', + 'rating' => '(string) Video only. Video rating.', + 'display_embed' => '(string) Video only. Whether to share or not the video.', + 'allow_download' => '(string) Video only. Whether the video can be downloaded or not.', + 'artist' => '(string) Audio Only. Artist metadata for the audio track.', + 'album' => '(string) Audio Only. Album metadata for the audio track.', + ), + + 'response_format' => array( + 'ID' => '(int) The ID of the media item', + 'date' => '(ISO 8601 datetime) The date the media was uploaded', + 'post_ID' => '(int) ID of the post this media is attached to', + 'author_ID' => '(int) ID of the user who uploaded the media', + 'URL' => '(string) URL to the file', + 'guid' => '(string) Unique identifier', + 'file' => '(string) File name', + 'extension' => '(string) File extension', + 'mime_type' => '(string) File mime type', + 'title' => '(string) File name', + 'caption' => '(string) User provided caption of the file', + 'description' => '(string) Description of the file', + 'alt' => '(string) Alternative text for image files.', + 'thumbnails' => '(object) Media item thumbnail URL options', + 'height' => '(int) (Image & video only) Height of the media item', + 'width' => '(int) (Image & video only) Width of the media item', + 'length' => '(int) (Video & audio only) Duration of the media item, in seconds', + 'exif' => '(array) (Image & audio only) Exif (meta) information about the media item', + 'rating' => '(string) (Video only) VideoPress rating of the video', + 'display_embed' => '(string) Video only. Whether to share or not the video.', + 'allow_download' => '(string) Video only. Whether the video can be downloaded or not.', + 'videopress_guid' => '(string) (Video only) VideoPress GUID of the video when uploaded on a blog with VideoPress', + 'videopress_processing_done' => '(bool) (Video only) If the video is uploaded on a blog with VideoPress, this will return the status of processing on the video.', + ), + + 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/82974409/media/446', + 'example_request_data' => array( + 'headers' => array( + 'authorization' => 'Bearer YOUR_API_TOKEN', + ), + 'body' => array( + 'title' => 'Updated Title', + ), ), - 'body' => array( - 'title' => 'Updated Title' - ) ) -) ); +); class WPCOM_JSON_API_Update_Media_v1_1_Endpoint extends WPCOM_JSON_API_Endpoint { function callback( $path = '', $blog_id = 0, $media_id = 0 ) { @@ -74,7 +82,7 @@ class WPCOM_JSON_API_Update_Media_v1_1_Endpoint extends WPCOM_JSON_API_Endpoint return new WP_Error( 'unknown_media', 'Unknown Media', 404 ); } - $input = $this->input( true ); + $input = $this->input( true ); $insert = array(); if ( isset( $input['title'] ) ) { @@ -98,7 +106,7 @@ class WPCOM_JSON_API_Update_Media_v1_1_Endpoint extends WPCOM_JSON_API_Endpoint update_post_meta( $media_id, '_wp_attachment_image_alt', $alt ); } - // audio only artist/album info + // audio only artist/album info. if ( 0 === strpos( $item->mime_type, 'audio/' ) ) { $changed = false; $id3data = wp_get_attachment_metadata( $media_id ); @@ -110,12 +118,12 @@ class WPCOM_JSON_API_Update_Media_v1_1_Endpoint extends WPCOM_JSON_API_Endpoint $id3_keys = array( 'artist' => __( 'Artist', 'jetpack' ), - 'album' => __( 'Album', 'jetpack' ) + 'album' => __( 'Album', 'jetpack' ), ); foreach ( $id3_keys as $key => $label ) { if ( isset( $input[ $key ] ) ) { - $changed = true; + $changed = true; $id3data[ $key ] = wp_strip_all_tags( $input[ $key ], true ); } } @@ -125,10 +133,47 @@ class WPCOM_JSON_API_Update_Media_v1_1_Endpoint extends WPCOM_JSON_API_Endpoint } } + // Pass the item to the handle_video_meta() that checks if it's a VideoPress item and saves it. + $result = $this->handle_video_meta( $media_id, $input, $item ); + + if ( is_wp_error( $result ) ) { + return $result; + } + $insert['ID'] = $media_id; wp_update_post( (object) $insert ); $item = $this->get_media_item_v1_1( $media_id ); return $item; } + + /** + * Persist the VideoPress metadata if the given item argument is a VideoPress item. + * + * @param string $media_id The ID of the video. + * @param array $input The request input. + * @param stdClass $item The response item. + * + * @return bool|WP_Error + */ + public function handle_video_meta( $media_id, $input, $item ) { + if ( ! class_exists( \Videopress_Attachment_Metadata::class ) ) { + return false; + } + + if ( ! \Videopress_Attachment_Metadata::is_videopress_media( $item ) ) { + return false; + } + + return \Videopress_Attachment_Metadata::persist_metadata( + $media_id, + $item->videopress_guid, + $input['title'], + $input['caption'], + $input['description'], + $input['rating'], + $input['display_embed'], + $input['allow_download'] + ); + } } diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-post-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-post-endpoint.php index 43d6fe11..07adba9e 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-post-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-post-endpoint.php @@ -301,6 +301,16 @@ class WPCOM_JSON_API_Update_Post_Endpoint extends WPCOM_JSON_API_Post_Endpoint { if ( 'publish' === $new_status && 'draft' === $last_status && ! isset( $input['date_gmt'] ) && $date_in_past ) { $input['date_gmt'] = gmdate( 'Y-m-d H:i:s' ); } + + // Untrash a post so that the proper hooks get called as well as the comments get untrashed. + if ( 'trash' === $last_status && 'trash' !== $new_status && isset( $post->ID ) ) { + wp_untrash_post( $post->ID ); + $untashed_post = get_post( $post->ID ); + // Lets make sure that we use the revert the slug. + if ( isset( $untashed_post->post_name ) && $untashed_post->post_name . '__trashed' === $input['slug'] ) { + unset( $input['slug'] ); + } + } } if ( function_exists( 'wpcom_switch_to_locale' ) ) { @@ -705,7 +715,6 @@ class WPCOM_JSON_API_Update_Post_Endpoint extends WPCOM_JSON_API_Post_Endpoint { $meta = (object) $meta; - // Custom meta description can only be set on sites that have a business subscription. if ( Jetpack_SEO_Posts::DESCRIPTION_META_KEY == $meta->key && ! Jetpack_SEO_Utils::is_enabled_jetpack_seo() ) { return new WP_Error( 'unauthorized', __( 'SEO tools are not enabled for this site.', 'jetpack' ), 403 ); } diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-post-v1-1-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-post-v1-1-endpoint.php index b3d9b98d..4dbe5fe5 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-post-v1-1-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-post-v1-1-endpoint.php @@ -329,6 +329,11 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_ if ( $reset_draft_date || $reset_scheduled_date ) { $input['date_gmt'] = gmdate( 'Y-m-d H:i:s' ); } + + // Untrash a post so that the proper hooks get called as well as the comments get untrashed. + if ( $this->should_untrash_post( $last_status, $new_status, $post ) ) { + $input = $this->untrash_post( $post, $input ); + } } if ( function_exists( 'wpcom_switch_to_blog_locale' ) ) { @@ -784,7 +789,6 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_ $meta = (object) $meta; - // Custom meta description can only be set on sites that have a business subscription. if ( Jetpack_SEO_Posts::DESCRIPTION_META_KEY == $meta->key && ! Jetpack_SEO_Utils::is_enabled_jetpack_seo() ) { return new WP_Error( 'unauthorized', __( 'SEO tools are not enabled for this site.', 'jetpack' ), 403 ); } @@ -992,6 +996,20 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_ return $_user->ID; } + protected function should_untrash_post( $last_status, $new_status, $post ) { + return 'trash' === $last_status && 'trash' !== $new_status && isset( $post->ID ); + } + + protected function untrash_post( $post, $input ) { + wp_untrash_post( $post->ID ); + $untrashed_post = get_post( $post->ID ); + // Lets make sure that we use the reverted the slug. + if ( isset( $untrashed_post->post_name ) && $untrashed_post->post_name . '__trashed' === $input['slug'] ) { + unset( $input['slug'] ); + } + return $input; + } + protected function should_load_theme_functions( $post_id = null ) { if ( empty( $post_id ) ) { $input = $this->input( true ); diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-post-v1-2-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-post-v1-2-endpoint.php index f0f2d044..b0c10bcd 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-post-v1-2-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-post-v1-2-endpoint.php @@ -151,6 +151,8 @@ new WPCOM_JSON_API_Update_Post_v1_2_Endpoint( array( ) ) ); +use function \Automattic\Jetpack\Extensions\Map\map_block_from_geo_points; + class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Post_v1_1_Endpoint { // /sites/%s/posts/new -> $blog_id @@ -273,6 +275,11 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos if ( $reset_draft_date || $reset_scheduled_date ) { $input['date_gmt'] = gmdate( 'Y-m-d H:i:s' ); } + + // Untrash a post so that the proper hooks get called as well as the comments get untrashed. + if ( $this->should_untrash_post( $last_status, $new_status, $post ) ) { + $input = $this->untrash_post( $post, $input ); + } } if ( function_exists( 'wpcom_switch_to_blog_locale' ) ) { @@ -502,6 +509,12 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos $media_id_string = join( ',', array_filter( array_map( 'absint', $media_results['media_ids'] ) ) ); } + $is_dtp_fb_post = false; + if ( in_array( '_dtp_fb', wp_list_pluck( (array) $metadata, 'key' ), true ) ) { + $is_dtp_fb_post = true; + add_filter( 'rest_api_allowed_public_metadata', array( $this, 'dtp_fb_allowed_metadata' ) ); + } + if ( $new ) { if ( isset( $input['content'] ) && ! has_shortcode( $input['content'], 'gallery' ) && ( $has_media || $has_media_by_url ) ) { switch ( ( $has_media + $has_media_by_url ) ) { @@ -525,7 +538,16 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos } } - $post_id = wp_insert_post( add_magic_quotes( $insert ), true ); + $insert['post_date'] = isset( $insert['post_date'] ) ? $insert['post_date'] : ''; + + if ( $is_dtp_fb_post ) { + $insert = $this->dtp_fb_preprocess_post( $insert, $metadata ); + } + + $post_id = $this->post_exists( $insert['post_title'], $insert['post_content'], $insert['post_date'], $post_type->name ); + if ( 0 === $post_id ) { + $post_id = wp_insert_post( add_magic_quotes( $insert ), true ); + } } else { $insert['ID'] = $post->ID; @@ -755,7 +777,6 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos $meta = (object) $meta; - // Custom meta description can only be set on sites that have a business subscription. if ( Jetpack_SEO_Posts::DESCRIPTION_META_KEY == $meta->key && ! Jetpack_SEO_Utils::is_enabled_jetpack_seo() ) { return new WP_Error( 'unauthorized', __( 'SEO tools are not enabled for this site.', 'jetpack' ), 403 ); } @@ -846,8 +867,15 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos $return['sticky'] = ( true === $sticky ); } - if ( ! empty( $media_results['errors'] ) ) - $return['media_errors'] = $media_results['errors']; + if ( ! empty( $media_results['errors'] ) ) { + /* + * Depending on whether the errors array keys are sequential or not + * json_encode would transform this into either an array or an object + * see https://www.php.net/manual/en/function.json-encode.php#example-3967 + * We use array_values to always return an array + */ + $return['media_errors'] = array_values( $media_results['errors'] ); + } if ( 'publish' !== $return['status'] && isset( $input['title'] )) { $sal_site = $this->get_sal_post_by( 'ID', $post_id, $args['context'] ); @@ -870,4 +898,96 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos return ! empty( $type ) && ! in_array( $type, array( 'post', 'revision' ) ); } + + /** + * Filter for rest_api_allowed_public_metadata. + * Adds FB's DTP specific metadata. + * + * @param array $keys Array of metadata that is accessible by the REST API. + * + * @return array + */ + public function dtp_fb_allowed_metadata( $keys ) { + return array_merge( $keys, array( '_dtp_fb', '_dtp_fb_geo_points', '_dtp_fb_post_link' ) ); + } + + /** + * Pre-process FB DTP posts before inserting. + * Here we can improve the DTP content for the following issues: + * - Render the map block based on provided coordinates in metadata + * - [TODO] Improve the title + * + * @param array $post Post to be inserted. + * @param array $metadata Metadata for the post. + * + * @return mixed + */ + private function dtp_fb_preprocess_post( $post, $metadata ) { + $geo_points_metadata = wp_filter_object_list( $metadata, array( 'key' => '_dtp_fb_geo_points' ), 'and', 'value' ); + if ( ! empty( $geo_points_metadata ) ) { + $fb_points = reset( $geo_points_metadata ); + $geo_points = array(); + + // Prepare Geo Points so that they match the format expected by the map block. + foreach ( $fb_points as $fb_point ) { + $geo_points[] = array( + 'coordinates' => array( + 'longitude' => $fb_point['longitude'], + 'latitude' => $fb_point['latitude'], + ), + 'title' => $fb_point['name'], + ); + } + $map_block = map_block_from_geo_points( $geo_points ); + + $post['post_content'] = $map_block . $post['post_content']; + } + + $post['post_format'] = 'aside'; + + return $post; + } + + /** + * Determines if a post exists based on title, content, date, and type, + * But excluding IDs in gallery shortcodes. + * This will prevent duplication of posts created through the API. + * + * @param string $title Post title. + * @param string $content Post content. + * @param string $post_date Post date. + * @param string $type Optional post type. + * @return int Post ID if post exists, 0 otherwise. + */ + private function post_exists( $title, $content, $post_date, $type = '' ) { + $date = date_create( $post_date ); + + $posts = get_posts( + array( + 'year' => date_format( $date, 'Y' ), + 'monthnum' => date_format( $date, 'n' ), + 'day' => date_format( $date, 'j' ), + 'hour' => date_format( $date, 'G' ), + 'minute' => date_format( $date, 'i' ), + 'second' => date_format( $date, 's' ), + 'post_type' => $type, + 'title' => $title, + 'numberposts' => -1, + 'suppress_filters' => false, + ) + ); + + foreach ( $posts as $post ) { + $gallery_ids_pattern = "/(\[gallery[^\]]*)(\sids='[\d,]+')([^\]]*\])/"; + + $post->post_content = preg_replace( $gallery_ids_pattern, '$1$3', $post->post_content ); + $content = preg_replace( $gallery_ids_pattern, '$1$3', $content ); + + if ( $content === $post->post_content ) { + return $post->ID; + } + } + + return 0; + } } diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-site-homepage-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-site-homepage-endpoint.php index fa8c4cf8..16d24940 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-site-homepage-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-site-homepage-endpoint.php @@ -29,7 +29,7 @@ new WPCOM_JSON_API_Update_Site_Homepage_Endpoint( array ( 'page_for_posts_id' => 0, ), ), - 'example_response' => '{"is_page_on_front":true,"page_on_front_id":1,"page_for_posts_id":0}' + 'example_response' => '{"is_page_on_front":true,"page_on_front_id":1,"page_for_posts_id":0}', ) ); class WPCOM_JSON_API_Update_Site_Homepage_Endpoint extends WPCOM_JSON_API_Endpoint { diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-site-logo-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-site-logo-endpoint.php index 2ccca0a9..996601d7 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-site-logo-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-site-logo-endpoint.php @@ -12,7 +12,7 @@ new WPCOM_JSON_API_Update_Site_Logo_Endpoint( array ( ), 'request_format' => array( 'id' => '(int) The ID of the logo post', - 'url' => '(string) The URL of the logo post', + 'url' => '(string) The URL of the logo post (deprecated)', ), 'response_format' => array( 'id' => '(int) The ID of the logo post', @@ -23,7 +23,6 @@ new WPCOM_JSON_API_Update_Site_Logo_Endpoint( array ( 'headers' => array( 'authorization' => 'Bearer YOUR_API_TOKEN' ), 'body' => array( 'id' => 12345, - 'url' => 'https://s.w.org/about/images/logos/codeispoetry-rgb.png', ), ), 'example_response' => ' @@ -68,29 +67,29 @@ class WPCOM_JSON_API_Update_Site_Logo_Endpoint extends WPCOM_JSON_API_Endpoint { $args = $this->input(); $logo_settings = $this->get_current_settings(); + if ( empty( $args ) || ! is_array( $args ) ) { return $logo_settings; } if ( isset( $args['id'] ) ) { - $logo_settings['id'] = intval( $args['id'], 10 ); - } - if ( isset( $args['url'] ) ) { - $logo_settings['url'] = $args['url']; - } - if ( isset( $args['url'] ) || isset( $args['id'] ) ) { - update_option( 'site_logo', $logo_settings ); + update_option( 'site_logo', (int) $args['id'] ); } return $this->get_current_settings(); } function get_current_settings() { - $logo_settings = get_option( 'site_logo' ); - if ( ! is_array( $logo_settings ) ) { - $logo_settings = array(); + $logo_id = get_option( 'site_logo' ); + + if ( ! $logo_id ) { + return array(); } - return $logo_settings; + + return array( + 'id' => $logo_id, + 'url' => wp_get_attachment_url( $logo_id ), + ); } } diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-user-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-user-endpoint.php index 8ec4c59c..8b8e6045 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-user-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-user-endpoint.php @@ -86,7 +86,7 @@ class WPCOM_JSON_API_Update_User_Endpoint extends WPCOM_JSON_API_Endpoint { $domains = array_unique( array_map( array( $this, 'get_subscription_domain_name' ), $subscriptions ) ); - return $domains; + return array_values( $domains ); } /** @@ -102,7 +102,17 @@ class WPCOM_JSON_API_Update_User_Endpoint extends WPCOM_JSON_API_Endpoint { if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { $domains = $this->domain_subscriptions_for_site_owned_by_user( $user_id ); if ( ! empty( $domains ) ) { - return new WP_Error( 'user_owns_domain_subscription', join( ', ', $domains ) ); + $error = new WP_Error( 'user_owns_domain_subscription', join( ', ', $domains ) ); + $error->add_data( $domains, 'additional_data' ); + return $error; + } + + $active_user_subscriptions = WPCOM_Store::get_user_subscriptions( $user_id, get_current_blog_id() ); + if ( ! empty( $active_user_subscriptions ) ) { + $product_names = array_values( wp_list_pluck( $active_user_subscriptions, 'product_name' ) ); + $error = new WP_Error( 'user_has_active_subscriptions', 'User has active subscriptions' ); + $error->add_data( $product_names, 'additional_data' ); + return $error; } } @@ -159,7 +169,7 @@ class WPCOM_JSON_API_Update_User_Endpoint extends WPCOM_JSON_API_Endpoint { } return array( - 'success' => wp_delete_user( $user_id, intval( $input['reassign'] ) ), + 'success' => wp_delete_user( $user_id, (int) $input['reassign'] ), ); } } diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-upload-media-v1-1-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-upload-media-v1-1-endpoint.php index a46d0afd..86bbec41 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-upload-media-v1-1-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-upload-media-v1-1-endpoint.php @@ -108,6 +108,11 @@ class WPCOM_JSON_API_Upload_Media_v1_1_Endpoint extends WPCOM_JSON_API_Endpoint // Normal WPCOM upload processing if ( count( $other_media_files ) > 0 || count( $media_urls ) > 0 ) { + if ( is_multisite() ) { // Do not check for available space in non multisites. + add_filter( 'wp_handle_upload_prefilter', array( $this, 'check_upload_size' ), 9 ); // used for direct media uploads. + add_filter( 'wp_handle_sideload_prefilter', array( $this, 'check_upload_size' ), 9 ); // used for uploading media via url. + } + $create_media = $this->handle_media_creation_v1_1( $other_media_files, $media_urls, $media_attrs ); $media_ids = $create_media['media_ids']; $errors = $create_media['errors']; @@ -119,7 +124,7 @@ class WPCOM_JSON_API_Upload_Media_v1_1_Endpoint extends WPCOM_JSON_API_Endpoint } if ( count( $media_items ) <= 0 ) { - return $this->api->output_early( 400, array( 'errors' => $errors ) ); + return $this->api->output_early( 400, array( 'errors' => $this->rewrite_generic_upload_error( $errors ) ) ); } $results = array(); @@ -135,13 +140,75 @@ class WPCOM_JSON_API_Upload_Media_v1_1_Endpoint extends WPCOM_JSON_API_Endpoint $response = array( 'media' => $results ); if ( count( $errors ) > 0 ) { - $response['errors'] = $errors; + $response['errors'] = $this->rewrite_generic_upload_error( $errors ); } return $response; } /** + * This changes the generic "upload_error" code to something more meaningful if possible + * + * @param array $errors Errors for the uploaded file. + * @return array The same array with an improved error message. + */ + function rewrite_generic_upload_error( $errors ) { + foreach ( $errors as $k => $error ) { + if ( 'upload_error' === $error['error'] && false !== strpos( $error['message'], '|' ) ) { + list( $errors[ $k ]['error'], $errors[ $k ]['message'] ) = explode( '|', $error['message'], 2 ); + } + } + return $errors; + } + + /** + * Determine if uploaded file exceeds space quota on multisite. + * + * This is a copy of the core function with added functionality, synced + * with this with WP_REST_Attachments_Controller::check_upload_size() + * to allow for specifying a better error message. + * + * @param array $file $_FILES array for a given file. + * @return array Maybe extended with an error message. + */ + function check_upload_size( $file ) { + if ( get_site_option( 'upload_space_check_disabled' ) ) { + return $file; + } + + if ( isset( $file['error'] ) && $file['error'] > 0 ) { // There's already an error. Error Codes Reference: https://www.php.net/manual/en/features.file-upload.errors.php . + return $file; + } + + if ( defined( 'WP_IMPORTING' ) ) { + return $file; + } + + $space_left = get_upload_space_available(); + + $file_size = filesize( $file['tmp_name'] ); + if ( $space_left < $file_size ) { + /* translators: %s: Required disk space in kilobytes. */ + $file['error'] = 'rest_upload_limited_space|' . sprintf( __( 'Not enough space to upload. %s KB needed.', 'default' ), number_format( ( $file_size - $space_left ) / KB_IN_BYTES ) ); + } + + $max_upload_size = KB_IN_BYTES * get_site_option( 'fileupload_maxk', 1500 ); + if ( defined( 'IS_WPCOM' ) && IS_WPCOM && defined( 'WPCOM_MAX_UPLOAD_FILE_SIZE' ) ) { + $max_upload_size = WPCOM_MAX_UPLOAD_FILE_SIZE; + } + + if ( $file_size > $max_upload_size ) { + /* translators: %s: Maximum allowed file size in kilobytes. */ + $file['error'] = 'rest_upload_file_too_big|' . sprintf( __( 'This file is too big. Files must be less than %s KB in size.', 'jetpack' ), $max_upload_size / KB_IN_BYTES ); + } + + if ( upload_is_user_over_quota( false ) ) { + $file['error'] = 'rest_upload_user_quota_exceeded|' . __( 'You have used your space quota. Please delete files before uploading.', 'default' ); + } + + return $file; + } + /** * Force to use the WPCOM API instead of proxy back to the Jetpack API if the blog is a paid Jetpack * blog w/ the VideoPress module enabled AND the uploaded file is a video. * diff --git a/plugins/jetpack/json-endpoints/jetpack/class-jetpack-json-api-delete-backup-helper-script-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class-jetpack-json-api-delete-backup-helper-script-endpoint.php index 2729dc58..3f6a88dc 100644 --- a/plugins/jetpack/json-endpoints/jetpack/class-jetpack-json-api-delete-backup-helper-script-endpoint.php +++ b/plugins/jetpack/json-endpoints/jetpack/class-jetpack-json-api-delete-backup-helper-script-endpoint.php @@ -3,11 +3,15 @@ * API endpoint /sites/%s/delete-backup-helper-script * This API endpoint deletes a Jetpack Backup Helper Script * - * @package Jetpack + * @package automattic/jetpack */ use Automattic\Jetpack\Backup\Helper_Script_Manager; +/** + * API endpoint /sites/%s/delete-backup-helper-script + * This API endpoint deletes a Jetpack Backup Helper Script + */ class Jetpack_JSON_API_Delete_Backup_Helper_Script_Endpoint extends Jetpack_JSON_API_Endpoint { /** * This endpoint is only accessible from Jetpack Backup; it requires no further capabilities. @@ -43,7 +47,7 @@ class Jetpack_JSON_API_Delete_Backup_Helper_Script_Endpoint extends Jetpack_JSON * @param null $object Unused. * @return bool|WP_Error a WP_Error object or true if the input seems ok. */ - protected function validate_input( $object ) { + protected function validate_input( $object ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable $args = $this->input(); if ( ! isset( $args['path'] ) ) { diff --git a/plugins/jetpack/json-endpoints/jetpack/class-jetpack-json-api-install-backup-helper-script-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class-jetpack-json-api-install-backup-helper-script-endpoint.php index a5c2bdeb..b0ef0b71 100644 --- a/plugins/jetpack/json-endpoints/jetpack/class-jetpack-json-api-install-backup-helper-script-endpoint.php +++ b/plugins/jetpack/json-endpoints/jetpack/class-jetpack-json-api-install-backup-helper-script-endpoint.php @@ -3,12 +3,16 @@ * API endpoint /sites/%s/install-backup-helper-script * This API endpoint installs a Helper Script to assist Jetpack Backup fetch data * - * @package Jetpack + * @package automattic/jetpack */ use Automattic\Jetpack\Backup\Helper_Script_Manager; -class Jetpack_JSON_API_Install_Backup_Helper_Script_Endpoint extends Jetpack_JSON_API_Endpoint { +/** + * API endpoint /sites/%s/install-backup-helper-script + * This API endpoint installs a Helper Script to assist Jetpack Backup fetch data + */ +class Jetpack_JSON_API_Install_Backup_Helper_Script_Endpoint extends Jetpack_JSON_API_Endpoint { /** * This endpoint is only accessible from Jetpack Backup; it requires no further capabilities. * @@ -43,13 +47,14 @@ class Jetpack_JSON_API_Install_Backup_Helper_Script_Endpoint extends Jetpack_JSO * @param null $object Unused. * @return bool|WP_Error a WP_Error object or true if the input seems ok. */ - protected function validate_input( $object ) { + protected function validate_input( $object ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable $args = $this->input(); if ( ! isset( $args['helper'] ) ) { return new WP_Error( 'invalid_args', __( 'You must specify a helper script body', 'jetpack' ), 400 ); } + // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode $this->helper_script = base64_decode( $args['helper'] ); if ( ! $this->helper_script ) { return new WP_Error( 'invalid_args', __( 'Helper script body must be base64 encoded', 'jetpack' ), 400 ); diff --git a/plugins/jetpack/json-endpoints/jetpack/class-jetpack-json-api-modules-list-v1-2-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class-jetpack-json-api-modules-list-v1-2-endpoint.php new file mode 100644 index 00000000..8f7fa76a --- /dev/null +++ b/plugins/jetpack/json-endpoints/jetpack/class-jetpack-json-api-modules-list-v1-2-endpoint.php @@ -0,0 +1,50 @@ +<?php +/** + * List modules v1.2 endpoint. + * + * @package automattic/jetpack + */ + +use Automattic\Jetpack\Status; +/** + * List modules v1.2 endpoint. + */ +class Jetpack_JSON_API_Modules_List_V1_2_Endpoint extends Jetpack_JSON_API_Endpoint { + + /** + * This endpoint allows authentication both via a blog and a user token. + * If a user token is used, that user should have `jetpack_manage_modules` capability. + * + * @var array|string + */ + protected $needed_capabilities = 'jetpack_manage_modules'; + + /** + * Fetch modules list. + * + * @return array An array of module objects. + */ + protected function result() { + require_once JETPACK__PLUGIN_DIR . 'class.jetpack-admin.php'; + + $is_offline_mode = ( new Status() )->is_offline_mode(); + + $modules = Jetpack_Admin::init()->get_modules(); + + foreach ( $modules as $slug => $properties ) { + if ( $is_offline_mode ) { + $requires_connection = isset( $modules[ $slug ]['requires_connection'] ) && $modules[ $slug ]['requires_connection']; + $requires_user_connection = isset( $modules[ $slug ]['requires_user_connection'] ) && $modules[ $slug ]['requires_user_connection']; + if ( + $requires_connection || $requires_user_connection + ) { + $modules[ $slug ]['activated'] = false; + } + } + } + + $modules = Jetpack::get_translated_modules( $modules ); + + return array( 'modules' => $modules ); + } +} diff --git a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-cron-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-cron-endpoint.php index 9638c3eb..c1ca60a7 100644 --- a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-cron-endpoint.php +++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-cron-endpoint.php @@ -200,12 +200,7 @@ class Jetpack_JSON_API_Cron_Schedule_Endpoint extends Jetpack_JSON_API_Cron_Endp $lock = $this->lock_cron(); $next = wp_schedule_single_event( $args['timestamp'], $hook, $arguments ); $this->maybe_unlock_cron( $lock ); - /** - * Note: Before WP 5.1, the return value was either `false` or `null`. - * With 5.1 and later, the return value is now `false` or `true`. - * We need to account for both. - */ - return array( 'success' => false !== $next ); + return array( 'success' => $next ); } } diff --git a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-endpoint.php index 8a349015..07457d7d 100644 --- a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-endpoint.php +++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-endpoint.php @@ -94,6 +94,10 @@ abstract class Jetpack_JSON_API_Endpoint extends WPCOM_JSON_API_Endpoint { * @return bool|WP_Error */ protected function check_capability( $capability ) { + // If this endpoint accepts site based authentication, skip capabilities check. + if ( $this->accepts_site_based_authentication() ) { + return true; + } if ( is_array( $capability ) ) { // the idea is that the we can pass in an array of capabilitie that the user needs to have before we allowing them to do something $capabilities = ( isset( $capability['capabilities'] ) ? $capability['capabilities'] : $capability ); @@ -111,11 +115,15 @@ abstract class Jetpack_JSON_API_Endpoint extends WPCOM_JSON_API_Endpoint { $failed[] = $cap; } } - // Check that must have conditions is less then + // Check if all conditions have passed. if ( $passed < $must_pass ) { - return new WP_Error( 'unauthorized', sprintf( __( 'This user is not authorized to %s on this blog.', 'jetpack' ), implode( ', ', $failed ), 403 ) ); + return new WP_Error( + 'unauthorized', + /* translators: %s: comma-separated list of capabilities */ + sprintf( __( 'This user is not authorized to %s on this blog.', 'jetpack' ), implode( ', ', $failed ) ), + 403 + ); } - } else { if ( !current_user_can( $capability ) ) { return new WP_Error( 'unauthorized', sprintf( __( 'This user is not authorized to %s on this blog.', 'jetpack' ), $capability ), 403 ); diff --git a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-comment-backup-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-comment-backup-endpoint.php index 0e4bc256..e526902b 100644 --- a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-comment-backup-endpoint.php +++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-comment-backup-endpoint.php @@ -11,12 +11,15 @@ class Jetpack_JSON_API_Get_Comment_Backup_Endpoint extends Jetpack_JSON_API_Endp return new WP_Error( 'comment_id_not_specified', __( 'You must specify a Comment ID', 'jetpack' ), 400 ); } - $this->comment_id = intval( $comment_id ); + $this->comment_id = (int) $comment_id; return true; } protected function result() { + // Disable Sync as this is a read-only operation and triggered by sync activity. + \Automattic\Jetpack\Sync\Actions::mark_sync_read_only(); + $comment = get_comment( $this->comment_id ); if ( empty( $comment ) ) { return new WP_Error( 'comment_not_found', __( 'Comment not found', 'jetpack' ), 404 ); diff --git a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-database-object-backup-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-database-object-backup-endpoint.php index b7134730..05a5c7f8 100644 --- a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-database-object-backup-endpoint.php +++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-database-object-backup-endpoint.php @@ -64,6 +64,9 @@ class Jetpack_JSON_API_Get_Database_Object_Backup_Endpoint extends Jetpack_JSON_ protected function result() { global $wpdb; + // Disable Sync as this is a read-only operation and triggered by sync activity. + \Automattic\Jetpack\Sync\Actions::mark_sync_read_only(); + $table = $wpdb->prefix . $this->object_type['table']; $id_field = $this->object_type['id_field']; diff --git a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-option-backup-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-option-backup-endpoint.php index a5d8d3a7..642e3139 100644 --- a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-option-backup-endpoint.php +++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-option-backup-endpoint.php @@ -7,7 +7,7 @@ class Jetpack_JSON_API_Get_Option_Backup_Endpoint extends Jetpack_JSON_API_Endpo protected $option_names; function validate_input( $object ) { - $query_args = $this->query_args(); + $query_args = $this->query_args(); if ( empty( $query_args['name'] ) ) { return new WP_Error( 'option_name_not_specified', __( 'You must specify an option name', 'jetpack' ), 400 ); @@ -23,6 +23,9 @@ class Jetpack_JSON_API_Get_Option_Backup_Endpoint extends Jetpack_JSON_API_Endpo } protected function result() { + // Disable Sync as this is a read-only operation and triggered by sync activity. + \Automattic\Jetpack\Sync\Actions::mark_sync_read_only(); + $options = array_map( array( $this, 'get_option_row' ), $this->option_names ); return array( 'options' => $options ); } diff --git a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-post-backup-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-post-backup-endpoint.php index 7e7ff2a7..c6102dfc 100644 --- a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-post-backup-endpoint.php +++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-post-backup-endpoint.php @@ -11,7 +11,7 @@ class Jetpack_JSON_API_Get_Post_Backup_Endpoint extends Jetpack_JSON_API_Endpoin return new WP_Error( 'post_id_not_specified', __( 'You must specify a Post ID', 'jetpack' ), 400 ); } - $this->post_id = intval( $post_id ); + $this->post_id = (int) $post_id; return true; } @@ -19,6 +19,9 @@ class Jetpack_JSON_API_Get_Post_Backup_Endpoint extends Jetpack_JSON_API_Endpoin protected function result() { global $wpdb; + // Disable Sync as this is a read-only operation and triggered by sync activity. + \Automattic\Jetpack\Sync\Actions::mark_sync_read_only(); + $post = get_post( $this->post_id ); if ( empty( $post ) ) { return new WP_Error( 'post_not_found', __( 'Post not found', 'jetpack' ), 404 ); diff --git a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-term-backup-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-term-backup-endpoint.php index 40d0ab97..21882ddd 100644 --- a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-term-backup-endpoint.php +++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-term-backup-endpoint.php @@ -11,12 +11,15 @@ class Jetpack_JSON_API_Get_Term_Backup_Endpoint extends Jetpack_JSON_API_Endpoin return new WP_Error( 'term_id_not_specified', __( 'You must specify a Term ID', 'jetpack' ), 400 ); } - $this->term_id = intval( $term_id ); + $this->term_id = (int) $term_id; return true; } protected function result() { + // Disable Sync as this is a read-only operation and triggered by sync activity. + \Automattic\Jetpack\Sync\Actions::mark_sync_read_only(); + $term = get_term( $this->term_id ); if ( empty( $term ) ) { return new WP_Error( 'term_not_found', __( 'Term not found', 'jetpack' ), 404 ); diff --git a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-user-backup-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-user-backup-endpoint.php index 22ca195d..a57e4579 100644 --- a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-user-backup-endpoint.php +++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-user-backup-endpoint.php @@ -11,12 +11,15 @@ class Jetpack_JSON_API_Get_User_Backup_Endpoint extends Jetpack_JSON_API_Endpoin return new WP_Error( 'user_id_not_specified', __( 'You must specify a User ID', 'jetpack' ), 400 ); } - $this->user_id = intval( $user_id ); + $this->user_id = (int) $user_id; return true; } protected function result() { + // Disable Sync as this is a read-only operation and triggered by sync activity. + \Automattic\Jetpack\Sync\Actions::mark_sync_read_only(); + $user = get_user_by( 'id', $this->user_id ); if ( empty( $user ) ) { return new WP_Error( 'user_not_found', __( 'User not found', 'jetpack' ), 404 ); diff --git a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-log-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-log-endpoint.php index f1d0f4da..ba6ea7cf 100644 --- a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-log-endpoint.php +++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-log-endpoint.php @@ -7,7 +7,7 @@ class Jetpack_JSON_API_Jetpack_Log_Endpoint extends Jetpack_JSON_API_Endpoint { protected function result() { $args = $this->input(); $event = ( isset( $args['event'] ) && is_string( $args['event'] ) ) ? $code : false; - $num = ( isset( $args['num'] ) ) ? intval( $num ) : false; + $num = ( isset( $args['num'] ) ) ? (int) $num : false; return array( 'log' => Jetpack::get_log( $event, $num ) diff --git a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-delete-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-delete-endpoint.php index 3748d621..94b6ddd3 100644 --- a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-delete-endpoint.php +++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-delete-endpoint.php @@ -2,46 +2,48 @@ // POST /sites/%s/plugins/%s/delete new Jetpack_JSON_API_Plugins_Delete_Endpoint( array( - 'description' => 'Delete/Uninstall a plugin from your jetpack blog', - 'group' => '__do_not_document', - 'stat' => 'plugins:1:delete', - 'min_version' => '1', - 'max_version' => '1.1', - 'method' => 'POST', - 'path' => '/sites/%s/plugins/%s/delete', - 'path_labels' => array( + 'description' => 'Delete/Uninstall a plugin from your jetpack blog', + 'group' => '__do_not_document', + 'stat' => 'plugins:1:delete', + 'min_version' => '1', + 'max_version' => '1.1', + 'method' => 'POST', + 'path' => '/sites/%s/plugins/%s/delete', + 'path_labels' => array( '$site' => '(int|string) The site ID, The site domain', '$plugin' => '(int|string) The plugin slug to delete', ), - 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format, - 'example_request_data' => array( + 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format, + 'allow_jetpack_site_auth' => true, + 'example_request_data' => array( 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' + 'authorization' => 'Bearer YOUR_API_TOKEN', ), ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/akismet%2Fakismet/delete' + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/akismet%2Fakismet/delete', ) ); // v1.2 new Jetpack_JSON_API_Plugins_Delete_Endpoint( array( - 'description' => 'Delete/Uninstall a plugin from your jetpack blog', - 'group' => '__do_not_document', - 'stat' => 'plugins:1:delete', - 'min_version' => '1.2', - 'method' => 'POST', - 'path' => '/sites/%s/plugins/%s/delete', - 'path_labels' => array( + 'description' => 'Delete/Uninstall a plugin from your jetpack blog', + 'group' => '__do_not_document', + 'stat' => 'plugins:1:delete', + 'min_version' => '1.2', + 'method' => 'POST', + 'path' => '/sites/%s/plugins/%s/delete', + 'path_labels' => array( '$site' => '(int|string) The site ID, The site domain', '$plugin' => '(int|string) The plugin slug to delete', ), - 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format_v1_2, - 'example_request_data' => array( + 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format_v1_2, + 'allow_jetpack_site_auth' => true, + 'example_request_data' => array( 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' + 'authorization' => 'Bearer YOUR_API_TOKEN', ), ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.2/sites/example.wordpress.org/plugins/akismet%2Fakismet/delete' + 'example_request' => 'https://public-api.wordpress.com/rest/v1.2/sites/example.wordpress.org/plugins/akismet%2Fakismet/delete', ) ); diff --git a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-endpoint.php index 6c3b4d0a..95a6645c 100644 --- a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-endpoint.php +++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-endpoint.php @@ -144,14 +144,22 @@ abstract class Jetpack_JSON_API_Plugins_Endpoint extends Jetpack_JSON_API_Endpoi $plugin['action_links'] = $action_link; } - $autoupdate = in_array( $plugin_file, Jetpack_Options::get_option( 'autoupdate_plugins', array() ) ); - $plugin['autoupdate'] = $autoupdate; + $plugin['plugin'] = $plugin_file; + if ( ! class_exists( 'WP_Automatic_Updater' ) ) { + require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; + } + $autoupdate = ( new WP_Automatic_Updater() )->should_update( 'plugin', (object) $plugin, WP_PLUGIN_DIR ); + $plugin['autoupdate'] = $autoupdate; $autoupdate_translation = in_array( $plugin_file, Jetpack_Options::get_option( 'autoupdate_plugins_translations', array() ) ); $plugin['autoupdate_translation'] = $autoupdate || $autoupdate_translation || Jetpack_Options::get_option( 'autoupdate_translations', false ); $plugin['uninstallable'] = is_uninstallable_plugin( $plugin_file ); + if ( is_multisite() ) { + $plugin['network_active'] = is_plugin_active_for_network( $plugin_file ); + } + if ( ! empty ( $this->log[ $plugin_file ] ) ) { $plugin['log'] = $this->log[ $plugin_file ]; } @@ -176,13 +184,21 @@ abstract class Jetpack_JSON_API_Plugins_Endpoint extends Jetpack_JSON_API_Endpoi $plugin['action_links'] = $action_link; } - $autoupdate = $this->plugin_has_autoupdates_enabled( $plugin_file ); - $plugin['autoupdate'] = $autoupdate; + $plugin['plugin'] = $plugin_file; + if ( ! class_exists( 'WP_Automatic_Updater' ) ) { + require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; + } + $autoupdate = ( new WP_Automatic_Updater() )->should_update( 'plugin', (object) $plugin, WP_PLUGIN_DIR ); + $plugin['autoupdate'] = $autoupdate; $autoupdate_translation = $this->plugin_has_translations_autoupdates_enabled( $plugin_file ); $plugin['autoupdate_translation'] = $autoupdate || $autoupdate_translation || Jetpack_Options::get_option( 'autoupdate_translations', false ); $plugin['uninstallable'] = is_uninstallable_plugin( $plugin_file ); + if ( is_multisite() ) { + $plugin['network_active'] = is_plugin_active_for_network( $plugin_file ); + } + if ( ! empty ( $this->log[ $plugin_file ] ) ) { $plugin['log'] = $this->log[ $plugin_file ]; } @@ -190,15 +206,10 @@ abstract class Jetpack_JSON_API_Plugins_Endpoint extends Jetpack_JSON_API_Endpoi return $plugin; } - protected function plugin_has_autoupdates_enabled( $plugin_file ) { - return (bool) in_array( $plugin_file, Jetpack_Options::get_option( 'autoupdate_plugins', array() ) ); - } - protected function plugin_has_translations_autoupdates_enabled( $plugin_file ) { return (bool) in_array( $plugin_file, Jetpack_Options::get_option( 'autoupdate_plugins_translations', array() ) ); } - protected function get_file_mod_capabilities() { $reasons_can_not_autoupdate = array(); $reasons_can_not_modify_files = array(); @@ -248,10 +259,33 @@ abstract class Jetpack_JSON_API_Plugins_Endpoint extends Jetpack_JSON_API_Endpoi $plugins = array(); /** This filter is documented in wp-admin/includes/class-wp-plugins-list-table.php */ $installed_plugins = apply_filters( 'all_plugins', get_plugins() ); - foreach( $this->plugins as $plugin ) { - if ( ! isset( $installed_plugins[ $plugin ] ) ) + foreach ( $this->plugins as $plugin ) { + if ( ! isset( $installed_plugins[ $plugin ] ) ) { continue; - $plugins[] = $this->format_plugin( $plugin, $installed_plugins[ $plugin ] ); + } + + $formatted_plugin = $this->format_plugin( $plugin, $installed_plugins[ $plugin ] ); + + // If this endpoint accepts site based authentication and a blog token is used, skip capabilities check. + if ( $this->accepts_site_based_authentication() ) { + $plugins[] = $formatted_plugin; + continue; + } + + /* + * Do not show network-active plugins + * to folks who do not have the permission to see them. + */ + if ( + /** This filter is documented in src/wp-admin/includes/class-wp-plugins-list-table.php */ + ! apply_filters( 'show_network_active_plugins', current_user_can( 'manage_network_plugins' ) ) + && ! empty( $formatted_plugin['network_active'] ) + && true === $formatted_plugin['network_active'] + ) { + continue; + } + + $plugins[] = $formatted_plugin; } $args = $this->query_args(); @@ -272,6 +306,11 @@ abstract class Jetpack_JSON_API_Plugins_Endpoint extends Jetpack_JSON_API_Endpoi $this->network_wide = true; } + // If this endpoint accepts site based authentication and a blog token is used, skip capabilities check. + if ( $this->accepts_site_based_authentication() ) { + return true; + } + if ( $this->network_wide && ! current_user_can( 'manage_network_plugins' ) ) { return new WP_Error( 'unauthorized', __( 'This user is not authorized to manage plugins network wide.', 'jetpack' ), 403 ); } diff --git a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-get-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-get-endpoint.php index 276fca49..6d2dd612 100644 --- a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-get-endpoint.php +++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-get-endpoint.php @@ -2,23 +2,24 @@ new Jetpack_JSON_API_Plugins_Get_Endpoint( array( - 'description' => 'Get the Plugin data.', - 'method' => 'GET', - 'path' => '/sites/%s/plugins/%s/', - 'min_version' => '1', - 'max_version' => '1.1', - 'stat' => 'plugins:1', - 'path_labels' => array( + 'description' => 'Get the Plugin data.', + 'method' => 'GET', + 'path' => '/sites/%s/plugins/%s/', + 'min_version' => '1', + 'max_version' => '1.1', + 'stat' => 'plugins:1', + 'path_labels' => array( '$site' => '(int|string) The site ID, The site domain', '$plugin' => '(string) The plugin ID', ), - 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format, - 'example_request_data' => array( + 'allow_jetpack_site_auth' => true, + 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format, + 'example_request_data' => array( 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' + 'authorization' => 'Bearer YOUR_API_TOKEN', ), ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/hello-dolly%20hello' + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/hello-dolly%20hello', ) ); // no v1.2 version since it is .com only diff --git a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-install-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-install-endpoint.php index bbd6de19..77e09c88 100644 --- a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-install-endpoint.php +++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-install-endpoint.php @@ -5,46 +5,48 @@ include_once ABSPATH . 'wp-admin/includes/file.php'; // POST /sites/%s/plugins/%s/install new Jetpack_JSON_API_Plugins_Install_Endpoint( array( - 'description' => 'Install a plugin to your jetpack blog', - 'group' => '__do_not_document', - 'stat' => 'plugins:1:install', - 'min_version' => '1', - 'max_version' => '1.1', - 'method' => 'POST', - 'path' => '/sites/%s/plugins/%s/install', - 'path_labels' => array( + 'description' => 'Install a plugin to your jetpack blog', + 'group' => '__do_not_document', + 'stat' => 'plugins:1:install', + 'min_version' => '1', + 'max_version' => '1.1', + 'method' => 'POST', + 'path' => '/sites/%s/plugins/%s/install', + 'path_labels' => array( '$site' => '(int|string) The site ID, The site domain', '$plugin' => '(int|string) The plugin slug to install', ), - 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format, - 'example_request_data' => array( + 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format, + 'allow_jetpack_site_auth' => true, + 'example_request_data' => array( 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' + 'authorization' => 'Bearer YOUR_API_TOKEN', ), ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/akismet/install' + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/akismet/install', ) ); new Jetpack_JSON_API_Plugins_Install_Endpoint( array( - 'description' => 'Install a plugin to your jetpack blog', - 'group' => '__do_not_document', - 'stat' => 'plugins:1:install', - 'min_version' => '1.2', - 'method' => 'POST', - 'path' => '/sites/%s/plugins/%s/install', - 'path_labels' => array( + 'description' => 'Install a plugin to your jetpack blog', + 'group' => '__do_not_document', + 'stat' => 'plugins:1:install', + 'min_version' => '1.2', + 'method' => 'POST', + 'path' => '/sites/%s/plugins/%s/install', + 'path_labels' => array( '$site' => '(int|string) The site ID, The site domain', '$plugin' => '(int|string) The plugin slug to install', ), - 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format_v1_2, - 'example_request_data' => array( + 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format_v1_2, + 'allow_jetpack_site_auth' => true, + 'example_request_data' => array( 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' + 'authorization' => 'Bearer YOUR_API_TOKEN', ), ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.2/sites/example.wordpress.org/plugins/akismet/install' + 'example_request' => 'https://public-api.wordpress.com/rest/v1.2/sites/example.wordpress.org/plugins/akismet/install', ) ); diff --git a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-list-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-list-endpoint.php index ff8004d0..5f59b687 100644 --- a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-list-endpoint.php +++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-list-endpoint.php @@ -2,24 +2,25 @@ new Jetpack_JSON_API_Plugins_List_Endpoint( array( - 'description' => 'Get installed Plugins on your blog', - 'method' => 'GET', - 'path' => '/sites/%s/plugins', - 'stat' => 'plugins', - 'min_version' => '1', - 'max_version' => '1.1', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain' + 'description' => 'Get installed Plugins on your blog', + 'method' => 'GET', + 'path' => '/sites/%s/plugins', + 'stat' => 'plugins', + 'min_version' => '1', + 'max_version' => '1.1', + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', ), - 'response_format' => array( + 'allow_jetpack_site_auth' => true, + 'response_format' => array( 'plugins' => '(plugin) An array of plugin objects.', ), - 'example_request_data' => array( + 'example_request_data' => array( 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' + 'authorization' => 'Bearer YOUR_API_TOKEN', ), ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins' + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins', ) ); // No v1.2 versions since they are .com only diff --git a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-modify-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-modify-endpoint.php index 232cc2c5..d562f02e 100644 --- a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-modify-endpoint.php +++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-modify-endpoint.php @@ -4,68 +4,70 @@ use Automattic\Jetpack\Constants; new Jetpack_JSON_API_Plugins_Modify_Endpoint( array( - 'description' => 'Activate/Deactivate a Plugin on your Jetpack Site, or set automatic updates', - 'min_version' => '1', - 'max_version' => '1.1', - 'method' => 'POST', - 'path' => '/sites/%s/plugins/%s', - 'stat' => 'plugins:1:modify', - 'path_labels' => array( + 'description' => 'Activate/Deactivate a Plugin on your Jetpack Site, or set automatic updates', + 'min_version' => '1', + 'max_version' => '1.1', + 'method' => 'POST', + 'path' => '/sites/%s/plugins/%s', + 'stat' => 'plugins:1:modify', + 'path_labels' => array( '$site' => '(int|string) The site ID, The site domain', '$plugin' => '(string) The plugin ID', ), - 'request_format' => array( + 'allow_jetpack_site_auth' => true, + 'request_format' => array( 'action' => '(string) Possible values are \'update\'', 'autoupdate' => '(bool) Whether or not to automatically update the plugin', 'active' => '(bool) Activate or deactivate the plugin', 'network_wide' => '(bool) Do action network wide (default value: false)', ), - 'query_parameters' => array( + 'query_parameters' => array( 'autoupdate' => '(bool=false) If the update is happening as a result of autoupdate event', ), - 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format, - 'example_request_data' => array( + 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format, + 'example_request_data' => array( 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' + 'authorization' => 'Bearer YOUR_API_TOKEN', ), 'body' => array( 'action' => 'update', - ) + ), ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/hello-dolly%20hello' + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/hello-dolly%20hello', ) ); new Jetpack_JSON_API_Plugins_Modify_Endpoint( array( - 'description' => 'Activate/Deactivate a list of plugins on your Jetpack Site, or set automatic updates', - 'min_version' => '1', - 'max_version' => '1.1', - 'method' => 'POST', - 'path' => '/sites/%s/plugins', - 'stat' => 'plugins:modify', - 'path_labels' => array( + 'description' => 'Activate/Deactivate a list of plugins on your Jetpack Site, or set automatic updates', + 'min_version' => '1', + 'max_version' => '1.1', + 'method' => 'POST', + 'path' => '/sites/%s/plugins', + 'stat' => 'plugins:modify', + 'path_labels' => array( '$site' => '(int|string) The site ID, The site domain', ), - 'request_format' => array( + 'request_format' => array( 'action' => '(string) Possible values are \'update\'', 'autoupdate' => '(bool) Whether or not to automatically update the plugin', 'active' => '(bool) Activate or deactivate the plugin', 'network_wide' => '(bool) Do action network wide (default value: false)', 'plugins' => '(array) A list of plugin ids to modify', ), - 'query_parameters' => array( + 'allow_jetpack_site_auth' => true, + 'query_parameters' => array( 'autoupdate' => '(bool=false) If the update is happening as a result of autoupdate event', ), - 'response_format' => array( + 'response_format' => array( 'plugins' => '(array:plugin) An array of plugin objects.', 'updated' => '(array) A list of plugin ids that were updated. Only present if action is update.', 'not_updated' => '(array) A list of plugin ids that were not updated. Only present if action is update.', 'log' => '(array) Update log. Only present if action is update.', ), - 'example_request_data' => array( + 'example_request_data' => array( 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' + 'authorization' => 'Bearer YOUR_API_TOKEN', ), 'body' => array( 'active' => true, @@ -73,34 +75,35 @@ new Jetpack_JSON_API_Plugins_Modify_Endpoint( 'jetpack/jetpack', 'akismet/akismet', ), - ) + ), ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins' + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins', ) ); new Jetpack_JSON_API_Plugins_Modify_Endpoint( array( - 'description' => 'Update a Plugin on your Jetpack Site', - 'min_version' => '1', - 'max_version' => '1.1', - 'method' => 'POST', - 'path' => '/sites/%s/plugins/%s/update/', - 'stat' => 'plugins:1:update', - 'path_labels' => array( + 'description' => 'Update a Plugin on your Jetpack Site', + 'min_version' => '1', + 'max_version' => '1.1', + 'method' => 'POST', + 'path' => '/sites/%s/plugins/%s/update/', + 'stat' => 'plugins:1:update', + 'path_labels' => array( '$site' => '(int|string) The site ID, The site domain', '$plugin' => '(string) The plugin ID', ), - 'query_parameters' => array( + 'allow_jetpack_site_auth' => true, + 'query_parameters' => array( 'autoupdate' => '(bool=false) If the update is happening as a result of autoupdate event', ), - 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format, - 'example_request_data' => array( + 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format, + 'example_request_data' => array( 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' + 'authorization' => 'Bearer YOUR_API_TOKEN', ), ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/hello-dolly%20hello/update' + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/hello-dolly%20hello/update', ) ); @@ -170,15 +173,15 @@ class Jetpack_JSON_API_Plugins_Modify_Endpoint extends Jetpack_JSON_API_Plugins_ } protected function autoupdate_on() { - $autoupdate_plugins = Jetpack_Options::get_option( 'autoupdate_plugins', array() ); + $autoupdate_plugins = (array) get_site_option( 'auto_update_plugins', array() ); $autoupdate_plugins = array_unique( array_merge( $autoupdate_plugins, $this->plugins ) ); - Jetpack_Options::update_option( 'autoupdate_plugins', $autoupdate_plugins ); + update_site_option( 'auto_update_plugins', $autoupdate_plugins ); } protected function autoupdate_off() { - $autoupdate_plugins = Jetpack_Options::get_option( 'autoupdate_plugins', array() ); + $autoupdate_plugins = (array) get_site_option( 'auto_update_plugins', array() ); $autoupdate_plugins = array_diff( $autoupdate_plugins, $this->plugins ); - Jetpack_Options::update_option( 'autoupdate_plugins', $autoupdate_plugins ); + update_site_option( 'auto_update_plugins', $autoupdate_plugins ); } protected function autoupdate_translations_on() { @@ -248,6 +251,10 @@ class Jetpack_JSON_API_Plugins_Modify_Endpoint extends Jetpack_JSON_API_Plugins_ } protected function current_user_can( $capability, $plugin = null ) { + // If this endpoint accepts site based authentication and a blog token is used, skip capabilities check. + if ( $this->accepts_site_based_authentication() ) { + return true; + } if ( $plugin ) { return current_user_can( $capability, $plugin ); } @@ -292,6 +299,7 @@ class Jetpack_JSON_API_Plugins_Modify_Endpoint extends Jetpack_JSON_API_Plugins_ } protected function update() { + $query_args = $this->query_args(); if ( isset( $query_args['autoupdate'] ) && $query_args['autoupdate'] ) { Constants::set_constant( 'JETPACK_PLUGIN_AUTOUPDATE', true ); @@ -318,6 +326,12 @@ class Jetpack_JSON_API_Plugins_Modify_Endpoint extends Jetpack_JSON_API_Plugins_ remove_action( 'upgrader_process_complete', 'wp_version_check' ); remove_action( 'upgrader_process_complete', 'wp_update_themes' ); + // Early return if unable to obtain auto_updater lock. + // @see https://github.com/WordPress/wordpress-develop/blob/66469efa99e7978c8824e287834135aa9842e84f/src/wp-admin/includes/class-wp-automatic-updater.php#L453. + if ( Constants::get_constant( 'JETPACK_PLUGIN_AUTOUPDATE' ) && ! WP_Upgrader::create_lock( 'auto_updater' ) ) { + return new WP_Error( 'update_fail', __( 'Updates are already in progress.', 'jetpack' ), 400 ); + } + $result = false; foreach ( $this->plugins as $plugin ) { @@ -327,6 +341,17 @@ class Jetpack_JSON_API_Plugins_Modify_Endpoint extends Jetpack_JSON_API_Plugins_ continue; } + // Rely on WP_Automatic_Updater class to check if a plugin item should be updated if it is a Jetpack autoupdate request. + if ( Constants::get_constant( 'JETPACK_PLUGIN_AUTOUPDATE' ) && ! ( new WP_Automatic_Updater() )->should_update( 'plugin', $update_plugins->response[ $plugin ], WP_PLUGIN_DIR ) ) { + continue; + } + + // Establish per plugin lock. + $plugin_slug = Jetpack_Autoupdate::get_plugin_slug( $plugin ); + if ( ! WP_Upgrader::create_lock( 'jetpack_' . $plugin_slug ) ) { + continue; + } + /** * Pre-upgrade action * @@ -351,11 +376,19 @@ class Jetpack_JSON_API_Plugins_Modify_Endpoint extends Jetpack_JSON_API_Plugins_ $errors = $upgrader->skin->get_errors(); $this->log[$plugin] = $upgrader->skin->get_upgrade_messages(); + // release individual plugin lock. + WP_Upgrader::release_lock( 'jetpack_' . $plugin_slug ); + if ( is_wp_error( $errors ) && $errors->get_error_code() ) { return $errors; } } + // release auto_udpate lock. + if ( Constants::get_constant( 'JETPACK_PLUGIN_AUTOUPDATE' ) ) { + WP_Upgrader::release_lock( 'auto_updater' ); + } + if ( ! $this->bulk && ! $result && $update_attempted ) { return new WP_Error( 'update_fail', __( 'There was an error updating your plugin', 'jetpack' ), 400 ); } diff --git a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-modify-v1-2-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-modify-v1-2-endpoint.php index 23940da0..11d9f101 100644 --- a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-modify-v1-2-endpoint.php +++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-modify-v1-2-endpoint.php @@ -1,66 +1,68 @@ <?php new Jetpack_JSON_API_Plugins_Modify_v1_2_Endpoint( array( - 'description' => 'Activate/Deactivate a Plugin on your Jetpack Site, or set automatic updates', - 'min_version' => '1.2', - 'method' => 'POST', - 'path' => '/sites/%s/plugins/%s', - 'stat' => 'plugins:1:modify', - 'path_labels' => array( + 'description' => 'Activate/Deactivate a Plugin on your Jetpack Site, or set automatic updates', + 'min_version' => '1.2', + 'method' => 'POST', + 'path' => '/sites/%s/plugins/%s', + 'stat' => 'plugins:1:modify', + 'path_labels' => array( '$site' => '(int|string) The site ID, The site domain', '$plugin' => '(string) The plugin ID', ), - 'request_format' => array( + 'request_format' => array( 'action' => '(string) Possible values are \'update\'', 'autoupdate' => '(bool) Whether or not to automatically update the plugin', 'active' => '(bool) Activate or deactivate the plugin', 'network_wide' => '(bool) Do action network wide (default value: false)', ), - 'query_parameters' => array( + 'query_parameters' => array( 'autoupdate' => '(bool=false) If the update is happening as a result of autoupdate event', ), - 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format_v1_2, - 'example_request_data' => array( + 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format_v1_2, + 'allow_jetpack_site_auth' => true, + 'example_request_data' => array( 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' + 'authorization' => 'Bearer YOUR_API_TOKEN', ), 'body' => array( 'action' => 'update', - ) + ), ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.2/sites/example.wordpress.org/plugins/hello-dolly%20hello' + 'example_request' => 'https://public-api.wordpress.com/rest/v1.2/sites/example.wordpress.org/plugins/hello-dolly%20hello', ) ); new Jetpack_JSON_API_Plugins_Modify_v1_2_Endpoint( array( - 'description' => 'Activate/Deactivate a list of plugins on your Jetpack Site, or set automatic updates', - 'min_version' => '1.2', - 'method' => 'POST', - 'path' => '/sites/%s/plugins', - 'stat' => 'plugins:modify', - 'path_labels' => array( + 'description' => 'Activate/Deactivate a list of plugins on your Jetpack Site, or set automatic updates', + 'min_version' => '1.2', + 'method' => 'POST', + 'path' => '/sites/%s/plugins', + 'stat' => 'plugins:modify', + 'path_labels' => array( '$site' => '(int|string) The site ID, The site domain', ), - 'request_format' => array( + 'request_format' => array( 'action' => '(string) Possible values are \'update\'', 'autoupdate' => '(bool) Whether or not to automatically update the plugin', 'active' => '(bool) Activate or deactivate the plugin', 'network_wide' => '(bool) Do action network wide (default value: false)', 'plugins' => '(array) A list of plugin ids to modify', ), - 'query_parameters' => array( + 'query_parameters' => array( 'autoupdate' => '(bool=false) If the update is happening as a result of autoupdate event', ), - 'response_format' => array( + 'response_format' => array( 'plugins' => '(array:plugin_v1_2) An array of plugin objects.', 'updated' => '(array) A list of plugin ids that were updated. Only present if action is update.', 'not_updated' => '(array) A list of plugin ids that were not updated. Only present if action is update.', 'log' => '(array) Update log. Only present if action is update.', ), - 'example_request_data' => array( + 'allow_jetpack_site_auth' => true, + 'example_request_data' => array( 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' + 'authorization' => 'Bearer YOUR_API_TOKEN', ), 'body' => array( 'active' => true, @@ -68,48 +70,58 @@ new Jetpack_JSON_API_Plugins_Modify_v1_2_Endpoint( 'jetpack/jetpack', 'akismet/akismet', ), - ) + ), ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.2/sites/example.wordpress.org/plugins' + 'example_request' => 'https://public-api.wordpress.com/rest/v1.2/sites/example.wordpress.org/plugins', ) ); new Jetpack_JSON_API_Plugins_Modify_v1_2_Endpoint( array( - 'description' => 'Update a Plugin on your Jetpack Site', - 'min_version' => '1.2', - 'method' => 'POST', - 'path' => '/sites/%s/plugins/%s/update/', - 'stat' => 'plugins:1:update', - 'path_labels' => array( + 'description' => 'Update a Plugin on your Jetpack Site', + 'min_version' => '1.2', + 'method' => 'POST', + 'path' => '/sites/%s/plugins/%s/update/', + 'stat' => 'plugins:1:update', + 'path_labels' => array( '$site' => '(int|string) The site ID, The site domain', '$plugin' => '(string) The plugin ID', ), - 'query_parameters' => array( + 'query_parameters' => array( 'autoupdate' => '(bool=false) If the update is happening as a result of autoupdate event', ), - 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format_v1_2, - 'example_request_data' => array( + 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format_v1_2, + 'allow_jetpack_site_auth' => true, + 'example_request_data' => array( 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' + 'authorization' => 'Bearer YOUR_API_TOKEN', ), ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.2/sites/example.wordpress.org/plugins/hello-dolly%20hello/update' + 'example_request' => 'https://public-api.wordpress.com/rest/v1.2/sites/example.wordpress.org/plugins/hello-dolly%20hello/update', ) ); class Jetpack_JSON_API_Plugins_Modify_v1_2_Endpoint extends Jetpack_JSON_API_Plugins_Modify_Endpoint { + /** + * Activate plugins. + * + * @return null|WP_Error null on success, WP_Error otherwise. + */ protected function activate() { $permission_error = false; $has_errors = false; foreach ( $this->plugins as $plugin ) { - if ( ! $this->current_user_can( 'activate_plugin', $plugin ) ) { - $this->log[$plugin]['error'] = __( 'Sorry, you are not allowed to activate this plugin.' ); - $has_errors = true; - $permission_error = true; - continue; + // If this endpoint accepts site based authentication and a blog token is used, skip capabilities check. + if ( ! $this->accepts_site_based_authentication() ) { + if ( ! $this->current_user_can( 'activate_plugin', $plugin ) ) { + $this->log[ $plugin ]['error'] = __( 'Sorry, you are not allowed to activate this plugin.', 'jetpack' ); + + $has_errors = true; + $permission_error = true; + continue; + } } if ( ( ! $this->network_wide && Jetpack::is_plugin_active( $plugin ) ) || is_plugin_active_for_network( $plugin ) ) { @@ -117,16 +129,18 @@ class Jetpack_JSON_API_Plugins_Modify_v1_2_Endpoint extends Jetpack_JSON_API_Plu } if ( ! $this->network_wide && is_network_only_plugin( $plugin ) && is_multisite() ) { - $this->log[$plugin]['error'] = __( 'Plugin can only be Network Activated', 'jetpack' ); - $has_errors = true; + $this->log[ $plugin ]['error'] = __( 'Plugin can only be Network Activated', 'jetpack' ); + + $has_errors = true; continue; } $result = activate_plugin( $plugin, '', $this->network_wide ); if ( is_wp_error( $result ) ) { - $this->log[$plugin]['error'] = $result->get_error_messages(); - $has_errors = true; + $this->log[ $plugin ]['error'] = $result->get_error_messages(); + + $has_errors = true; continue; } @@ -136,31 +150,41 @@ class Jetpack_JSON_API_Plugins_Modify_v1_2_Endpoint extends Jetpack_JSON_API_Plu } if ( ! $success ) { - $this->log[$plugin]['error'] = $result->get_error_messages; - $has_errors = true; + $this->log[ $plugin ]['error'] = $result->get_error_messages; + + $has_errors = true; continue; } - $this->log[$plugin][] = __( 'Plugin activated.', 'jetpack' ); + $this->log[ $plugin ][] = __( 'Plugin activated.', 'jetpack' ); } if ( ! $this->bulk && $has_errors ) { $plugin = $this->plugins[0]; if ( $permission_error ) { - return new WP_Error( 'unauthorized_error', $this->log[$plugin]['error'], 403 ); + return new WP_Error( 'unauthorized_error', $this->log[ $plugin ]['error'], 403 ); } - return new WP_Error( 'activation_error', $this->log[$plugin]['error'] ); + return new WP_Error( 'activation_error', $this->log[ $plugin ]['error'] ); } } - + /** + * Deactivate plugins. + * + * @return null|WP_Error null on success, WP_Error otherwise. + */ protected function deactivate() { $permission_error = false; foreach ( $this->plugins as $plugin ) { - if ( ! $this->current_user_can( 'deactivate_plugin', $plugin ) ) { - $error = $this->log[$plugin]['error'] = __( 'Sorry, you are not allowed to deactivate this plugin.', 'jetpack' ); - $permission_error = true; - continue; + // If this endpoint accepts site based authentication and a blog token is used, skip capabilities check. + if ( ! $this->accepts_site_based_authentication() ) { + if ( ! $this->current_user_can( 'deactivate_plugin', $plugin ) ) { + $error = __( 'Sorry, you are not allowed to deactivate this plugin.', 'jetpack' ); + + $this->log[ $plugin ]['error'] = $error; + $permission_error = true; + continue; + } } if ( ! Jetpack::is_plugin_active( $plugin ) ) { @@ -175,10 +199,12 @@ class Jetpack_JSON_API_Plugins_Modify_v1_2_Endpoint extends Jetpack_JSON_API_Plu } if ( ! $success ) { - $error = $this->log[$plugin]['error'] = __( 'There was an error deactivating your plugin', 'jetpack' ); + $error = __( 'There was an error deactivating your plugin', 'jetpack' ); + + $this->log[ $plugin ]['error'] = $error; continue; } - $this->log[$plugin][] = __( 'Plugin deactivated.', 'jetpack' ); + $this->log[ $plugin ][] = __( 'Plugin deactivated.', 'jetpack' ); } if ( ! $this->bulk && isset( $error ) ) { if ( $permission_error ) { diff --git a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-new-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-new-endpoint.php index 286a625b..3a16b1b0 100644 --- a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-new-endpoint.php +++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-new-endpoint.php @@ -7,51 +7,53 @@ include_once ABSPATH . 'wp-admin/includes/file.php'; // POST /sites/%s/plugins/new new Jetpack_JSON_API_Plugins_New_Endpoint( array( - 'description' => 'Install a plugin to a Jetpack site by uploading a zip file', - 'group' => '__do_not_document', - 'stat' => 'plugins:new', - 'min_version' => '1', - 'max_version' => '1.1', - 'method' => 'POST', - 'path' => '/sites/%s/plugins/new', - 'path_labels' => array( + 'description' => 'Install a plugin to a Jetpack site by uploading a zip file', + 'group' => '__do_not_document', + 'stat' => 'plugins:new', + 'min_version' => '1', + 'max_version' => '1.1', + 'method' => 'POST', + 'path' => '/sites/%s/plugins/new', + 'path_labels' => array( '$site' => '(int|string) Site ID or domain', ), - 'request_format' => array( + 'request_format' => array( 'zip' => '(zip) Plugin package zip file. multipart/form-data encoded. ', ), - 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format, - 'example_request_data' => array( + 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format, + 'allow_jetpack_site_auth' => true, + 'example_request_data' => array( 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' + 'authorization' => 'Bearer YOUR_API_TOKEN', ), ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/new' + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/plugins/new', ) ); new Jetpack_JSON_API_Plugins_New_Endpoint( array( - 'description' => 'Install a plugin to a Jetpack site by uploading a zip file', - 'group' => '__do_not_document', - 'stat' => 'plugins:new', - 'min_version' => '1.2', - 'method' => 'POST', - 'path' => '/sites/%s/plugins/new', - 'path_labels' => array( + 'description' => 'Install a plugin to a Jetpack site by uploading a zip file', + 'group' => '__do_not_document', + 'stat' => 'plugins:new', + 'min_version' => '1.2', + 'method' => 'POST', + 'path' => '/sites/%s/plugins/new', + 'path_labels' => array( '$site' => '(int|string) Site ID or domain', ), - 'request_format' => array( + 'request_format' => array( 'zip' => '(zip) Plugin package zip file. multipart/form-data encoded. ', ), - 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format_v1_2, - 'example_request_data' => array( + 'response_format' => Jetpack_JSON_API_Plugins_Endpoint::$_response_format_v1_2, + 'allow_jetpack_site_auth' => true, + 'example_request_data' => array( 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' + 'authorization' => 'Bearer YOUR_API_TOKEN', ), ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.2/sites/example.wordpress.org/plugins/new' + 'example_request' => 'https://public-api.wordpress.com/rest/v1.2/sites/example.wordpress.org/plugins/new', ) ); diff --git a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-sync-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-sync-endpoint.php index 98875ec0..94e7c790 100644 --- a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-sync-endpoint.php +++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-sync-endpoint.php @@ -1,6 +1,7 @@ <?php use Automattic\Jetpack\Sync\Actions; +use Automattic\Jetpack\Sync\Health; use Automattic\Jetpack\Sync\Modules; use Automattic\Jetpack\Sync\Queue; use Automattic\Jetpack\Sync\Queue_Buffer; @@ -10,6 +11,13 @@ use Automattic\Jetpack\Sync\Settings; // POST /sites/%s/sync class Jetpack_JSON_API_Sync_Endpoint extends Jetpack_JSON_API_Endpoint { + + /** + * This endpoint allows authentication both via a blog and a user token. + * If a user token is used, that user should have `manage_options` capability. + * + * @var array|string + */ protected $needed_capabilities = 'manage_options'; protected function validate_call( $_blog_id, $capability, $check_manage_active = true ) { @@ -67,6 +75,7 @@ class Jetpack_JSON_API_Sync_Status_Endpoint extends Jetpack_JSON_API_Sync_Endpoi // GET /sites/%s/data-check class Jetpack_JSON_API_Sync_Check_Endpoint extends Jetpack_JSON_API_Sync_Endpoint { protected function result() { + Actions::mark_sync_read_only(); $store = new Replicastore(); return $store->checksum_all(); } @@ -88,12 +97,62 @@ class Jetpack_JSON_API_Sync_Histogram_Endpoint extends Jetpack_JSON_API_Sync_End if ( ! isset( $args['strip_non_ascii'] ) ) { $args['strip_non_ascii'] = true; } - $histogram = $store->checksum_histogram( $args['object_type'], $args['buckets'], $args['start_id'], $args['end_id'], $columns, $args['strip_non_ascii'], $args['shared_salt'] ); + + /** + * Hack: nullify the values of `start_id` and `end_id` if we're only requesting ranges. + * + * The endpoint doesn't support nullable values :( + */ + if ( true === $args['only_range_edges'] ) { + if ( 0 === $args['start_id'] ) { + $args['start_id'] = null; + } + + if ( 0 === $args['end_id'] ) { + $args['end_id'] = null; + } + } + + $histogram = $store->checksum_histogram( $args['object_type'], $args['buckets'], $args['start_id'], $args['end_id'], $columns, $args['strip_non_ascii'], $args['shared_salt'], $args['only_range_edges'], $args['detailed_drilldown'] ); + + // Hack to disable Sync during this call, so we can resolve faster. + Actions::mark_sync_read_only(); return array( 'histogram' => $histogram, 'type' => $store->get_checksum_type() ); } } +// phpcs:disable Generic.Files.OneObjectStructurePerFile.MultipleFound +/** + * POST /sites/%s/sync/health + */ +class Jetpack_JSON_API_Sync_Modify_Health_Endpoint extends Jetpack_JSON_API_Sync_Endpoint { + + /** + * Callback for sync/health endpoint. + * + * @return array|WP_Error result of request. + */ + protected function result() { + $args = $this->input(); + + switch ( $args['status'] ) { + case Health::STATUS_IN_SYNC: + case Health::STATUS_OUT_OF_SYNC: + Health::update_status( $args['status'] ); + break; + default: + return new WP_Error( 'invalid_status', 'Invalid Sync Status Provided.' ); + } + + // re-fetch so we see what's really being stored. + return array( + 'success' => Health::get_status(), + ); + } +} +// phpcs:enable + // POST /sites/%s/sync/settings class Jetpack_JSON_API_Sync_Modify_Settings_Endpoint extends Jetpack_JSON_API_Sync_Endpoint { protected function result() { @@ -147,6 +206,7 @@ class Jetpack_JSON_API_Sync_Object extends Jetpack_JSON_API_Sync_Endpoint { $codec = Sender::get_instance()->get_codec(); + Actions::mark_sync_read_only(); Settings::set_is_syncing( true ); $objects = $codec->encode( $sync_module->get_objects_by_id( $object_type, $object_ids ) ); Settings::set_is_syncing( false ); @@ -249,7 +309,14 @@ class Jetpack_JSON_API_Sync_Checkout_Endpoint extends Jetpack_JSON_API_Sync_Endp } } - public function immediate_full_sync_pull( $number_of_items ) { + /** + * Check out a buffer of full sync actions. + * + * @param null $number_of_items Number of Actions to check-out. + * + * @return array Sync Actions to be returned to requestor + */ + public function immediate_full_sync_pull( $number_of_items = null ) { // try to give ourselves as much time as possible. set_time_limit( 0 ); @@ -294,6 +361,7 @@ class Jetpack_JSON_API_Sync_Checkout_Endpoint extends Jetpack_JSON_API_Sync_Endp class Jetpack_JSON_API_Sync_Close_Endpoint extends Jetpack_JSON_API_Sync_Endpoint { protected function result() { + $request_body = $this->input(); $queue_name = $this->validate_queue( $request_body['queue'] ); @@ -317,14 +385,29 @@ class Jetpack_JSON_API_Sync_Close_Endpoint extends Jetpack_JSON_API_Sync_Endpoin $items = $queue->peek_by_id( $request_body['item_ids'] ); - /** This action is documented in packages/sync/src/modules/Full_Sync.php */ - $full_sync_module = Modules::get_module( 'full-sync' ); + // Update Full Sync Status if queue is "full_sync". + if ( 'full_sync' === $queue_name ) { + $full_sync_module = Modules::get_module( 'full-sync' ); - $full_sync_module->update_sent_progress_action( $items ); + $full_sync_module->update_sent_progress_action( $items ); + } $buffer = new Queue_Buffer( $request_body['buffer_id'], $request_body['item_ids'] ); $response = $queue->close( $buffer, $request_body['item_ids'] ); + // Perform another checkout? + if ( isset( $request_body['continue'] ) && $request_body['continue'] ) { + if ( in_array( $queue_name, array( 'full_sync', 'immediate' ), true ) ) { + // Send Full Sync Actions. + Sender::get_instance()->do_full_sync(); + } else { + // Send Incremental Sync Actions. + if ( $queue->has_any_items() ) { + Sender::get_instance()->do_sync(); + } + } + } + if ( is_wp_error( $response ) ) { return $response; } @@ -337,7 +420,7 @@ class Jetpack_JSON_API_Sync_Close_Endpoint extends Jetpack_JSON_API_Sync_Endpoin protected static function sanitize_item_ids( $item ) { // lets not delete any options that don't start with jpsq_sync- - if ( substr( $item, 0, 5 ) !== 'jpsq_' ) { + if ( ! is_string( $item ) || substr( $item, 0, 5 ) !== 'jpsq_' ) { return null; } //Limit to A-Z,a-z,0-9,_,-,. diff --git a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-user-connect-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-user-connect-endpoint.php index 366f5ff7..b88d0406 100644 --- a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-user-connect-endpoint.php +++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-user-connect-endpoint.php @@ -1,6 +1,7 @@ <?php -use Automattic\Jetpack\Connection\Utils as Connection_Utils; +use Automattic\Jetpack\Connection\Manager as Connection_Manager; +use Automattic\Jetpack\Connection\Tokens; class Jetpack_JSON_API_User_Connect_Endpoint extends Jetpack_JSON_API_Endpoint { @@ -10,8 +11,8 @@ class Jetpack_JSON_API_User_Connect_Endpoint extends Jetpack_JSON_API_Endpoint { private $user_token; function result() { - Connection_Utils::update_user_token( $this->user_id, sprintf( '%s.%d', $this->user_token, $this->user_id ), false ); - return array( 'success' => Jetpack::is_user_connected( $this->user_id ) ); + ( new Tokens() )->update_user_token( $this->user_id, sprintf( '%s.%d', $this->user_token, $this->user_id ), false ); + return array( 'success' => ( new Connection_Manager( 'jetpack' ) )->is_user_connected( $this->user_id ) ); } function validate_input( $user_id ) { @@ -20,7 +21,7 @@ class Jetpack_JSON_API_User_Connect_Endpoint extends Jetpack_JSON_API_Endpoint { return new WP_Error( 'input_error', __( 'user_id is required', 'jetpack' ) ); } $this->user_id = $user_id; - if ( Jetpack::is_user_connected( $this->user_id ) ) { + if ( ( new Connection_Manager( 'jetpack' ) )->is_user_connected( $this->user_id ) ) { return new WP_Error( 'user_already_connected', __( 'The user is already connected', 'jetpack' ) ); } if ( ! isset( $input['user_token'] ) ) { diff --git a/plugins/jetpack/json-endpoints/jetpack/class.wpcom-json-api-get-option-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class.wpcom-json-api-get-option-endpoint.php index b261f202..16895cd4 100644 --- a/plugins/jetpack/json-endpoints/jetpack/class.wpcom-json-api-get-option-endpoint.php +++ b/plugins/jetpack/json-endpoints/jetpack/class.wpcom-json-api-get-option-endpoint.php @@ -3,7 +3,12 @@ use Automattic\Jetpack\Sync\Defaults; class WPCOM_JSON_API_Get_Option_Endpoint extends Jetpack_JSON_API_Endpoint { - + /** + * This endpoint allows authentication both via a blog and a user token. + * If a user token is used, that user should have `manage_options` capability. + * + * @var array|string + */ protected $needed_capabilities = 'manage_options'; public $option_name; diff --git a/plugins/jetpack/json-endpoints/jetpack/json-api-jetpack-endpoints.php b/plugins/jetpack/json-endpoints/jetpack/json-api-jetpack-endpoints.php index 6f13e52c..f252fa75 100644 --- a/plugins/jetpack/json-endpoints/jetpack/json-api-jetpack-endpoints.php +++ b/plugins/jetpack/json-endpoints/jetpack/json-api-jetpack-endpoints.php @@ -8,218 +8,243 @@ require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-endpoint.php require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-themes-endpoint.php' ); require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-themes-active-endpoint.php' ); -new Jetpack_JSON_API_Themes_Active_Endpoint( array( - 'description' => 'Get the active theme of your blog', - 'stat' => 'themes:mine', - 'method' => 'GET', - 'path' => '/sites/%s/themes/mine', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain' - ), - 'response_format' => Jetpack_JSON_API_Themes_Endpoint::$_response_format, - 'example_request_data' => array( - 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' +new Jetpack_JSON_API_Themes_Active_Endpoint( + array( + 'description' => 'Get the active theme of your blog', + 'stat' => 'themes:mine', + 'method' => 'GET', + 'path' => '/sites/%s/themes/mine', + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', ), - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/themes/mine' -) ); + 'response_format' => Jetpack_JSON_API_Themes_Endpoint::$_response_format, + 'allow_jetpack_site_auth' => true, + 'example_request_data' => array( + 'headers' => array( + 'authorization' => 'Bearer YOUR_API_TOKEN', + ), + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/themes/mine', + ) +); -new Jetpack_JSON_API_Themes_Active_Endpoint( array( - 'description' => 'Change the active theme of your blog', - 'method' => 'POST', - 'path' => '/sites/%s/themes/mine', - 'stat' => 'themes:mine', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain' - ), - 'query_parameters' => array( - 'context' => false - ), - 'request_format' => array( - 'theme' => '(string) The ID of the theme that should be activated' - ), - 'response_format' => Jetpack_JSON_API_Themes_Endpoint::$_response_format, - 'example_request_data' => array( - 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' +new Jetpack_JSON_API_Themes_Active_Endpoint( + array( + 'description' => 'Change the active theme of your blog', + 'method' => 'POST', + 'path' => '/sites/%s/themes/mine', + 'stat' => 'themes:mine', + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', ), - 'body' => array( - 'theme' => 'twentytwelve' - ) - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/themes/mine' -) ); + 'query_parameters' => array( + 'context' => false, + ), + 'request_format' => array( + 'theme' => '(string) The ID of the theme that should be activated', + ), + 'response_format' => Jetpack_JSON_API_Themes_Endpoint::$_response_format, + 'allow_jetpack_site_auth' => true, + 'example_request_data' => array( + 'headers' => array( + 'authorization' => 'Bearer YOUR_API_TOKEN', + ), + 'body' => array( + 'theme' => 'twentytwelve', + ), + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/themes/mine', + ) +); require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-themes-list-endpoint.php' ); -new Jetpack_JSON_API_Themes_List_Endpoint( array( - 'description' => 'Get WordPress.com Themes allowed on your blog', - 'group' => '__do_not_document', - 'stat' => 'themes', - 'method' => 'GET', - 'path' => '/sites/%s/themes', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain' - ), - 'response_format' => array( - 'found' => '(int) The total number of themes found.', - 'themes' => '(array) An array of theme objects.', - ), - 'example_request_data' => array( - 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' +new Jetpack_JSON_API_Themes_List_Endpoint( + array( + 'description' => 'Get WordPress.com Themes allowed on your blog', + 'group' => '__do_not_document', + 'stat' => 'themes', + 'method' => 'GET', + 'path' => '/sites/%s/themes', + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', ), - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/themes' -) ); + 'response_format' => array( + 'found' => '(int) The total number of themes found.', + 'themes' => '(array) An array of theme objects.', + ), + 'allow_jetpack_site_auth' => true, + 'example_request_data' => array( + 'headers' => array( + 'authorization' => 'Bearer YOUR_API_TOKEN', + ), + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/themes', + ) +); require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-themes-get-endpoint.php' ); require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-themes-new-endpoint.php' ); // POST /sites/%s/themes/%new -new Jetpack_JSON_API_Themes_New_Endpoint( array( - 'description' => 'Install a theme to your jetpack blog', - 'group' => '__do_not_document', - 'stat' => 'themes:new', - 'method' => 'POST', - 'path' => '/sites/%s/themes/new', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain', - ), - 'request_format' => array( - 'zip' => '(zip) Theme package zip file. multipart/form-data encoded. ', - ), - 'response_format' => Jetpack_JSON_API_Themes_Endpoint::$_response_format, - 'example_request_data' => array( - 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' +new Jetpack_JSON_API_Themes_New_Endpoint( + array( + 'description' => 'Install a theme to your jetpack blog', + 'group' => '__do_not_document', + 'stat' => 'themes:new', + 'method' => 'POST', + 'path' => '/sites/%s/themes/new', + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', ), - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/themes/new' -) ); - - + 'request_format' => array( + 'zip' => '(zip) Theme package zip file. multipart/form-data encoded. ', + ), + 'response_format' => Jetpack_JSON_API_Themes_Endpoint::$_response_format, + 'allow_jetpack_site_auth' => true, + 'example_request_data' => array( + 'headers' => array( + 'authorization' => 'Bearer YOUR_API_TOKEN', + ), + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/themes/new', + ) +); -new Jetpack_JSON_API_Themes_Get_Endpoint( array( - 'description' => 'Get a single theme on a jetpack blog', - 'group' => '__do_not_document', - 'stat' => 'themes:get:1', - 'method' => 'GET', - 'path' => '/sites/%s/themes/%s', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain', - '$theme' => '(string) The theme slug', - ), - 'response_format' => Jetpack_JSON_API_Themes_Endpoint::$_response_format, - 'example_request_data' => array( - 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' +new Jetpack_JSON_API_Themes_Get_Endpoint( + array( + 'description' => 'Get a single theme on a jetpack blog', + 'group' => '__do_not_document', + 'stat' => 'themes:get:1', + 'method' => 'GET', + 'path' => '/sites/%s/themes/%s', + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', + '$theme' => '(string) The theme slug', ), - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/themes/twentyfourteen' -) ); + 'response_format' => Jetpack_JSON_API_Themes_Endpoint::$_response_format, + 'allow_jetpack_site_auth' => true, + 'example_request_data' => array( + 'headers' => array( + 'authorization' => 'Bearer YOUR_API_TOKEN', + ), + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/themes/twentyfourteen', + ) +); require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-themes-modify-endpoint.php' ); -new Jetpack_JSON_API_Themes_Modify_Endpoint( array( - 'description' => 'Modify a single theme on a jetpack blog', - 'group' => '__do_not_document', - 'stat' => 'themes:modify:1', - 'method' => 'POST', - 'path' => '/sites/%s/themes/%s', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain', - '$theme' => '(string) The theme slug', - ), - 'request_format' => array( - 'action' => '(string) Only possible value is \'update\'. More to follow.', - 'autoupdate' => '(bool) Whether or not to automatically update the theme.', - ), - 'response_format' => Jetpack_JSON_API_Themes_Endpoint::$_response_format, - 'example_request_data' => array( - 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' +new Jetpack_JSON_API_Themes_Modify_Endpoint( + array( + 'description' => 'Modify a single theme on a jetpack blog', + 'group' => '__do_not_document', + 'stat' => 'themes:modify:1', + 'method' => 'POST', + 'path' => '/sites/%s/themes/%s', + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', + '$theme' => '(string) The theme slug', ), - 'body' => array( - 'action' => 'update', - ) - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/themes/twentyfourteen' -) ); + 'request_format' => array( + 'action' => '(string) Only possible value is \'update\'. More to follow.', + 'autoupdate' => '(bool) Whether or not to automatically update the theme.', + ), + 'response_format' => Jetpack_JSON_API_Themes_Endpoint::$_response_format, + 'allow_jetpack_site_auth' => true, + 'example_request_data' => array( + 'headers' => array( + 'authorization' => 'Bearer YOUR_API_TOKEN', + ), + 'body' => array( + 'action' => 'update', + ), + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/themes/twentyfourteen', + ) +); -new Jetpack_JSON_API_Themes_Modify_Endpoint( array( - 'description' => 'Modify a list of themes on a jetpack blog', - 'group' => '__do_not_document', - 'stat' => 'themes:modify', - 'method' => 'POST', - 'path' => '/sites/%s/themes', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain', - ), - 'request_format' => array( - 'action' => '(string) Only possible value is \'update\'. More to follow.', - 'autoupdate' => '(bool) Whether or not to automatically update the theme.', - 'themes' => '(array) A list of theme slugs', - ), - 'response_format' => array( - 'themes' => '(array:theme) A list of theme objects', - ), - 'example_request_data' => array( - 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' +new Jetpack_JSON_API_Themes_Modify_Endpoint( + array( + 'description' => 'Modify a list of themes on a jetpack blog', + 'group' => '__do_not_document', + 'stat' => 'themes:modify', + 'method' => 'POST', + 'path' => '/sites/%s/themes', + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', ), - 'body' => array( - 'action' => 'autoupdate_on', - 'themes' => array( - 'twentytwelve', - 'twentyfourteen', + 'request_format' => array( + 'action' => '(string) Only possible value is \'update\'. More to follow.', + 'autoupdate' => '(bool) Whether or not to automatically update the theme.', + 'themes' => '(array) A list of theme slugs', + ), + 'response_format' => array( + 'themes' => '(array:theme) A list of theme objects', + ), + 'allow_jetpack_site_auth' => true, + 'example_request_data' => array( + 'headers' => array( + 'authorization' => 'Bearer YOUR_API_TOKEN', ), - ) - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/themes' -) ); + 'body' => array( + 'action' => 'autoupdate_on', + 'themes' => array( + 'twentytwelve', + 'twentyfourteen', + ), + ), + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/themes', + ) +); require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-themes-install-endpoint.php' ); // POST /sites/%s/themes/%s/install -new Jetpack_JSON_API_Themes_Install_Endpoint( array( - 'description' => 'Install a theme to your jetpack blog', - 'group' => '__do_not_document', - 'stat' => 'themes:1:install', - 'method' => 'POST', - 'path' => '/sites/%s/themes/%s/install', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain', - '$theme' => '(int|string) The theme slug to install', - ), - 'response_format' => Jetpack_JSON_API_Themes_Endpoint::$_response_format, - 'example_request_data' => array( - 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' +new Jetpack_JSON_API_Themes_Install_Endpoint( + array( + 'description' => 'Install a theme to your jetpack blog', + 'group' => '__do_not_document', + 'stat' => 'themes:1:install', + 'method' => 'POST', + 'path' => '/sites/%s/themes/%s/install', + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', + '$theme' => '(int|string) The theme slug to install', ), - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/themes/twentyfourteen/install' -) ); + 'response_format' => Jetpack_JSON_API_Themes_Endpoint::$_response_format, + 'allow_jetpack_site_auth' => true, + 'example_request_data' => array( + 'headers' => array( + 'authorization' => 'Bearer YOUR_API_TOKEN', + ), + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/themes/twentyfourteen/install', + ) +); require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-themes-delete-endpoint.php' ); // POST /sites/%s/themes/%s/delete -new Jetpack_JSON_API_Themes_Delete_Endpoint( array( - 'description' => 'Delete/Uninstall a theme from your jetpack blog', - 'group' => '__do_not_document', - 'stat' => 'themes:1:delete', - 'method' => 'POST', - 'path' => '/sites/%s/themes/%s/delete', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain', - '$theme' => '(string) The slug of the theme to delete', - ), - 'response_format' => Jetpack_JSON_API_Themes_Endpoint::$_response_format, - 'example_request_data' => array( - 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' +new Jetpack_JSON_API_Themes_Delete_Endpoint( + array( + 'description' => 'Delete/Uninstall a theme from your jetpack blog', + 'group' => '__do_not_document', + 'stat' => 'themes:1:delete', + 'method' => 'POST', + 'path' => '/sites/%s/themes/%s/delete', + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', + '$theme' => '(string) The slug of the theme to delete', ), - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/themes/twentyfourteen/delete' -) ); + 'response_format' => Jetpack_JSON_API_Themes_Endpoint::$_response_format, + 'allow_jetpack_site_auth' => true, + 'example_request_data' => array( + 'headers' => array( + 'authorization' => 'Bearer YOUR_API_TOKEN', + ), + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/themes/twentyfourteen/delete', + ) +); // PLUGINS @@ -238,71 +263,107 @@ require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-plugins-modi require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-modules-endpoint.php' ); require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-modules-get-endpoint.php' ); -new Jetpack_JSON_API_Modules_Get_Endpoint( array( - 'description' => 'Get the info about a Jetpack Module on your Jetpack Site', - 'method' => 'GET', - 'path' => '/sites/%s/jetpack/modules/%s/', - 'stat' => 'jetpack:modules:1', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain', - '$module' => '(string) The module name', - ), - 'response_format' => Jetpack_JSON_API_Modules_Endpoint::$_response_format, - 'example_request_data' => array( - 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' +new Jetpack_JSON_API_Modules_Get_Endpoint( + array( + 'description' => 'Get the info about a Jetpack Module on your Jetpack Site', + 'method' => 'GET', + 'path' => '/sites/%s/jetpack/modules/%s/', + 'stat' => 'jetpack:modules:1', + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', + '$module' => '(string) The module name', ), - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/jetpack/modules/stats' -) ); + 'response_format' => Jetpack_JSON_API_Modules_Endpoint::$_response_format, + 'allow_jetpack_site_auth' => true, + 'example_request_data' => array( + 'headers' => array( + 'authorization' => 'Bearer YOUR_API_TOKEN', + ), + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/jetpack/modules/stats', + ) +); require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-modules-modify-endpoint.php' ); -new Jetpack_JSON_API_Modules_Modify_Endpoint( array( - 'description' => 'Modify the status of a Jetpack Module on your Jetpack Site', - 'method' => 'POST', - 'path' => '/sites/%s/jetpack/modules/%s/', - 'stat' => 'jetpack:modules:1', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain', - '$module' => '(string) The module name', - ), - 'request_format' => array( - 'active' => '(bool) The module activation status', - ), - 'response_format' => Jetpack_JSON_API_Modules_Endpoint::$_response_format, - 'example_request_data' => array( - 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' +new Jetpack_JSON_API_Modules_Modify_Endpoint( + array( + 'description' => 'Modify the status of a Jetpack Module on your Jetpack Site', + 'method' => 'POST', + 'path' => '/sites/%s/jetpack/modules/%s/', + 'stat' => 'jetpack:modules:1', + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', + '$module' => '(string) The module name', ), - 'body' => array( - 'active' => true, - ) - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/jetpack/modules/stats' -) ); + 'request_format' => array( + 'active' => '(bool) The module activation status', + ), + 'response_format' => Jetpack_JSON_API_Modules_Endpoint::$_response_format, + 'allow_jetpack_site_auth' => true, + 'example_request_data' => array( + 'headers' => array( + 'authorization' => 'Bearer YOUR_API_TOKEN', + ), + 'body' => array( + 'active' => true, + ), + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/jetpack/modules/stats', + ) +); require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-modules-list-endpoint.php' ); -new Jetpack_JSON_API_Modules_List_Endpoint( array( - 'description' => 'Get the list of available Jetpack modules on your site', - 'method' => 'GET', - 'path' => '/sites/%s/jetpack/modules', - 'stat' => 'jetpack:modules', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain' - ), - 'response_format' => array( - 'found' => '(int) The total number of modules found.', - 'modules' => '(array) An array of module objects.', - ), - 'example_request_data' => array( - 'headers' => array( - 'authorization' => 'Bearer YOUR_API_TOKEN' +new Jetpack_JSON_API_Modules_List_Endpoint( + array( + 'description' => 'Get the list of available Jetpack modules on your site', + 'method' => 'GET', + 'path' => '/sites/%s/jetpack/modules', + 'stat' => 'jetpack:modules', + 'min_version' => '1', + 'max_version' => '1.1', + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', ), - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/jetpack/modules' -) ); + 'response_format' => array( + 'found' => '(int) The total number of modules found.', + 'modules' => '(array) An array of module objects.', + ), + 'allow_jetpack_site_auth' => true, + 'example_request_data' => array( + 'headers' => array( + 'authorization' => 'Bearer YOUR_API_TOKEN', + ), + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/jetpack/modules', + ) +); + +require_once $json_jetpack_endpoints_dir . 'class-jetpack-json-api-modules-list-v1-2-endpoint.php'; + +new Jetpack_JSON_API_Modules_List_V1_2_Endpoint( + array( + 'description' => 'Get the list of available Jetpack modules on your site', + 'method' => 'GET', + 'path' => '/sites/%s/jetpack/modules', + 'stat' => 'jetpack:modules', + 'min_version' => '1.2', + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', + ), + 'response_format' => array( + 'modules' => '(array) An array of module objects.', + ), + 'allow_jetpack_site_auth' => true, + 'example_request_data' => array( + 'headers' => array( + 'authorization' => 'Bearer YOUR_API_TOKEN', + ), + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1.2/sites/example.wordpress.org/jetpack/modules', + ) +); require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-updates-status-endpoint.php' ); @@ -434,40 +495,44 @@ new Jetpack_JSON_API_Core_Endpoint( array( require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-sync-endpoint.php' ); // POST /sites/%s/sync -new Jetpack_JSON_API_Sync_Endpoint( array( - 'description' => 'Force sync of all options and constants', - 'method' => 'POST', - 'path' => '/sites/%s/sync', - 'stat' => 'sync', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain' - ), - 'request_format' => array( - 'modules' => '(string) Comma-delimited set of sync modules to use (default: all of them)', - 'posts' => '(string) Comma-delimited list of post IDs to sync', - 'comments' => '(string) Comma-delimited list of comment IDs to sync', - 'users' => '(string) Comma-delimited list of user IDs to sync', - ), - 'response_format' => array( - 'scheduled' => '(bool) Whether or not the synchronisation was started' - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/sync' -) ); +new Jetpack_JSON_API_Sync_Endpoint( + array( + 'description' => 'Force sync of all options and constants', + 'method' => 'POST', + 'path' => '/sites/%s/sync', + 'stat' => 'sync', + 'allow_jetpack_site_auth' => true, + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', + ), + 'request_format' => array( + 'modules' => '(string) Comma-delimited set of sync modules to use (default: all of them)', + 'posts' => '(string) Comma-delimited list of post IDs to sync', + 'comments' => '(string) Comma-delimited list of comment IDs to sync', + 'users' => '(string) Comma-delimited list of user IDs to sync', + ), + 'response_format' => array( + 'scheduled' => '(bool) Whether or not the synchronisation was started', + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/sync', + ) +); // GET /sites/%s/sync/status new Jetpack_JSON_API_Sync_Status_Endpoint( array( - 'description' => 'Status of the current full sync or the previous full sync', - 'method' => 'GET', - 'path' => '/sites/%s/sync/status', - 'stat' => 'sync-status', - 'path_labels' => array( + 'description' => 'Status of the current full sync or the previous full sync', + 'method' => 'GET', + 'path' => '/sites/%s/sync/status', + 'stat' => 'sync-status', + 'allow_jetpack_site_auth' => true, + 'path_labels' => array( '$site' => '(int|string) The site ID, The site domain', ), - 'query_parameters' => array( + 'query_parameters' => array( 'fields' => '(string|null) List of comma-separated fields to return (see `response_format`).', ), - 'response_format' => array( + 'response_format' => array( 'posts_checksum' => '(string|null) Posts checksum. Needs to be requested using the filter parameter.', 'comments_checksum' => '(string|null) Comments checksum. Needs to be requested using the filter parameter.', 'post_meta_checksum' => '(string|null) Post Meta checksum. Needs to be requested using the filter parameter.', @@ -489,54 +554,85 @@ new Jetpack_JSON_API_Sync_Status_Endpoint( 'cron_size' => '(int) Size of the current cron array', 'next_cron' => '(int) The number of seconds till the next item in cron.', 'progress' => '(array) Full Sync status by module', + 'debug_details' => '(array) Details as to why Sync is disabled.', ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/sync/status', + 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/sync/status', ) ); // GET /sites/%s/data-checksums -new Jetpack_JSON_API_Sync_Check_Endpoint( array( - 'description' => 'Check that cacheable data on the site is in sync with wordpress.com', - 'group' => '__do_not_document', - 'method' => 'GET', - 'path' => '/sites/%s/data-checksums', - 'stat' => 'data-checksums', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain' - ), - 'response_format' => array( - 'posts' => '(string) Posts checksum', - 'comments' => '(string) Comments checksum', - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/data-checksums' -) ); +new Jetpack_JSON_API_Sync_Check_Endpoint( + array( + 'description' => 'Check that cacheable data on the site is in sync with wordpress.com', + 'group' => '__do_not_document', + 'method' => 'GET', + 'path' => '/sites/%s/data-checksums', + 'stat' => 'data-checksums', + 'allow_jetpack_site_auth' => true, + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', + ), + 'response_format' => array( + 'posts' => '(string) Posts checksum', + 'comments' => '(string) Comments checksum', + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/data-checksums', + ) +); // GET /sites/%s/data-histogram -new Jetpack_JSON_API_Sync_Histogram_Endpoint( array( - 'description' => 'Get a histogram of checksums for certain synced data', - 'group' => '__do_not_document', - 'method' => 'GET', - 'path' => '/sites/%s/data-histogram', - 'stat' => 'data-histogram', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain' - ), - 'query_parameters' => array( - 'object_type' => '(string=posts) The type of object to checksum - posts, comments or options', - 'buckets' => '(int=10) The number of buckets for the checksums', - 'start_id' => '(int=0) Starting ID for the range', - 'end_id' => '(int=null) Ending ID for the range', - 'columns' => '(string) Columns to checksum', - 'strip_non_ascii' => '(bool=true) Strip non-ascii characters from all columns', - 'shared_salt' => '(string) Salt to reduce the collision and improve validation', - ), - 'response_format' => array( - 'histogram' => '(array) Associative array of histograms by ID range, e.g. "500-999" => "abcd1234"', - 'type' => '(string) Type of checksum algorithm', - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/data-histogram' -) ); +new Jetpack_JSON_API_Sync_Histogram_Endpoint( + array( + 'description' => 'Get a histogram of checksums for certain synced data', + 'group' => '__do_not_document', + 'method' => 'GET', + 'path' => '/sites/%s/data-histogram', + 'stat' => 'data-histogram', + 'allow_jetpack_site_auth' => true, + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', + ), + 'query_parameters' => array( + 'object_type' => '(string=posts) The type of object to checksum - posts, comments or options', + 'buckets' => '(int=10) The number of buckets for the checksums', + 'start_id' => '(int=0) Starting ID for the range', + 'end_id' => '(int=null) Ending ID for the range', + 'columns' => '(string) Columns to checksum', + 'strip_non_ascii' => '(bool=true) Strip non-ascii characters from all columns', + 'shared_salt' => '(string) Salt to reduce the collision and improve validation', + 'only_range_edges' => '(bool=false) Only return the edges of the specified range', + 'detailed_drilldown' => '(bool=false) Return a detailed drilldown in `key => checksum` format', + ), + 'response_format' => array( + 'histogram' => '(array) Associative array of histograms by ID range, e.g. "500-999" => "abcd1234"', + 'type' => '(string) Type of checksum algorithm', + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/data-histogram', + ) +); + +// POST /sites/%s/sync/health . +new Jetpack_JSON_API_Sync_Modify_Health_Endpoint( + array( + 'description' => 'Update sync health', + 'method' => 'POST', + 'group' => '__do_not_document', + 'path' => '/sites/%s/sync/health', + 'stat' => 'write-sync-health', + 'allow_jetpack_site_auth' => true, + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', + ), + 'request_format' => array( + 'status' => '(string) Sync Health Status of site', + ), + 'response_format' => array( + 'response' => '(string) Current Sync Health ', + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/sync/health', + ) +); $sync_settings_response = array( 'dequeue_max_bytes' => '(int|bool=false) Maximum bytes to read from queue in a single request', @@ -551,6 +647,7 @@ $sync_settings_response = array( 'post_meta_whitelist' => '(array|string|bool=false) List of post meta to be included in sync. Send "empty" to unset.', 'comment_meta_whitelist' => '(array|string|bool=false) List of comment meta to be included in sync. Send "empty" to unset.', 'disable' => '(int|bool=false) Set to 1 or true to disable sync entirely.', + 'checksum_disable' => '(int|bool=false) Set to 1 or true to disable checksums entirely.', 'render_filtered_content' => '(int|bool=true) Set to 1 or true to render filtered content.', 'max_enqueue_full_sync' => '(int|bool=false) Maximum number of rows to enqueue during each full sync process', 'max_queue_size_full_sync' => '(int|bool=false) Maximum queue size that full sync is allowed to use', @@ -563,161 +660,186 @@ $sync_settings_response = array( ); // GET /sites/%s/sync/settings -new Jetpack_JSON_API_Sync_Get_Settings_Endpoint( array( - 'description' => 'Update sync settings', - 'method' => 'GET', - 'group' => '__do_not_document', - 'path' => '/sites/%s/sync/settings', - 'stat' => 'write-sync-settings', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain' - ), - 'response_format' => $sync_settings_response, - 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/sync/settings' -) ); +new Jetpack_JSON_API_Sync_Get_Settings_Endpoint( + array( + 'description' => 'Update sync settings', + 'method' => 'GET', + 'group' => '__do_not_document', + 'path' => '/sites/%s/sync/settings', + 'stat' => 'write-sync-settings', + 'allow_jetpack_site_auth' => true, + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', + ), + 'response_format' => $sync_settings_response, + 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/sync/settings', + ) +); // POST /sites/%s/sync/settings -new Jetpack_JSON_API_Sync_Modify_Settings_Endpoint( array( - 'description' => 'Update sync settings', - 'method' => 'POST', - 'group' => '__do_not_document', - 'path' => '/sites/%s/sync/settings', - 'stat' => 'write-sync-settings', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain' - ), - 'request_format' => $sync_settings_response, - 'response_format' => $sync_settings_response, - 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/sync/settings' -) ); +new Jetpack_JSON_API_Sync_Modify_Settings_Endpoint( + array( + 'description' => 'Update sync settings', + 'method' => 'POST', + 'group' => '__do_not_document', + 'path' => '/sites/%s/sync/settings', + 'stat' => 'write-sync-settings', + 'allow_jetpack_site_auth' => true, + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', + ), + 'request_format' => $sync_settings_response, + 'response_format' => $sync_settings_response, + 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/sync/settings', + ) +); // GET /sites/%s/sync/object -new Jetpack_JSON_API_Sync_Object( array( - 'description' => 'Get an object by ID from one of the sync modules, in the format it would be synced in', - 'group' => '__do_not_document', - 'method' => 'GET', - 'path' => '/sites/%s/sync/object', - 'stat' => 'sync-object', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain' - ), - 'query_parameters' => array( - 'module_name' => '(string) The sync module ID, e.g. "posts"', - 'object_type' => '(string) An identified for the object type, e.g. "post"', - 'object_ids' => '(array) The IDs of the objects', - ), - 'response_format' => array( - 'objects' => '(string) The encoded objects', - 'codec' => '(string) The codec used to encode the objects, deflate-json-array or simple' - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/sync/object?module_name=posts&object_type=post&object_ids[]=1&object_ids[]=2&object_ids[]=3' -) ); +new Jetpack_JSON_API_Sync_Object( + array( + 'description' => 'Get an object by ID from one of the sync modules, in the format it would be synced in', + 'group' => '__do_not_document', + 'method' => 'GET', + 'path' => '/sites/%s/sync/object', + 'stat' => 'sync-object', + 'allow_jetpack_site_auth' => true, + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', + ), + 'query_parameters' => array( + 'module_name' => '(string) The sync module ID, e.g. "posts"', + 'object_type' => '(string) An identified for the object type, e.g. "post"', + 'object_ids' => '(array) The IDs of the objects', + ), + 'response_format' => array( + 'objects' => '(string) The encoded objects', + 'codec' => '(string) The codec used to encode the objects, deflate-json-array or simple', + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/sync/object?module_name=posts&object_type=post&object_ids[]=1&object_ids[]=2&object_ids[]=3', + ) +); // POST /sites/%s/sync/now -new Jetpack_JSON_API_Sync_Now_Endpoint( array( - 'description' => 'Force immediate sync of top items on a queue', - 'method' => 'POST', - 'path' => '/sites/%s/sync/now', - 'stat' => 'sync-now', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain' - ), - 'request_format' => array( - 'queue' => '(string) sync or full_sync', - ), - 'response_format' => array( - 'response' => '(array) The response from the server' - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/sync/now?queue=full_sync' -) ); +new Jetpack_JSON_API_Sync_Now_Endpoint( + array( + 'description' => 'Force immediate sync of top items on a queue', + 'method' => 'POST', + 'path' => '/sites/%s/sync/now', + 'stat' => 'sync-now', + 'allow_jetpack_site_auth' => true, + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', + ), + 'request_format' => array( + 'queue' => '(string) sync or full_sync', + ), + 'response_format' => array( + 'response' => '(array) The response from the server', + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/sync/now?queue=full_sync', + ) +); // POST /sites/%s/sync/unlock -new Jetpack_JSON_API_Sync_Unlock_Endpoint( array( - 'description' => 'Unlock the queue in case it gets locked by a process.', - 'method' => 'POST', - 'path' => '/sites/%s/sync/unlock', - 'group' => '__do_not_document', - 'stat' => 'sync-unlock', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain' - ), - 'request_format' => array( - 'queue' => '(string) sync or full_sync', - ), - 'response_format' => array( - 'success' => '(bool) Unlocking the queue successful?' - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/sync/unlock' -) ); +new Jetpack_JSON_API_Sync_Unlock_Endpoint( + array( + 'description' => 'Unlock the queue in case it gets locked by a process.', + 'method' => 'POST', + 'path' => '/sites/%s/sync/unlock', + 'group' => '__do_not_document', + 'stat' => 'sync-unlock', + 'allow_jetpack_site_auth' => true, + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', + ), + 'request_format' => array( + 'queue' => '(string) sync or full_sync', + ), + 'response_format' => array( + 'success' => '(bool) Unlocking the queue successful?', + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/sync/unlock', + ) +); // GET /sites/%s/sync/object-id-range -new Jetpack_JSON_API_Sync_Object_Id_Range( array( - 'description' => 'Gets minimum and maximum object ids for each batch of given batch size.', - 'method' => 'GET', - 'path' => '/sites/%s/sync/object-id-range', - 'group' => '__do_not_document', - 'stat' => 'sync-object-id-range', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain' - ), - 'query_parameters' => array( - 'batch_size' => '(int=1000) The amount of objects per batch.', - 'sync_module' => '(string=posts) The sync module used to enumerate the ranges.', - ), - 'response_format' => array( - 'ranges' => '(array) An array of range objects with min and max properties for each batch.', - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/sync/object-id-range?batch_size=100&sync_module=comments' -) ); +new Jetpack_JSON_API_Sync_Object_Id_Range( + array( + 'description' => 'Gets minimum and maximum object ids for each batch of given batch size.', + 'method' => 'GET', + 'path' => '/sites/%s/sync/object-id-range', + 'group' => '__do_not_document', + 'stat' => 'sync-object-id-range', + 'allow_jetpack_site_auth' => true, + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', + ), + 'query_parameters' => array( + 'batch_size' => '(int=1000) The amount of objects per batch.', + 'sync_module' => '(string=posts) The sync module used to enumerate the ranges.', + ), + 'response_format' => array( + 'ranges' => '(array) An array of range objects with min and max properties for each batch.', + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/sync/object-id-range?batch_size=100&sync_module=comments', + ) +); // POST /sites/%s/sync/checkout -new Jetpack_JSON_API_Sync_Checkout_Endpoint( array( - 'description' => 'Locks the queue and returns items and the buffer ID.', - 'method' => 'POST', - 'path' => '/sites/%s/sync/checkout', - 'group' => '__do_not_document', - 'stat' => 'sync-checkout', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain' - ), - 'request_format' => array( - 'queue' => '(string) sync or full_sync', - 'number_of_items' => '(int=10) Maximum number of items from the queue to be returned', - 'encode' => '(bool=true) Use the default encode method', - 'force' => '(bool=false) Force unlock the queue', - 'pop' => '(bool=false) Pop from the queue without checkout, use carefully 😱', - ), - 'response_format' => array( - 'buffer_id' => '(string) Buffer ID that we are using', - 'items' => '(array) Items from the queue that are ready to be processed by the sync server', - 'skipped_items' => '(array) Skipped item ids', - 'codec' => '(string) The name of the codec used to encode the data', - 'sent_timestamp' => '(int) Current timestamp of the server', - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/sync/checkout' -) ); +new Jetpack_JSON_API_Sync_Checkout_Endpoint( + array( + 'description' => 'Locks the queue and returns items and the buffer ID.', + 'method' => 'POST', + 'path' => '/sites/%s/sync/checkout', + 'group' => '__do_not_document', + 'stat' => 'sync-checkout', + 'allow_jetpack_site_auth' => true, + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', + ), + 'request_format' => array( + 'queue' => '(string) sync or full_sync', + 'number_of_items' => '(int=10) Maximum number of items from the queue to be returned', + 'encode' => '(bool=true) Use the default encode method', + 'force' => '(bool=false) Force unlock the queue', + 'pop' => '(bool=false) Pop from the queue without checkout, use carefully 😱', + ), + 'response_format' => array( + 'buffer_id' => '(string) Buffer ID that we are using', + 'items' => '(array) Items from the queue that are ready to be processed by the sync server', + 'skipped_items' => '(array) Skipped item ids', + 'codec' => '(string) The name of the codec used to encode the data', + 'sent_timestamp' => '(int) Current timestamp of the server', + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/sync/checkout', + ) +); // POST /sites/%s/sync/close -new Jetpack_JSON_API_Sync_Close_Endpoint( array( - 'description' => 'Closes the buffer and delete the processed items from the queue.', - 'method' => 'POST', - 'path' => '/sites/%s/sync/close', - 'group' => '__do_not_document', - 'stat' => 'sync-close', - 'path_labels' => array( - '$site' => '(int|string) The site ID, The site domain' - ), - 'request_format' => array( - 'item_ids' => '(array) Item IDs to delete from the queue.', - 'queue' => '(string) sync or full_sync', - 'buffer_id' => '(string) buffer ID that was opened during the checkout step.', - ), - 'response_format' => array( - 'success' => '(bool) Closed the buffer successfully?' - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/sync/close' -) ); +new Jetpack_JSON_API_Sync_Close_Endpoint( + array( + 'description' => 'Closes the buffer and delete the processed items from the queue.', + 'method' => 'POST', + 'path' => '/sites/%s/sync/close', + 'group' => '__do_not_document', + 'stat' => 'sync-close', + 'allow_jetpack_site_auth' => true, + 'path_labels' => array( + '$site' => '(int|string) The site ID, The site domain', + ), + 'request_format' => array( + 'item_ids' => '(array) Item IDs to delete from the queue.', + 'queue' => '(string) sync or full_sync', + 'buffer_id' => '(string) buffer ID that was opened during the checkout step.', + 'continue' => '(bool=false) Perform another checkout from queue.', + ), + 'response_format' => array( + 'success' => '(bool) Closed the buffer successfully?', + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/example.wordpress.org/sync/close', + ) +); require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-log-endpoint.php' ); @@ -829,58 +951,64 @@ new Jetpack_JSON_API_Translations_Modify_Endpoint( array( // Options require_once( $json_jetpack_endpoints_dir . 'class.wpcom-json-api-get-option-endpoint.php' ); -new WPCOM_JSON_API_Get_Option_Endpoint( array ( - 'method' => 'GET', - 'description' => 'Fetches an option.', - 'group' => '__do_not_document', - 'stat' => 'option', - 'path' => '/sites/%s/option', - 'path_labels' => array( - '$site' => '(int|string) Site ID or domain', - ), - 'query_parameters' => array( - 'option_name' => '(string) The name of the option to fetch.', - 'site_option' => '(bool=false) True if the option is a site option.', - ), - 'response_format' => array( - 'option_value' => '(string|object) The value of the option.', - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/82974409/option?option_name=blogname', - 'example_request_data' => array( - 'headers' => array( 'authorization' => 'Bearer YOUR_API_TOKEN' ), - ), -) ); +new WPCOM_JSON_API_Get_Option_Endpoint( + array( + 'method' => 'GET', + 'description' => 'Fetches an option.', + 'group' => '__do_not_document', + 'stat' => 'option', + 'allow_jetpack_site_auth' => true, + 'path' => '/sites/%s/option', + 'path_labels' => array( + '$site' => '(int|string) Site ID or domain', + ), + 'query_parameters' => array( + 'option_name' => '(string) The name of the option to fetch.', + 'site_option' => '(bool=false) True if the option is a site option.', + ), + 'response_format' => array( + 'option_value' => '(string|object) The value of the option.', + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/82974409/option?option_name=blogname', + 'example_request_data' => array( + 'headers' => array( 'authorization' => 'Bearer YOUR_API_TOKEN' ), + ), + ) +); require_once( $json_jetpack_endpoints_dir . 'class.wpcom-json-api-update-option-endpoint.php' ); -new WPCOM_JSON_API_Update_Option_Endpoint( array ( - 'method' => 'POST', - 'description' => 'Updates an option.', - 'group' => '__do_not_document', - 'stat' => 'option:update', - 'path' => '/sites/%s/option', - 'path_labels' => array( - '$site' => '(int|string) Site ID or domain', - ), - 'query_parameters' => array( - 'option_name' => '(string) The name of the option to fetch.', - 'site_option' => '(bool=false) True if the option is a site option.', - 'is_array' => '(bool=false) True if the value should be converted to an array before saving.', - ), - 'request_format' => array( - 'option_value' => '(string|object) The new value of the option.', - ), - 'response_format' => array( - 'option_value' => '(string|object) The value of the updated option.', - ), - 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/82974409/option', - 'example_request_data' => array( - 'headers' => array( 'authorization' => 'Bearer YOUR_API_TOKEN' ), - 'body' => array( - 'option_value' => 'My new blog name' +new WPCOM_JSON_API_Update_Option_Endpoint( + array( + 'method' => 'POST', + 'description' => 'Updates an option.', + 'group' => '__do_not_document', + 'stat' => 'option:update', + 'allow_jetpack_site_auth' => true, + 'path' => '/sites/%s/option', + 'path_labels' => array( + '$site' => '(int|string) Site ID or domain', ), - ), -) ); + 'query_parameters' => array( + 'option_name' => '(string) The name of the option to fetch.', + 'site_option' => '(bool=false) True if the option is a site option.', + 'is_array' => '(bool=false) True if the value should be converted to an array before saving.', + ), + 'request_format' => array( + 'option_value' => '(string|object) The new value of the option.', + ), + 'response_format' => array( + 'option_value' => '(string|object) The value of the updated option.', + ), + 'example_request' => 'https://public-api.wordpress.com/rest/v1.1/sites/82974409/option', + 'example_request_data' => array( + 'headers' => array( 'authorization' => 'Bearer YOUR_API_TOKEN' ), + 'body' => array( + 'option_value' => 'My new blog name', + ), + ), + ) +); require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-cron-endpoint.php' ); |