summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony G. Basile <blueness@gentoo.org>2017-06-15 08:53:57 -0400
committerAnthony G. Basile <blueness@gentoo.org>2017-06-15 08:53:57 -0400
commit48822ba710570832bbc0ffb9b6c3470e25e7bf29 (patch)
tree70e349b7e03191c456033287e53593056249c962 /plugins/jetpack/json-endpoints
parentUpdate twentyfourteen 2.0 (diff)
downloadblogs-gentoo-48822ba710570832bbc0ffb9b6c3470e25e7bf29.tar.gz
blogs-gentoo-48822ba710570832bbc0ffb9b6c3470e25e7bf29.tar.bz2
blogs-gentoo-48822ba710570832bbc0ffb9b6c3470e25e7bf29.zip
Update jetpack 5.0
Signed-off-by: Anthony G. Basile <blueness@gentoo.org>
Diffstat (limited to 'plugins/jetpack/json-endpoints')
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-get-post-v1-1-endpoint.php8
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-get-site-endpoint.php54
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-get-site-v1-2-endpoint.php2
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-list-media-v1-1-endpoint.php1
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-list-media-v1-2-endpoint.php30
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-list-posts-endpoint.php17
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-list-posts-v1-1-endpoint.php35
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-list-posts-v1-2-endpoint.php382
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-list-roles-endpoint.php7
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-post-endpoint.php31
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-post-v1-1-endpoint.php13
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-publicize-endpoint.php181
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-site-settings-endpoint.php57
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-site-settings-v1-2-endpoint.php13
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-site-user-endpoint.php17
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-update-comment-endpoint.php10
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-update-post-endpoint.php21
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-update-post-v1-1-endpoint.php65
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-update-post-v1-2-endpoint.php59
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-update-site-homepage-endpoint.php45
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-update-site-logo-endpoint.php47
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-update-taxonomy-endpoint.php5
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-update-user-endpoint.php1
-rw-r--r--plugins/jetpack/json-endpoints/class.wpcom-json-api-upload-media-v1-1-endpoint.php116
-rw-r--r--plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-comment-backup-endpoint.php52
-rw-r--r--plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-option-backup-endpoint.php35
-rw-r--r--plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-post-backup-endpoint.php6
-rw-r--r--plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-term-backup-endpoint.php32
-rw-r--r--plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-user-backup-endpoint.php32
-rw-r--r--plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-endpoint.php2
-rw-r--r--plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-plugins-modify-endpoint.php2
-rw-r--r--plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-user-connect-endpoint.php31
-rw-r--r--plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-user-create-endpoint.php61
-rw-r--r--plugins/jetpack/json-endpoints/jetpack/json-api-jetpack-endpoints.php183
34 files changed, 1342 insertions, 311 deletions
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 6f79222a..6f3152cd 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
@@ -10,15 +10,17 @@ class WPCOM_JSON_API_Get_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_End
$args = $this->query_args();
+ $site = $this->get_platform()->get_site( $blog_id );
+
if ( false !== strpos( $path, '/posts/slug:' ) ) {
- $post_id = $this->get_platform()->get_site( $blog_id )->get_post_id_by_name( $post_id );
+ $post_id = $site->get_post_id_by_name( $post_id );
if ( is_wp_error( $post_id ) ) {
return $post_id;
}
}
if ( defined( 'IS_WPCOM' ) && IS_WPCOM &&
- ! in_array( get_post_type( $post_id ), array( false, 'post', 'page', 'revision' ) ) ) {
+ ! in_array( get_post_type( $post_id ), array( false, 'post', 'revision' ) ) ) {
$this->load_theme_functions();
}
@@ -28,7 +30,7 @@ class WPCOM_JSON_API_Get_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_End
return $return;
}
- if ( ! $this->current_user_can_access_post_type( $return['type'], $args['context'] ) ) {
+ if ( ! $site->current_user_can_access_post_type( $return['type'], $args['context'] ) ) {
return new WP_Error( 'unknown_post', 'Unknown post', 404 );
}
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 75ad1f3b..3ebd3bc1 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
@@ -25,6 +25,7 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint {
'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',
);
protected static $no_member_fields = array(
@@ -86,10 +87,14 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint {
'page_on_front',
'page_for_posts',
'headstart',
+ 'headstart_is_fresh',
'ak_vp_bundle_enabled',
- 'verification_services_codes',
Jetpack_SEO_Utils::FRONT_PAGE_META_OPTION,
Jetpack_SEO_Titles::TITLE_FORMATS_OPTION,
+ 'verification_services_codes',
+ 'podcasting_archive',
+ 'is_domain_only',
+ 'is_automated_transfer',
);
protected static $jetpack_response_field_additions = array(
@@ -103,7 +108,9 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint {
protected static $jetpack_response_option_additions = array(
'publicize_permanently_disabled',
- 'ak_vp_bundle_enabled'
+ 'ak_vp_bundle_enabled',
+ 'is_automated_transfer',
+ 'frame_nonce'
);
private $site;
@@ -174,13 +181,33 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint {
array_intersect( $default_fields, $this->fields_to_include ) :
$default_fields;
- if ( ! is_user_member_of_blog( get_current_user_id(), get_current_blog_id() ) ) {
+ if ( ! $this->has_blog_access( $this->api->token_details, $blog_id ) ) {
$response_keys = array_intersect( $response_keys, self::$no_member_fields );
}
return $this->render_response_keys( $response_keys );
}
+ private function has_blog_access( $token_details, $blog_id ) {
+ if ( is_user_member_of_blog( get_current_user_id(), $blog_id ) ) {
+ return true;
+ }
+
+ $token_details = (array) $token_details;
+ if ( ! isset( $token_details['access'], $token_details['auth'], $token_details['blog_id'] ) ) {
+ return false;
+ }
+
+ if (
+ 'jetpack' === $token_details['auth'] &&
+ 'blog' === $token_details['access'] &&
+ $blog_id === $token_details['blog_id']
+ ) {
+ return true;
+ }
+ return false;
+ }
+
private function render_response_keys( &$response_keys ) {
$response = array();
@@ -289,6 +316,9 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint {
case 'plan' :
$response[ $key ] = $this->site->get_plan();
break;
+ case 'quota' :
+ $response[ $key ] = $this->site->get_quota();
+ break;
}
do_action( 'post_render_site_response_key', $key );
@@ -304,7 +334,6 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint {
$custom_front_page = $site->is_custom_front_page();
-
foreach ( $options_response_keys as $key ) {
switch ( $key ) {
case 'timezone' :
@@ -429,6 +458,9 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint {
case 'headstart' :
$options[ $key ] = $site->is_headstart();
break;
+ case 'headstart_is_fresh' :
+ $options[ $key ] = $site->is_headstart_fresh();
+ break;
case 'ak_vp_bundle_enabled' :
$options[ $key ] = $site->get_ak_vp_bundle_enabled();
break;
@@ -441,6 +473,15 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint {
case 'verification_services_codes' :
$options[ $key ] = $site->get_verification_services_codes();
break;
+ case 'podcasting_archive':
+ $options[ $key ] = $site->get_podcasting_archive();
+ break;
+ case 'is_domain_only':
+ $options[ $key ] = $site->is_domain_only();
+ break;
+ case 'is_automated_transfer':
+ $options[ $key ] = $site->is_automated_transfer();
+ break;
}
}
@@ -469,6 +510,7 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint {
// apply any WPCOM-only response components to a Jetpack site response
public function decorate_jetpack_response( &$response ) {
$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;
@@ -479,8 +521,7 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint {
$response->{ $key } = $value;
}
- $token_details = (object) $this->api->token_details;
- if ( is_user_member_of_blog( get_current_user_id(), get_current_blog_id() ) || 'blog' === $token_details->access ) {
+ if ( $this->has_blog_access( $this->api->token_details, $response->ID ) ) {
$wpcom_member_response = $this->render_response_keys( self::$jetpack_response_field_member_additions );
foreach( $wpcom_member_response as $key => $value ) {
@@ -508,6 +549,7 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint {
}
}
+ restore_current_blog();
return $response; // possibly no need since it's modified in place
}
}
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 898df417..e705e0eb 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
@@ -1,4 +1,5 @@
<?php
+
class WPCOM_JSON_API_GET_Site_V1_2_Endpoint extends WPCOM_JSON_API_GET_Site_Endpoint {
public static $site_format = array(
@@ -24,6 +25,7 @@ class WPCOM_JSON_API_GET_Site_V1_2_Endpoint extends WPCOM_JSON_API_GET_Site_Endp
'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',
);
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 fc2e479a..fb910908 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
@@ -97,6 +97,7 @@ class WPCOM_JSON_API_List_Media_v1_1_Endpoint extends WPCOM_JSON_API_Endpoint {
}
$response = array();
+
foreach ( $media->posts as $item ) {
$response[] = $this->get_media_item_v1_1( $item->ID );
}
diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-media-v1-2-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-media-v1-2-endpoint.php
new file mode 100644
index 00000000..702129e6
--- /dev/null
+++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-media-v1-2-endpoint.php
@@ -0,0 +1,30 @@
+<?php
+
+jetpack_require_lib( 'class.media' );
+
+class WPCOM_JSON_API_List_Media_v1_2_Endpoint extends WPCOM_JSON_API_List_Media_v1_1_Endpoint {
+ function callback( $path = '', $blog_id = 0 ) {
+ $response = parent::callback( $path, $blog_id );
+
+ if ( is_wp_error( $response ) ) {
+ return $response;
+ }
+
+ $media_list = $response['media'];
+
+ if ( count( $media_list ) < 1 ) {
+ return $response;
+ }
+
+ foreach ( $media_list as $index => $media_item ) {
+ // expose `revision_history` object for each image
+ $media_item->revision_history = (object) array(
+ 'items' => (array) Media::get_revision_history( $media_item->ID ),
+ 'original' => (object) Media::get_original_media( $media_item->ID )
+ );
+ }
+
+ return $response;
+ }
+}
+
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 1ab369f0..db82ae9b 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
@@ -172,6 +172,23 @@ class WPCOM_JSON_API_List_Posts_Endpoint extends WPCOM_JSON_API_Post_Endpoint {
$query['tag'] = $args['tag'];
}
+ if ( ! empty( $args['term'] ) ) {
+ $query['tax_query'] = array();
+ foreach ( $args['term'] as $taxonomy => $slug ) {
+ $taxonomy_object = get_taxonomy( $taxonomy );
+ 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 )
+ );
+ }
+ }
+
if ( isset( $args['page'] ) ) {
if ( $args['page'] < 1 ) {
$args['page'] = 1;
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 61953a1f..c50ac926 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
@@ -21,6 +21,7 @@ class WPCOM_JSON_API_List_Posts_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_E
$args = $this->query_args();
$is_eligible_for_page_handle = true;
+ $site = $this->get_platform()->get_site( $blog_id );
if ( $args['number'] < 1 ) {
$args['number'] = 20;
@@ -28,7 +29,7 @@ class WPCOM_JSON_API_List_Posts_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_E
return new WP_Error( 'invalid_number', 'The NUMBER parameter must be less than or equal to 100.', 400 );
}
- if ( isset( $args['type'] ) && ! $this->is_post_type_allowed( $args['type'] ) ) {
+ if ( isset( $args['type'] ) && ! $site->is_post_type_allowed( $args['type'] ) ) {
return new WP_Error( 'unknown_post_type', 'Unknown post type', 404 );
}
@@ -37,7 +38,7 @@ class WPCOM_JSON_API_List_Posts_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_E
if ( version_compare( $this->api->version, '1.1', '<' ) ) {
$args['type'] = array( 'post', 'page' );
} else { // 1.1+
- $args['type'] = $this->_get_whitelisted_post_types();
+ $args['type'] = $site->get_whitelisted_post_types();
}
}
@@ -68,7 +69,7 @@ class WPCOM_JSON_API_List_Posts_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_E
}
if ( isset( $args['type'] ) &&
- ! in_array( $args['type'], array( 'post', 'page', 'revision', 'any' ) ) &&
+ ! in_array( $args['type'], array( 'post', 'revision', 'page', 'any' ) ) &&
defined( 'IS_WPCOM' ) && IS_WPCOM ) {
$this->load_theme_functions();
}
@@ -80,7 +81,7 @@ class WPCOM_JSON_API_List_Posts_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_E
if ( is_array( $args['type'] ) ) {
$allowed_types = array();
foreach ( $args['type'] as $post_type ) {
- if ( $this->current_user_can_access_post_type( $post_type, $args['context'] ) ) {
+ if ( $site->current_user_can_access_post_type( $post_type, $args['context'] ) ) {
$allowed_types[] = $post_type;
}
}
@@ -91,7 +92,7 @@ class WPCOM_JSON_API_List_Posts_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_E
$args['type'] = $allowed_types;
}
else {
- if ( ! $this->current_user_can_access_post_type( $args['type'], $args['context'] ) ) {
+ if ( ! $site->current_user_can_access_post_type( $args['type'], $args['context'] ) ) {
return array( 'found' => 0, 'posts' => array() );
}
}
@@ -183,6 +184,23 @@ class WPCOM_JSON_API_List_Posts_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_E
$query['tag'] = $args['tag'];
}
+ if ( ! empty( $args['term'] ) ) {
+ $query['tax_query'] = array();
+ foreach ( $args['term'] as $taxonomy => $slug ) {
+ $taxonomy_object = get_taxonomy( $taxonomy );
+ 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 )
+ );
+ }
+ }
+
if ( isset( $args['page'] ) ) {
if ( $args['page'] < 1 ) {
$args['page'] = 1;
@@ -311,6 +329,13 @@ class WPCOM_JSON_API_List_Posts_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_E
$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;
+ }
+
break;
}
}
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
new file mode 100644
index 00000000..664fd45f
--- /dev/null
+++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-posts-v1-2-endpoint.php
@@ -0,0 +1,382 @@
+<?php
+/*
+ * WARNING: This file is distributed verbatim in Jetpack.
+ * There should be nothing WordPress.com specific in this file.
+ *
+ * @hide-in-jetpack
+ */
+
+class WPCOM_JSON_API_List_Posts_v1_2_Endpoint extends WPCOM_JSON_API_List_Posts_v1_1_Endpoint {
+ // /sites/%s/posts/ -> $blog_id
+ 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;
+ }
+
+ $args = $this->query_args();
+ $is_eligible_for_page_handle = true;
+ $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 );
+ }
+
+ if ( isset( $args['type'] ) ) {
+ // load all types on WPCOM, unless only built-in ones are requested
+ if ( defined( 'IS_WPCOM' ) && IS_WPCOM && ! in_array( $args['type'], array( 'post', 'revision', 'page' ) ) ) {
+ $this->load_theme_functions();
+ }
+
+ if ( ! $site->is_post_type_allowed( $args['type'] ) ) {
+ return new WP_Error( 'unknown_post_type', 'Unknown post type', 404 );
+ }
+
+ // Normalize post_type
+ if ( 'any' == $args['type'] ) {
+ $whitelisted_post_types = $site->get_whitelisted_post_types();
+
+ 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 );
+ } else {
+ $args['type'] = $whitelisted_post_types;
+ }
+ }
+ } else {
+ // let's be explicit about defaulting to 'post'
+ $args['type'] = 'post';
+ }
+
+ // make sure the user can read or edit the requested post type(s)
+ if ( is_array( $args['type'] ) ) {
+ $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;
+ }
+ }
+
+ if ( empty( $allowed_types ) ) {
+ return array( 'found' => 0, 'posts' => array() );
+ }
+ $args['type'] = $allowed_types;
+ }
+ else {
+ if ( ! $site->current_user_can_access_post_type( $args['type'], $args['context'] ) ) {
+ return array( 'found' => 0, 'posts' => array() );
+ }
+ }
+
+ // determine statuses
+ $status = ( ! empty( $args['status'] ) ) ? explode( ',', $args['status'] ) : array( 'publish' );
+ if ( is_user_logged_in() ) {
+ $statuses_whitelist = array(
+ 'publish',
+ 'pending',
+ 'draft',
+ 'future',
+ 'private',
+ 'trash',
+ 'any',
+ );
+ $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 );
+
+ if ( empty( $status ) ) {
+ // requested only protected statuses? nothing for you here
+ return array( 'found' => 0, 'posts' => array() );
+ }
+ // clear it (AKA published only) because "any" includes protected
+ $status = array();
+ }
+
+ $query = array(
+ 'posts_per_page' => $args['number'],
+ 'order' => $args['order'],
+ 'orderby' => $args['order_by'],
+ 'post_type' => $args['type'],
+ 'post_status' => $status,
+ 'post_parent' => isset( $args['parent_id'] ) ? $args['parent_id'] : null,
+ 'author' => isset( $args['author'] ) && 0 < $args['author'] ? $args['author'] : null,
+ 's' => isset( $args['search'] ) ? $args['search'] : null,
+ 'fields' => 'ids',
+ );
+
+ 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'] ) )
+ $show = true;
+ if ( current_user_can( 'edit_post_meta', $query['post_type'], $args['meta_key'] ) )
+ $show = true;
+
+ 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'] ) )
+ $meta['value'] = $args['meta_value'];
+
+ $query['meta_query'] = array( $meta );
+ }
+
+ if ( $args['sticky'] === 'include' ) {
+ $query['ignore_sticky_posts'] = 1;
+ } else if ( $args['sticky'] === 'exclude' ) {
+ $sticky = get_option( 'sticky_posts' );
+ if ( is_array( $sticky ) ) {
+ $query['post__not_in'] = $sticky;
+ }
+ } else if ( $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() );
+ }
+ }
+
+ if ( isset( $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',
+ );
+ $post_descendants = get_pages( $page_args );
+
+ $exclude_tree = array( $args['exclude_tree'] );
+ foreach ( $post_descendants as $child ) {
+ $exclude_tree[] = $child->ID;
+ }
+
+ $query['post__not_in'] = isset( $query['post__not_in'] ) ? array_merge( $query['post__not_in'], $exclude_tree ) : $exclude_tree;
+ }
+
+ if ( isset( $args['category'] ) ) {
+ $category = get_term_by( 'slug', $args['category'], 'category' );
+ if ( $category === false) {
+ $query['category_name'] = $args['category'];
+ } else {
+ $query['cat'] = $category->term_id;
+ }
+ }
+
+ if ( isset( $args['tag'] ) ) {
+ $query['tag'] = $args['tag'];
+ }
+
+ if ( ! empty( $args['term'] ) ) {
+ $query['tax_query'] = array();
+ foreach ( $args['term'] as $taxonomy => $slug ) {
+ $taxonomy_object = get_taxonomy( $taxonomy );
+ 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 )
+ );
+ }
+ }
+
+ if ( isset( $args['page'] ) ) {
+ if ( $args['page'] < 1 ) {
+ $args['page'] = 1;
+ }
+
+ $query['paged'] = $args['page'];
+ if ( $query['paged'] !== 1 ) {
+ $is_eligible_for_page_handle = false;
+ }
+ } else {
+ if ( $args['offset'] < 0 ) {
+ $args['offset'] = 0;
+ }
+
+ $query['offset'] = $args['offset'];
+ if ( $query['offset'] !== 0 ) {
+ $is_eligible_for_page_handle = false;
+ }
+ }
+
+ if ( isset( $args['before'] ) ) {
+ $this->date_range['before'] = $args['before'];
+ }
+ if ( isset( $args['after'] ) ) {
+ $this->date_range['after'] = $args['after'];
+ }
+
+ if ( isset( $args['modified_before_gmt'] ) ) {
+ $this->modified_range['before'] = $args['modified_before_gmt'];
+ }
+ if ( isset( $args['modified_after_gmt'] ) ) {
+ $this->modified_range['after'] = $args['modified_after_gmt'];
+ }
+
+ if ( $this->date_range ) {
+ add_filter( 'posts_where', array( $this, 'handle_date_range' ) );
+ }
+
+ if ( $this->modified_range ) {
+ add_filter( 'posts_where', array( $this, 'handle_modified_range' ) );
+ }
+
+ if ( isset( $args['page_handle'] ) ) {
+ $page_handle = wp_parse_args( $args['page_handle'] );
+ if ( isset( $page_handle['value'] ) && isset( $page_handle['id'] ) ) {
+ // we have a valid looking page handle
+ $this->page_handle = $page_handle;
+ add_filter( 'posts_where', array( $this, 'handle_where_for_page_handle' ) );
+ }
+ }
+
+ /**
+ * 'column' necessary for the me/posts endpoint (which extends sites/$site/posts).
+ * Would need to be added to the sites/$site/posts definition if we ever want to
+ * use it there.
+ */
+ $column_whitelist = array( 'post_modified_gmt' );
+ if ( isset( $args['column'] ) && in_array( $args['column'], $column_whitelist ) ) {
+ $query['column'] = $args['column'];
+ }
+
+ $this->performed_query = $query;
+ add_filter( 'posts_orderby', array( $this, 'handle_orderby_for_page_handle' ) );
+
+ $wp_query = new WP_Query( $query );
+
+ remove_filter( 'posts_orderby', array( $this, 'handle_orderby_for_page_handle' ) );
+
+ if ( $this->date_range ) {
+ remove_filter( 'posts_where', array( $this, 'handle_date_range' ) );
+ $this->date_range = array();
+ }
+
+ if ( $this->modified_range ) {
+ remove_filter( 'posts_where', array( $this, 'handle_modified_range' ) );
+ $this->modified_range = array();
+ }
+
+ if ( $this->page_handle ) {
+ remove_filter( 'posts_where', array( $this, 'handle_where_for_page_handle' ) );
+
+ }
+
+ $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++;
+ }
+ }
+
+ 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;
+
+ 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();
+ }
+ $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;
+ }
+
+ break;
+ }
+ }
+
+ $return['found'] -= $excluded_count;
+
+ return $return;
+ }
+
+ function build_page_handle( $post, $query ) {
+ $column = $query['orderby'];
+ if ( ! $column ) {
+ $column = 'date';
+ }
+ 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 :
+ $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 :
+ if ( isset( $range['before'] ) ) {
+ $where .= $wpdb->prepare(
+ " AND `$wpdb->posts`.$column < CAST( %s AS DATETIME ) ",
+ $range['before']
+ );
+ } else {
+ $where .= $wpdb->prepare(
+ " AND `$wpdb->posts`.$column > CAST( %s AS DATETIME ) ",
+ $range['after']
+ );
+ }
+ break;
+ }
+
+ return $where;
+ }
+}
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 82464c3f..ec142eb8 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
@@ -45,14 +45,13 @@ class WPCOM_JSON_API_List_Roles_Endpoint extends WPCOM_JSON_API_Endpoint {
$roles = array();
- global $wp_roles;
- $wp_roles->reinit();
+ $wp_roles= new WP_Roles();
$role_names = $wp_roles->get_names();
$role_keys = array_keys( $role_names );
foreach ( (array) $role_keys as $role_key ) {
$role_details = get_role( $role_key );
- $role_details->display_name = $role_names[$role_key];
+ $role_details->display_name = translate_user_role( $role_names[$role_key] );
$roles[] = $role_details;
}
@@ -61,4 +60,4 @@ class WPCOM_JSON_API_List_Roles_Endpoint extends WPCOM_JSON_API_Endpoint {
return array( 'roles' => $roles );
}
-} \ No newline at end of file
+}
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 95f59288..14472ab9 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
@@ -65,35 +65,6 @@ abstract class WPCOM_JSON_API_Post_Endpoint extends WPCOM_JSON_API_Endpoint {
parent::__construct( $args );
}
- function is_metadata_public( $key ) {
- if ( empty( $key ) )
- return false;
-
- // Default whitelisted meta keys.
- $whitelisted_meta = array( '_thumbnail_id' );
-
- /**
- * Filters the meta keys accessible by the REST API.
- * @see https://developer.wordpress.com/2013/04/26/custom-post-type-and-metadata-support-in-the-rest-api/
- *
- * @module json-api
- *
- * @since 2.2.3
- *
- * @param array $whitelisted_meta Array of metadata that is accessible by the REST API.
- */
- if ( in_array( $key, apply_filters( 'rest_api_allowed_public_metadata', $whitelisted_meta ) ) )
- return true;
-
- if ( 0 === strpos( $key, 'geo_' ) )
- return true;
-
- if ( 0 === strpos( $key, '_wpas_' ) )
- return true;
-
- return false;
- }
-
function the_password_form() {
return __( 'This post is password protected.', 'jetpack' );
}
@@ -449,7 +420,7 @@ abstract class WPCOM_JSON_API_Post_Endpoint extends WPCOM_JSON_API_Endpoint {
$show = true;
// Only business plan subscribers can view custom meta description.
- if ( Jetpack_SEO_Posts::DESCRIPTION_META_KEY == $meta->key && ! Jetpack_SEO_Utils::is_enabled_jetpack_seo() ) {
+ if ( Jetpack_SEO_Posts::DESCRIPTION_META_KEY === $meta['meta_key'] && ! Jetpack_SEO_Utils::is_enabled_jetpack_seo() ) {
$show = false;
}
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 93dade64..8dd17601 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
@@ -112,7 +112,18 @@ abstract class WPCOM_JSON_API_Post_v1_1_Endpoint extends WPCOM_JSON_API_Endpoint
setup_postdata( $post );
}
- $response = $this->render_response_keys( $post, $context, array_keys( $this->post_object_format ) );
+ $keys_to_render = array_keys( $this->post_object_format );
+ if ( isset( $this->api->query[ 'fields' ] ) ) {
+ $limit_to_fields = array_map( 'trim', explode( ',', $this->api->query['fields'] ) );
+ $keys_to_render = array_intersect( $keys_to_render, $limit_to_fields );
+ }
+
+ // always include 'type' because processors require it to validate access
+ if ( ! in_array( 'type', $keys_to_render ) ) {
+ array_push( $keys_to_render, 'type' );
+ }
+
+ $response = $this->render_response_keys( $post, $context, $keys_to_render );
unset( $GLOBALS['post'] );
diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-publicize-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-publicize-endpoint.php
deleted file mode 100644
index bccfa84d..00000000
--- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-publicize-endpoint.php
+++ /dev/null
@@ -1,181 +0,0 @@
-<?php
-
-class WPCOM_JSON_API_Get_Connections_Endpoint extends WPCOM_JSON_API_Endpoint {
- // /sites/%s/connections
- function callback( $path = '', $blog_id = 0 ) {
- // Verify required Publicize Jetpack module is active
- if ( ! class_exists( 'Publicize' ) || ( method_exists( 'Jetpack', 'is_module_active' ) && ! Jetpack::is_module_active( 'publicize' ) ) ) {
- return new WP_Error( 'missing_jetpack_module', 'The Publicize module must be activated in order to use this endpoint.', 400 );
- }
-
- // Authenticate user
- $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ), false );
- if ( is_wp_error( $blog_id ) ) {
- return $blog_id;
- }
-
- $current_user = wp_get_current_user();
- if ( ! $current_user->ID ) {
- return new WP_Error( 'authorization_required', 'An active access token must be used to query information about the current user.', 403 );
- }
-
- // Parse query arguments to determine if filtering is requested
- $args = $this->query_args();
- $service_filter = false;
- if ( ! empty( $args['service'] ) ) {
- $service_filter = $args['service'];
- }
-
- // Iterate over connected services
- $publicize = new Publicize();
- $connected_services = $publicize->get_services( 'connected' );
- $output = array();
- foreach( $connected_services as $service => $connections ) {
- if ( false != $service_filter && $service_filter != $service ) {
- continue;
- }
-
- foreach ( $connections as $connection_id => $connection ) {
- $output[] = WPCOM_JSON_API_Get_Connection_Endpoint::get_connection( $service, $connection );
- }
- }
-
- return array( 'connections' => $output );
- }
-}
-
-class WPCOM_JSON_API_Get_Connection_Endpoint extends WPCOM_JSON_API_Endpoint {
- function get_connection_by_id( $connection_id ) {
- $publicize = new Publicize();
-
- $connected_services = $publicize->get_services( 'connected' );
- foreach ( $connected_services as $service => $connections ) {
- foreach ( $connections as $c => $connection ) {
- if ( $connection_id == $publicize->get_connection_id( $connection ) ) {
- return WPCOM_JSON_API_Get_Connection_Endpoint::get_connection( $service, $connections[ $c ] );
- }
- }
- }
-
- return false;
- }
-
- function get_connection( $service, $connection ) {
- $publicize = new Publicize();
-
- $connection_id = $publicize->get_connection_id( $connection );
- if ( method_exists( $connection, 'get_meta' ) ) {
- $connection_meta = $connection->get_meta();
- $connection_data = (array) $connection->get_meta( 'connection_data' );
- } else {
- $connection_meta = $connection;
- $connection_data = $connection['connection_data'];
- }
-
- return array(
- 'ID' => (int) $connection_id,
- 'token_ID' => (int) $connection_data['token_id'],
- 'conn_ID' => (int) $connection_id,
- 'site_ID' => (int) $connection_data['blog_id'],
- 'user_ID' => (int) $connection_data['user_id'],
- 'shared' => ( 0 == (int) $connection_data['user_id'] ) ? true : false,
- 'service' => $service,
- 'label' => $publicize->get_service_label( $service ),
- 'issued' => $connection_meta['issued'],
- 'expires' => $connection_meta['expires'],
- 'external_ID' => $connection_meta['external_id'],
- 'external_name' => $connection_meta['external_name'],
- 'external_display' => $publicize->get_display_name( $service, $connection ),
- 'URL' => $publicize->get_profile_link( $service, $connection ),
- 'status' => ( method_exists( $connection, 'is_expired' ) && $connection->is_expired( HOUR_IN_SECONDS ) ) ? 'broken' : 'ok',
- 'refresh_url' => $publicize->refresh_url( $service ),
- 'meta' => maybe_unserialize( $connection_data['meta'] ),
- );
- }
-
- // /sites/%s/connections/$connection_id
- function callback( $path = '', $blog_id = 0, $connection_id = 0 ) {
- // Verify required Publicize Jetpack module is active
- if ( ! class_exists( 'Publicize' ) || ( method_exists( 'Jetpack', 'is_module_active' ) && ! Jetpack::is_module_active( 'publicize' ) ) ) {
- return new WP_Error( 'missing_jetpack_module', 'The Publicize module must be activated in order to use this endpoint.', 400 );
- }
-
- $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ), false );
- if ( is_wp_error( $blog_id ) ) {
- return $blog_id;
- }
-
- $current_user = wp_get_current_user();
- if ( ! $current_user->ID ) {
- return new WP_Error( 'authorization_required', 'An active access token must be used to query information about the current user.', 403 );
- }
-
- // Attempt to find connection
- $connection = WPCOM_JSON_API_Get_Connection_Endpoint::get_connection_by_id( $connection_id );
-
- // Verify that user has permission to view this connection
- if ( $current_user->ID != $connection['user_ID'] && 0 != $connection['user_ID'] ) {
- return new WP_Error( 'authorization_required', 'You do not have permission to access this resource.', 403 );
- }
-
- if ( empty( $connection ) ) {
- return new WP_Error( 'unknown_connection', 'Connection not found.', 404 );
- }
-
- return $connection;
- }
-}
-
-class WPCOM_JSON_API_Delete_Connection_Endpoint extends WPCOM_JSON_API_Endpoint {
- // /sites/%s/connections/$connection_id/delete
- function callback( $path = '', $blog_id = 0 , $connection_id = 0 ) {
- // Verify required Publicize Jetpack module is active
- if ( ! class_exists( 'Publicize' ) || ( method_exists( 'Jetpack', 'is_module_active' ) && ! Jetpack::is_module_active( 'publicize' ) ) ) {
- return new WP_Error( 'missing_jetpack_module', 'The Publicize module must be activated in order to use this endpoint.', 400 );
- }
-
- $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ), false );
- if ( is_wp_error( $blog_id ) ) {
- return $blog_id;
- }
-
- $current_user = wp_get_current_user();
- if ( ! $current_user->ID ) {
- return new WP_Error( 'authorization_required', 'An active access token must be used to query information about the current user.', 403 );
- }
-
- // Attempt to find connection
- $connection = WPCOM_JSON_API_Get_Connection_Endpoint::get_connection_by_id( $connection_id );
-
- if ( empty( $connection ) ) {
- return new WP_Error( 'unknown_connection', 'Connection not found.', 404 );
- }
-
- // Verify that user has permission to view this connection
- if ( $current_user->ID != $connection['user_ID'] && 0 != $connection['user_ID'] ) {
- return new WP_Error( 'authorization_required', 'You do not have permission to access this resource.', 403 );
- }
-
- // Remove publicize connections related to the connection
- $publicize = new Publicize();
- $is_deleted = ( false !== $publicize->disconnect( $connection['service'], $connection_id ) );
-
- if ( $is_deleted ) {
- /**
- * Fires when a Publicize connection is deleted.
- *
- * @module json-api
- *
- * @since 3.2.0
- *
- * @param int $connection_id Publicize connection ID.
- */
- do_action( 'rest_api_delete_publicize_connection', $connection_id );
- }
-
- return array(
- 'ID' => (int) $connection_id,
- 'deleted' => $is_deleted
- );
- }
-}
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 58abec3d..5aebe8d3 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
@@ -8,6 +8,7 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint {
'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.',
);
@@ -137,6 +138,14 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint {
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' );
@@ -198,8 +207,12 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint {
'comment_max_links' => (int) get_option( 'comment_max_links' ),
'moderation_keys' => get_option( 'moderation_keys' ),
'blacklist_keys' => get_option( 'blacklist_keys' ),
- 'lang_id' => get_option( 'lang_id' ),
- 'wga' => $this->get_google_analytics(),
+ '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' => defined( 'IS_WPCOM' ) && IS_WPCOM
+ ? get_option( '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 ),
@@ -216,12 +229,21 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint {
'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' ),
);
+ 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();
+ }
+
//allow future versions of this endpoint to support additional settings keys
/**
* Filter the current site setting in the returned response.
@@ -280,7 +302,6 @@ 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
/**
@@ -294,6 +315,8 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint {
*/
$input = apply_filters( 'rest_api_update_site_settings', $this->input() );
+ $blog_id = get_current_blog_id();
+
$jetpack_relatedposts_options = array();
$sharing_options = array();
$updated = array();
@@ -384,6 +407,7 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint {
$business_plugins->activate_plugin( 'wp-google-analytics' );
}
break;
+
case 'jetpack_testimonial':
case 'jetpack_portfolio':
case 'jetpack_comment_likes_enabled':
@@ -487,7 +511,15 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint {
// 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 ) ) {
- if ( delete_option( $key ) ) {
+ /**
+ * Fallback mechanism to clear a third party site icon setting. Can be used
+ * to unset the option when an API request instructs the site to remove the site icon.
+ *
+ * @module json-api
+ *
+ * @since 4.10
+ */
+ if ( delete_option( $key ) || apply_filters( 'rest_api_site_icon_cleared', false ) ) {
$updated[ $key ] = null;
}
} else if ( is_numeric( $value ) ) {
@@ -538,6 +570,23 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint {
}
break;
+ case 'wpcom_publish_posts_with_markdown':
+ case 'wpcom_publish_comments_with_markdown':
+ $coerce_value = (bool) $value;
+ if ( update_option( $key, $coerce_value ) ) {
+ $updated[ $key ] = $coerce_value;
+ }
+ break;
+
+ case 'amp_is_enabled':
+ if ( function_exists( 'wpcom_update_amp_enabled' ) ) {
+ $saved = wpcom_update_amp_enabled( $blog_id, $value );
+ if ( $saved ) {
+ $updated[ $key ] = (bool) $value;
+ }
+ }
+ break;
+
default:
//allow future versions of this endpoint to support additional settings keys
if ( has_filter( 'site_settings_endpoint_update_' . $key ) ) {
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 d682094d..872512b6 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
@@ -3,12 +3,13 @@
class WPCOM_JSON_API_Site_Settings_V1_2_Endpoint extends WPCOM_JSON_API_Site_Settings_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',
- 'locale' => '(string) Locale code of the site',
- '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',
+ 'locale' => '(string) Locale 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.',
);
diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-user-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-user-endpoint.php
index 7a61ce12..57de701c 100644
--- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-user-endpoint.php
+++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-site-user-endpoint.php
@@ -1,5 +1,4 @@
<?php
-
class WPCOM_JSON_API_Site_User_Endpoint extends WPCOM_JSON_API_Endpoint {
public static $user_format = array(
@@ -14,7 +13,7 @@ class WPCOM_JSON_API_Site_User_Endpoint extends WPCOM_JSON_API_Endpoint {
'avatar_URL' => '(url) Gravatar image URL',
'profile_URL' => '(url) Gravatar Profile URL',
'site_ID' => '(int) ID of the user\'s primary blog',
- 'roles' => '(array) The roles of the user',
+ 'roles' => '(array|string) The role or roles of the user',
);
// /sites/%s/users/%d -> $blog_id, $user_id
@@ -55,7 +54,7 @@ class WPCOM_JSON_API_Site_User_Endpoint extends WPCOM_JSON_API_Endpoint {
$the_user = $this->get_author( $user_id, true );
if ( $the_user && ! is_wp_error( $the_user ) ) {
$userdata = get_userdata( $user_id );
- $the_user->roles = ! is_wp_error( $userdata ) ? $userdata->roles : array();
+ $the_user->roles = ! is_wp_error( $userdata ) ? array_values( $userdata->roles ) : array();
}
return $the_user;
@@ -97,13 +96,23 @@ class WPCOM_JSON_API_Site_User_Endpoint extends WPCOM_JSON_API_Endpoint {
}
}
}
+
if ( isset( $input[ 'roles' ] ) ) {
+ // For now, we only use the first role in the array.
if ( is_array( $input['roles'] ) ) {
$user['role'] = $input['roles'][0];
- } else {
+ } else if ( is_string( $input['roles'] ) ) {
$user['role'] = $input['roles'];
+ } else {
+ return new WP_Error( 'invalid_input', __( 'The roles property must be a string or an array.', 'jetpack' ), 400 );
+ }
+
+ $editable_roles = array_keys( get_editable_roles() );
+ if ( ! in_array( $user['role'], $editable_roles ) ) {
+ return new WP_Error( 'invalid_input', sprintf( __( '%s is not a valid role.', 'jetpack' ), $editable_roles ), 400 );
}
}
+
$result = wp_update_user( $user );
if ( is_wp_error( $result ) ) {
return $result;
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 cd912132..79632dd3 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
@@ -173,10 +173,6 @@ class WPCOM_JSON_API_Update_Comment_Endpoint extends WPCOM_JSON_API_Comment_Endp
}
if ( isset( $update['comment_status'] ) ) {
- if ( count( $update ) === 1 ) {
- // We are only here to update the comment status so let's respond ASAP
- add_action( 'wp_set_comment_status', array( $this, 'output_comment' ), 0, 1 );
- }
switch ( $update['comment_status'] ) {
case 'approved' :
if ( 'approve' !== $comment_status ) {
@@ -263,10 +259,4 @@ class WPCOM_JSON_API_Update_Comment_Endpoint extends WPCOM_JSON_API_Comment_Endp
return $this->get_comment( $comment->comment_ID, $args['context'] );
}
-
- function output_comment( $comment_id ) {
- $args = $this->query_args();
- $output = $this->get_comment( $comment_id, $args['context'] );
- $this->api->output_early( 200, $output );
- }
}
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 849fed88..4231f296 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
@@ -311,7 +311,16 @@ class WPCOM_JSON_API_Update_Post_Endpoint extends WPCOM_JSON_API_Post_Endpoint {
$insert['edit_date'] = true;
}
- $post_id = wp_update_post( (object) $insert );
+ // this two-step process ensures any changes submitted along with status=trash get saved before trashing
+ if ( isset( $input['status'] ) && 'trash' === $input['status'] ) {
+ // if we insert it with status='trash', it will get double-trashed, so insert it as a draft first
+ unset( $insert['status'] );
+ $post_id = wp_update_post( (object) $insert );
+ // now call wp_trash_post so post_meta gets set and any filters get called
+ wp_trash_post( $post_id );
+ } else {
+ $post_id = wp_update_post( (object) $insert );
+ }
}
@@ -537,6 +546,10 @@ class WPCOM_JSON_API_Update_Post_Endpoint extends WPCOM_JSON_API_Post_Endpoint {
if ( ! empty( $meta->id ) ) {
$meta->id = absint( $meta->id );
$existing_meta_item = get_metadata_by_mid( 'post', $meta->id );
+ if ( $post_id !== (int) $existing_meta_item->post_id ) {
+ // Only allow updates for metadata on this post
+ continue;
+ }
}
$unslashed_meta_key = wp_unslash( $meta->key ); // should match what the final key will be
@@ -648,7 +661,11 @@ class WPCOM_JSON_API_Update_Post_Endpoint extends WPCOM_JSON_API_Post_Endpoint {
/** This action is documented in json-endpoints/class.wpcom-json-api-site-settings-endpoint.php */
do_action( 'wpcom_json_api_objects', 'posts' );
- wp_delete_post( $post->ID );
+ // we need to call wp_trash_post so that untrash will work correctly for all post types
+ if ( 'trash' === $post->post_status )
+ wp_delete_post( $post->ID );
+ else
+ wp_trash_post( $post->ID );
$status = get_post_status( $post->ID );
if ( false === $status ) {
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 0f697f0b..e74ec352 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
@@ -29,6 +29,8 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_
// /sites/%s/posts/new -> $blog_id
// /sites/%s/posts/%d -> $blog_id, $post_id
function write_post( $path, $blog_id, $post_id ) {
+ global $wpdb;
+
$new = $this->api->ends_with( $path, '/new' );
$args = $this->query_args();
@@ -139,9 +141,9 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_
}
}
- if ( function_exists( 'wpcom_switch_to_locale' ) ) {
+ if ( function_exists( 'wpcom_switch_to_blog_locale' ) ) {
// fixes calypso-pre-oss #12476: respect blog locale when creating the post slug
- wpcom_switch_to_locale( get_blog_lang_code( $blog_id ) );
+ wpcom_switch_to_blog_locale( $blog_id );
}
// If date was set, $this->input will set date_gmt, date still needs to be adjusted for the blog's offset
@@ -330,8 +332,16 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_
$has_media = ! empty( $input['media'] ) ? count( $input['media'] ) : false;
$has_media_by_url = ! empty( $input['media_urls'] ) ? count( $input['media_urls'] ) : false;
- if ( $new ) {
+ $media_id_string = '';
+ if ( $has_media || $has_media_by_url ) {
+ $media_files = ! empty( $input['media'] ) ? $input['media'] : array();
+ $media_urls = ! empty( $input['media_urls'] ) ? $input['media_urls'] : array();
+ $media_attrs = ! empty( $input['media_attrs'] ) ? $input['media_attrs'] : array();
+ $media_results = $this->handle_media_creation_v1_1( $media_files, $media_urls, $media_attrs );
+ $media_id_string = join( ',', array_filter( array_map( 'absint', $media_results['media_ids'] ) ) );
+ }
+ if ( $new ) {
if ( isset( $input['content'] ) && ! has_shortcode( $input['content'], 'gallery' ) && ( $has_media || $has_media_by_url ) ) {
switch ( ( $has_media + $has_media_by_url ) ) {
case 0 :
@@ -339,11 +349,17 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_
break;
case 1 :
// 1 image - make it big
- $insert['post_content'] = $input['content'] = "[gallery size=full columns=1]\n\n" . $input['content'];
+ $insert['post_content'] = $input['content'] = sprintf(
+ "[gallery size=full ids='%s' columns=1]\n\n",
+ $media_id_string
+ ) . $input['content'];
break;
default :
// Several images - 3 column gallery
- $insert['post_content'] = $input['content'] = "[gallery]\n\n" . $input['content'];
+ $insert['post_content'] = $input['content'] = sprintf(
+ "[gallery ids='%s']\n\n",
+ $media_id_string
+ ) . $input['content'];
break;
}
}
@@ -359,7 +375,16 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_
$insert['edit_date'] = true;
}
- $post_id = wp_update_post( (object) $insert );
+ // this two-step process ensures any changes submitted along with status=trash get saved before trashing
+ if ( isset( $input['status'] ) && 'trash' === $input['status'] ) {
+ // if we insert it with status='trash', it will get double-trashed, so insert it as a draft first
+ unset( $insert['status'] );
+ $post_id = wp_update_post( (object) $insert );
+ // now call wp_trash_post so post_meta gets set and any filters get called
+ wp_trash_post( $post_id );
+ } else {
+ $post_id = wp_update_post( (object) $insert );
+ }
}
@@ -373,12 +398,16 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_
return $post_check;
}
- if ( $has_media || $has_media_by_url ) {
- $media_files = ! empty( $input['media'] ) ? $input['media'] : array();
- $media_urls = ! empty( $input['media_urls'] ) ? $input['media_urls'] : array();
- $media_attrs = ! empty( $input['media_attrs'] ) ? $input['media_attrs'] : array();
- $force_parent_id = $post_id;
- $media_results = $this->handle_media_creation_v1_1( $media_files, $media_urls, $media_attrs, $force_parent_id );
+ if ( $media_id_string ) {
+ // Yes - this is really how wp-admin does it.
+ $wpdb->query( $wpdb->prepare(
+ "UPDATE $wpdb->posts SET post_parent = %d WHERE post_type = 'attachment' AND ID IN ( $media_id_string )",
+ $post_id
+ ) );
+ foreach ( $media_results['media_ids'] as $media_id ) {
+ clean_attachment_cache( $media_id );
+ }
+ clean_post_cache( $post_id );
}
// set page template for this post..
@@ -585,6 +614,10 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_
if ( ! empty( $meta->id ) ) {
$meta->id = absint( $meta->id );
$existing_meta_item = get_metadata_by_mid( 'post', $meta->id );
+ if ( $post_id !== (int) $existing_meta_item->post_id ) {
+ // Only allow updates for metadata on this post
+ continue;
+ }
}
$unslashed_meta_key = wp_unslash( $meta->key ); // should match what the final key will be
@@ -694,7 +727,11 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_
/** This action is documented in json-endpoints/class.wpcom-json-api-site-settings-endpoint.php */
do_action( 'wpcom_json_api_objects', 'posts' );
- wp_delete_post( $post->ID );
+ // we need to call wp_trash_post so that untrash will work correctly for all post types
+ if ( 'trash' === $post->post_status )
+ wp_delete_post( $post->ID );
+ else
+ wp_trash_post( $post->ID );
$status = get_post_status( $post->ID );
if ( false === $status ) {
@@ -777,6 +814,6 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_
$type = get_post_type( $post_id );
}
- return ! empty( $type ) && ! in_array( $type, array( 'post', 'page', 'revision' ) );
+ return ! empty( $type ) && ! in_array( $type, array( 'post', 'revision' ) );
}
}
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 7aeb011d..339d06c5 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
@@ -4,6 +4,8 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos
// /sites/%s/posts/new -> $blog_id
// /sites/%s/posts/%d -> $blog_id, $post_id
function write_post( $path, $blog_id, $post_id ) {
+ global $wpdb;
+
$new = $this->api->ends_with( $path, '/new' );
$args = $this->query_args();
@@ -113,9 +115,9 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos
}
}
- if ( function_exists( 'wpcom_switch_to_locale' ) ) {
+ if ( function_exists( 'wpcom_switch_to_blog_locale' ) ) {
// fixes calypso-pre-oss #12476: respect blog locale when creating the post slug
- wpcom_switch_to_locale( get_blog_lang_code( $blog_id ) );
+ wpcom_switch_to_blog_locale( $blog_id );
}
// If date is set, $this->input will set date_gmt, date still needs to be adjusted f
@@ -331,8 +333,16 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos
$has_media = ! empty( $input['media'] ) ? count( $input['media'] ) : false;
$has_media_by_url = ! empty( $input['media_urls'] ) ? count( $input['media_urls'] ) : false;
- if ( $new ) {
+ $media_id_string = '';
+ if ( $has_media || $has_media_by_url ) {
+ $media_files = ! empty( $input['media'] ) ? $input['media'] : array();
+ $media_urls = ! empty( $input['media_urls'] ) ? $input['media_urls'] : array();
+ $media_attrs = ! empty( $input['media_attrs'] ) ? $input['media_attrs'] : array();
+ $media_results = $this->handle_media_creation_v1_1( $media_files, $media_urls, $media_attrs );
+ $media_id_string = join( ',', array_filter( array_map( 'absint', $media_results['media_ids'] ) ) );
+ }
+ if ( $new ) {
if ( isset( $input['content'] ) && ! has_shortcode( $input['content'], 'gallery' ) && ( $has_media || $has_media_by_url ) ) {
switch ( ( $has_media + $has_media_by_url ) ) {
case 0 :
@@ -340,11 +350,17 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos
break;
case 1 :
// 1 image - make it big
- $insert['post_content'] = $input['content'] = "[gallery size=full columns=1]\n\n" . $input['content'];
+ $insert['post_content'] = $input['content'] = sprintf(
+ "[gallery size=full ids='%s' columns=1]\n\n",
+ $media_id_string
+ ) . $input['content'];
break;
default :
// Several images - 3 column gallery
- $insert['post_content'] = $input['content'] = "[gallery]\n\n" . $input['content'];
+ $insert['post_content'] = $input['content'] = sprintf(
+ "[gallery ids='%s']\n\n",
+ $media_id_string
+ ) . $input['content'];
break;
}
}
@@ -360,7 +376,16 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos
$insert['edit_date'] = true;
}
- $post_id = wp_update_post( (object) $insert );
+ // this two-step process ensures any changes submitted along with status=trash get saved before trashing
+ if ( isset( $input['status'] ) && 'trash' === $input['status'] ) {
+ // if we insert it with status='trash', it will get double-trashed, so insert it as a draft first
+ unset( $insert['status'] );
+ $post_id = wp_update_post( (object) $insert );
+ // now call wp_trash_post so post_meta gets set and any filters get called
+ wp_trash_post( $post_id );
+ } else {
+ $post_id = wp_update_post( (object) $insert );
+ }
}
@@ -374,12 +399,16 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos
return $post_check;
}
- if ( $has_media || $has_media_by_url ) {
- $media_files = ! empty( $input['media'] ) ? $input['media'] : array();
- $media_urls = ! empty( $input['media_urls'] ) ? $input['media_urls'] : array();
- $media_attrs = ! empty( $input['media_attrs'] ) ? $input['media_attrs'] : array();
- $force_parent_id = $post_id;
- $media_results = $this->handle_media_creation_v1_1( $media_files, $media_urls, $media_attrs, $force_parent_id );
+ if ( $media_id_string ) {
+ // Yes - this is really how wp-admin does it.
+ $wpdb->query( $wpdb->prepare(
+ "UPDATE $wpdb->posts SET post_parent = %d WHERE post_type = 'attachment' AND ID IN ( $media_id_string )",
+ $post_id
+ ) );
+ foreach ( $media_results['media_ids'] as $media_id ) {
+ clean_attachment_cache( $media_id );
+ }
+ clean_post_cache( $post_id );
}
// set page template for this post..
@@ -586,6 +615,10 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos
if ( ! empty( $meta->id ) ) {
$meta->id = absint( $meta->id );
$existing_meta_item = get_metadata_by_mid( 'post', $meta->id );
+ if ( $post_id !== (int) $existing_meta_item->post_id ) {
+ // Only allow updates for metadata on this post
+ continue;
+ }
}
$unslashed_meta_key = wp_unslash( $meta->key ); // should match what the final key will be
@@ -679,6 +712,6 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos
$type = get_post_type( $post_id );
}
- return ! empty( $type ) && ! in_array( $type, array( 'post', 'page', 'revision' ) );
+ return ! empty( $type ) && ! in_array( $type, array( 'post', 'revision' ) );
}
}
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
new file mode 100644
index 00000000..96191fdc
--- /dev/null
+++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-site-homepage-endpoint.php
@@ -0,0 +1,45 @@
+<?php
+
+class WPCOM_JSON_API_Update_Site_Homepage_Endpoint extends WPCOM_JSON_API_Endpoint {
+
+ function callback( $path = '', $site_id = 0 ) {
+ $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $site_id ) );
+ if ( is_wp_error( $blog_id ) ) {
+ return $blog_id;
+ }
+
+ if ( ! current_user_can( 'edit_theme_options' ) ) {
+ return new WP_Error( 'unauthorized', 'User is not authorized to access homepage settings', 403 );
+ }
+
+ $args = $this->input();
+ if ( empty( $args ) || ! is_array( $args ) ) {
+ return $this->get_current_settings();
+ }
+
+ if ( isset( $args['is_page_on_front'] ) ) {
+ $show_on_front = $args['is_page_on_front'] ? 'page' : 'posts';
+ update_option( 'show_on_front', $show_on_front );
+ }
+ if ( isset( $args['page_on_front_id'] ) ) {
+ update_option( 'page_on_front', $args['page_on_front_id'] );
+ }
+ if ( isset( $args['page_for_posts_id'] ) ) {
+ update_option( 'page_for_posts', $args['page_for_posts_id'] );
+ }
+
+ return $this->get_current_settings();
+ }
+
+ function get_current_settings() {
+ $is_page_on_front = ( get_option( 'show_on_front' ) === 'page' );
+ $page_on_front_id = get_option( 'page_on_front' );
+ $page_for_posts_id = get_option( 'page_for_posts' );
+
+ return array(
+ 'is_page_on_front' => $is_page_on_front,
+ 'page_on_front_id' => $page_on_front_id,
+ 'page_for_posts_id' => $page_for_posts_id,
+ );
+ }
+}
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
new file mode 100644
index 00000000..89fa9121
--- /dev/null
+++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-site-logo-endpoint.php
@@ -0,0 +1,47 @@
+<?php
+
+class WPCOM_JSON_API_Update_Site_Logo_Endpoint extends WPCOM_JSON_API_Endpoint {
+ function callback( $path = '', $site_id = 0 ) {
+ // Switch to the given blog.
+ $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $site_id ) );
+ if ( is_wp_error( $blog_id ) ) {
+ return $blog_id;
+ }
+
+ if ( ! current_user_can( 'edit_theme_options' ) ) {
+ return new WP_Error( 'unauthorized', 'User is not authorized to access logo settings', 403 );
+ }
+
+ if ( strpos( $path, '/delete' ) ) {
+ delete_option( 'site_logo' );
+ return array();
+ }
+
+ $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 );
+ }
+
+ return $this->get_current_settings();
+ }
+
+ function get_current_settings() {
+ $logo_settings = get_option( 'site_logo' );
+ if ( ! is_array( $logo_settings ) ) {
+ $logo_settings = array();
+ }
+ return $logo_settings;
+ }
+}
+
diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-taxonomy-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-taxonomy-endpoint.php
index b3f72269..979330b2 100644
--- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-taxonomy-endpoint.php
+++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-taxonomy-endpoint.php
@@ -47,9 +47,8 @@ class WPCOM_JSON_API_Update_Taxonomy_Endpoint extends WPCOM_JSON_API_Taxonomy_En
$input['parent'] = 0;
if ( $term = get_term_by( 'name', $input['name'], $taxonomy_type ) ) {
- // get_term_by is not case-sensitive, but a name with different casing is allowed
- // also, the exact same name is allowed as long as the parents are different
- if ( $input['name'] === $term->name && $input['parent'] === $term->parent ) {
+ // the same name is allowed as long as the parents are different
+ if ( $input['parent'] === $term->parent ) {
return new WP_Error( 'duplicate', 'A taxonomy with that name already exists', 400 );
}
}
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 f5915aff..e08e8810 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
@@ -1,5 +1,4 @@
<?php
-
class WPCOM_JSON_API_Update_User_Endpoint extends WPCOM_JSON_API_Endpoint {
function callback( $path = '', $blog_id = 0, $user_id = 0 ) {
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 4c33b270..bd34b606 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
@@ -1,13 +1,19 @@
<?php
class WPCOM_JSON_API_Upload_Media_v1_1_Endpoint extends WPCOM_JSON_API_Endpoint {
+ /**
+ * @param string $path
+ * @param int $blog_id
+ *
+ * @return array|int|WP_Error|void
+ */
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 ( ! current_user_can( 'upload_files' ) ) {
+ if ( ! current_user_can( 'upload_files' ) && ! $this->api->is_authorized_with_upload_token() ) {
return new WP_Error( 'unauthorized', 'User cannot upload media.', 403 );
}
@@ -16,32 +22,106 @@ class WPCOM_JSON_API_Upload_Media_v1_1_Endpoint extends WPCOM_JSON_API_Endpoint
$media_files = ! empty( $input['media'] ) ? $input['media'] : array();
$media_urls = ! empty( $input['media_urls'] ) ? $input['media_urls'] : array();
$media_attrs = ! empty( $input['attrs'] ) ? $input['attrs'] : array();
+
if ( empty( $media_files ) && empty( $media_urls ) ) {
return new WP_Error( 'invalid_input', 'No media provided in input.' );
}
- $create_media = $this->handle_media_creation_v1_1( $media_files, $media_urls, $media_attrs );
- $media_ids = $create_media['media_ids'];
- $errors = $create_media['errors'];
+ // For jetpack sites, we send the media via a different method, because the sync is very different.
+ $jetpack_sync = Jetpack_Media_Sync::summon( $blog_id );
- $results = array();
- if ( count( $media_ids ) <= 0 ) {
- $this->api->output_early( 400, array( 'errors' => $errors ) );
- } else {
- foreach ( $media_ids as $media_id ) {
- $result = $this->get_media_item_v1_1( $media_id );
- if ( is_wp_error( $result ) ) {
- $errors[] = array( 'file' => $media_id, 'error' => $result->get_error_code(), 'message' => $result->get_error_message() );
- } else {
- $results[] = $result;
- }
+ $jetpack_media_files = array();
+ $other_media_files = array();
+ $media_items = array();
+ $errors = array();
+
+ // We're splitting out videos for Jetpack sites
+ foreach ( $media_files as $media_item ) {
+ if ( preg_match( '@^video/@', $media_item['type'] ) && $jetpack_sync->is_jetpack_site() ) {
+ $jetpack_media_files[] = $media_item;
+
+ } else {
+ $other_media_files[] = $media_item;
}
- if ( count( $errors ) > 0 ) {
- return array( 'media' => $results, 'errors' => $errors );
+ }
+
+ // New Jetpack / VideoPress media upload processing
+ if ( count( $jetpack_media_files ) > 0 ) {
+ add_filter( 'upload_mimes', array( $this, 'allow_video_uploads' ) );
+
+ $media_items = $jetpack_sync->upload_media( $jetpack_media_files, $this->api );
+
+ $errors = $jetpack_sync->get_errors();
+
+ foreach ( $media_items as & $media_item ) {
+ // More than likely a post has not been created yet, so we pass in the media item we
+ // got back from the Jetpack site.
+ $post = (object) $media_item['post'];
+ $media_item = $this->get_media_item_v1_1( $media_item['ID'], $post, $media_item['file'] );
+ }
+ }
+
+ // Normal WPCOM upload processing
+ if ( count( $other_media_files ) > 0 || count( $media_urls ) > 0 ) {
+ $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'];
+
+ $media_items = array();
+ foreach ( $media_ids as $media_id ) {
+ $media_items[] = $this->get_media_item_v1_1( $media_id );
+ }
+ }
+
+ if ( count( $media_items ) <= 0 ) {
+ return $this->api->output_early( 400, array( 'errors' => $errors ) );
+ }
+
+ $results = array();
+ foreach ( $media_items as $media_item ) {
+ if ( is_wp_error( $media_item ) ) {
+ $errors[] = array( 'file' => $media_item['ID'], 'error' => $media_item->get_error_code(), 'message' => $media_item->get_error_message() );
+
} else {
- return array( 'media' => $results );
+ $results[] = $media_item;
+ }
+ }
+
+ $response = array( 'media' => $results );
+
+ if ( count( $errors ) > 0 ) {
+ $response['errors'] = $errors;
+ }
+
+ return $response;
+ }
+
+ /**
+ * 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.
+ *
+ * @param int $blog_id
+ * @return bool
+ */
+ function force_wpcom_request( $blog_id ) {
+
+ // We don't need to do anything if VideoPress is not enabled for the blog.
+ if ( ! is_videopress_enabled_on_jetpack_blog( $blog_id ) ) {
+ return false;
+ }
+
+ // Check to see if the upload is not a video type, if not then return false.
+ $input = $this->input( true );
+ $media_files = ! empty( $input['media'] ) ? $input['media'] : array();
+
+ foreach ( $media_files as $media_item ) {
+ if ( ! preg_match( '@^video/@', $media_item['type'] ) ) {
+ return false;
}
}
+ // The API request should be for a blog w/ Jetpack, A valid plan, has VideoPress enabled,
+ // and is a video file. Let's let it through.
+ return true;
}
}
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
new file mode 100644
index 00000000..0e4bc256
--- /dev/null
+++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-comment-backup-endpoint.php
@@ -0,0 +1,52 @@
+<?php
+
+class Jetpack_JSON_API_Get_Comment_Backup_Endpoint extends Jetpack_JSON_API_Endpoint {
+ // /sites/%s/comments/%d/backup -> $blog_id, $comment_id
+
+ protected $needed_capabilities = array(); // This endpoint is only accessible using a site token
+ protected $comment_id;
+
+ function validate_input( $comment_id ) {
+ if ( empty( $comment_id ) || ! is_numeric( $comment_id ) ) {
+ return new WP_Error( 'comment_id_not_specified', __( 'You must specify a Comment ID', 'jetpack' ), 400 );
+ }
+
+ $this->comment_id = intval( $comment_id );
+
+ return true;
+ }
+
+ protected function result() {
+ $comment = get_comment( $this->comment_id );
+ if ( empty( $comment ) ) {
+ return new WP_Error( 'comment_not_found', __( 'Comment not found', 'jetpack' ), 404 );
+ }
+
+ $allowed_keys = array(
+ 'comment_ID',
+ 'comment_post_ID',
+ 'comment_author',
+ 'comment_author_email',
+ 'comment_author_url',
+ 'comment_author_IP',
+ 'comment_date',
+ 'comment_date_gmt',
+ 'comment_content',
+ 'comment_karma',
+ 'comment_approved',
+ 'comment_agent',
+ 'comment_type',
+ 'comment_parent',
+ 'user_id',
+ );
+
+ $comment = array_intersect_key( $comment->to_array(), array_flip( $allowed_keys ) );
+ $comment_meta = get_comment_meta( $comment['comment_ID'] );
+
+ return array(
+ 'comment' => $comment,
+ 'meta' => is_array( $comment_meta ) ? $comment_meta : array(),
+ );
+ }
+
+}
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
new file mode 100644
index 00000000..a5d8d3a7
--- /dev/null
+++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-option-backup-endpoint.php
@@ -0,0 +1,35 @@
+<?php
+
+class Jetpack_JSON_API_Get_Option_Backup_Endpoint extends Jetpack_JSON_API_Endpoint {
+ // /sites/%s/options/backup -> $blog_id
+
+ protected $needed_capabilities = array(); // This endpoint is only accessible using a site token
+ protected $option_names;
+
+ function validate_input( $object ) {
+ $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 );
+ }
+
+ if ( is_array( $query_args['name'] ) ) {
+ $this->option_names = $query_args['name'];
+ } else {
+ $this->option_names = array( $query_args['name'] );
+ }
+
+ return true;
+ }
+
+ protected function result() {
+ $options = array_map( array( $this, 'get_option_row' ), $this->option_names );
+ return array( 'options' => $options );
+ }
+
+ private function get_option_row( $name ) {
+ global $wpdb;
+ return $wpdb->get_row( $wpdb->prepare( "select * from `{$wpdb->options}` where option_name = %s", $name ) );
+ }
+
+}
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 c9277cd4..903a16ac 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
@@ -3,12 +3,12 @@
class Jetpack_JSON_API_Get_Post_Backup_Endpoint extends Jetpack_JSON_API_Endpoint {
// /sites/%s/posts/%d/backup -> $blog_id, $post_id
- protected $needed_capabilities = array();
+ protected $needed_capabilities = array(); // This endpoint is only accessible using a site token
protected $post_id;
function validate_input( $post_id ) {
if ( empty( $post_id ) || ! is_numeric( $post_id ) ) {
- return new WP_Error( 'post_id_not_specified', __( 'You must specify a Post ID', 'jetpack' ) );
+ return new WP_Error( 'post_id_not_specified', __( 'You must specify a Post ID', 'jetpack' ), 400 );
}
$this->post_id = intval( $post_id );
@@ -19,7 +19,7 @@ class Jetpack_JSON_API_Get_Post_Backup_Endpoint extends Jetpack_JSON_API_Endpoin
protected function result() {
$post = get_post( $this->post_id );
if ( empty( $post ) ) {
- return new WP_Error( 'post_not_found', __( 'Post not found', 'jetpack' ) );
+ return new WP_Error( 'post_not_found', __( 'Post not found', 'jetpack' ), 404 );
}
return array(
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
new file mode 100644
index 00000000..40d0ab97
--- /dev/null
+++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-term-backup-endpoint.php
@@ -0,0 +1,32 @@
+<?php
+
+class Jetpack_JSON_API_Get_Term_Backup_Endpoint extends Jetpack_JSON_API_Endpoint {
+ // /sites/%s/terms/%d/backup -> $blog_id, $term_id
+
+ protected $needed_capabilities = array(); // This endpoint is only accessible using a site token
+ protected $term_id;
+
+ function validate_input( $term_id ) {
+ if ( empty( $term_id ) || ! is_numeric( $term_id ) ) {
+ return new WP_Error( 'term_id_not_specified', __( 'You must specify a Term ID', 'jetpack' ), 400 );
+ }
+
+ $this->term_id = intval( $term_id );
+
+ return true;
+ }
+
+ protected function result() {
+ $term = get_term( $this->term_id );
+ if ( empty( $term ) ) {
+ return new WP_Error( 'term_not_found', __( 'Term not found', 'jetpack' ), 404 );
+ }
+
+ return array(
+ 'term' => (array) $term,
+ 'meta' => get_term_meta( $this->term_id ),
+ );
+ }
+
+}
+
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
new file mode 100644
index 00000000..12fa5d9b
--- /dev/null
+++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-get-user-backup-endpoint.php
@@ -0,0 +1,32 @@
+<?php
+
+class Jetpack_JSON_API_Get_User_Backup_Endpoint extends Jetpack_JSON_API_Endpoint {
+ // /sites/%s/users/%d/backup -> $blog_id, $user_id
+
+ protected $needed_capabilities = array(); // This endpoint is only accessible using a site token
+ protected $user_id;
+
+ function validate_input( $user_id ) {
+ if ( empty( $user_id ) || ! is_numeric( $user_id ) ) {
+ return new WP_Error( 'user_id_not_specified', __( 'You must specify a User ID', 'jetpack' ), 400 );
+ }
+
+ $this->user_id = intval( $user_id );
+
+ return true;
+ }
+
+ protected function result() {
+ $user = get_user_by( 'id', $this->user_id );
+ if ( empty( $user ) ) {
+ return new WP_Error( 'user_not_found', __( 'User not found', 'jetpack' ), 404 );
+ }
+
+ return array(
+ 'user' => (array)$user,
+ 'meta' => get_user_meta( $user->ID ),
+ );
+ }
+
+}
+
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 229ffc98..04e56550 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
@@ -211,7 +211,7 @@ abstract class Jetpack_JSON_API_Plugins_Endpoint extends Jetpack_JSON_API_Endpoi
if ( count( $action_links ) > 0 ) {
$dom_doc = new DOMDocument;
foreach( $action_links as $action_link ) {
- $dom_doc->loadHTML( $action_link );
+ $dom_doc->loadHTML( mb_convert_encoding( $action_link, 'HTML-ENTITIES', 'UTF-8' ) );
$link_elements = $dom_doc->getElementsByTagName( 'a' );
if ( $link_elements->length == 0 ) {
continue;
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 22394029..c18a754f 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
@@ -245,7 +245,7 @@ class Jetpack_JSON_API_Plugins_Modify_Endpoint extends Jetpack_JSON_API_Plugins_
*
* @param array $plugin Plugin data
* @param array $plugin Array of plugin objects
- * @param bool $updated_attempted false for the first update, true subsequently
+ * @param bool $update_attempted false for the first update, true subsequently
*/
do_action( 'jetpack_pre_plugin_upgrade_translations', $plugin, $this->plugins, $update_attempted );
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
new file mode 100644
index 00000000..8b758559
--- /dev/null
+++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-user-connect-endpoint.php
@@ -0,0 +1,31 @@
+<?php
+
+class Jetpack_JSON_API_User_Connect_Endpoint extends Jetpack_JSON_API_Endpoint {
+
+ protected $needed_capabilities = 'create_users';
+
+ private $user_id;
+ private $user_token;
+
+ function result() {
+ Jetpack::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 ) );
+ }
+
+ function validate_input( $user_id ) {
+ $input = $this->input();
+ if ( ! isset( $user_id ) ) {
+ return new WP_Error( 'input_error', __( 'user_id is required', 'jetpack' ) );
+ }
+ $this->user_id = $user_id;
+ if ( 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'] ) ) {
+ return new WP_Error( 'input_error', __( 'user_token is required', 'jetpack' ) );
+ }
+ $this->user_token = sanitize_text_field( $input[ 'user_token'] );
+ return parent::validate_input( $user_id );
+ }
+
+}
diff --git a/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-user-create-endpoint.php b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-user-create-endpoint.php
new file mode 100644
index 00000000..07d1c219
--- /dev/null
+++ b/plugins/jetpack/json-endpoints/jetpack/class.jetpack-json-api-user-create-endpoint.php
@@ -0,0 +1,61 @@
+<?php
+
+class Jetpack_JSON_API_User_Create_Endpoint extends Jetpack_JSON_API_Endpoint {
+
+ protected $needed_capabilities = 'create_users';
+
+ private $user_data;
+
+ function result() {
+ return $this->create_or_get_user();
+ }
+
+ function validate_input( $object ) {
+ $this->user_data = $this->input();
+ if ( empty( $this->user_data ) ) {
+ return new WP_Error( 'input_error', __( 'user_data is required', 'jetpack' ) );
+ }
+ if ( ! isset( $this->user_data[ 'email' ] ) ) {
+ return new WP_Error( 'input_error', __( 'user email is required', 'jetpack' ) );
+ }
+ if ( ! isset( $this->user_data[ 'login' ] ) ) {
+ return new WP_Error( 'input_error', __( 'user login is required', 'jetpack' ) );
+ }
+ return parent::validate_input( $object );
+ }
+
+ function create_or_get_user() {
+ require_once JETPACK__PLUGIN_DIR . 'modules/sso/class.jetpack-sso-helpers.php';
+
+ // Check for an existing user
+ $user = get_user_by( 'email', $this->user_data['email'] );
+
+ if ( ! $user ) {
+ // We modify the input here to mimick the same call structure of the update user endpoint.
+ $this->user_data = (object) $this->user_data;
+ $roles = (array) $this->user_data->roles;
+ $this->user_data->role = array_pop( $roles );
+ $this->user_data->url = $this->user_data->roles;
+ $this->user_data->display_name = $this->user_data->name;
+ $this->user_data->description = '';
+ $user = Jetpack_SSO_Helpers::generate_user( $this->user_data );
+ }
+
+ if ( ! $user ) {
+ return false;
+ }
+
+ return $this->get_user( $user->ID );
+ }
+
+ public function get_user( $user_id ) {
+ $the_user = $this->get_author( $user_id, true );
+ if ( $the_user && ! is_wp_error( $the_user ) ) {
+ $userdata = get_userdata( $user_id );
+ $the_user->roles = ! is_wp_error( $userdata ) ? $userdata->roles : array();
+ }
+
+ return $the_user;
+ }
+
+}
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 bf8d23ea..918349ce 100644
--- a/plugins/jetpack/json-endpoints/jetpack/json-api-jetpack-endpoints.php
+++ b/plugins/jetpack/json-endpoints/jetpack/json-api-jetpack-endpoints.php
@@ -1134,9 +1134,60 @@ new Jetpack_JSON_API_Cron_Unschedule_Endpoint( array(
) );
// BACKUPS
-require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-get-post-backup-endpoint.php' );
+
+// GET /sites/%s/comments/%d/backup
+require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-get-comment-backup-endpoint.php' );
+new Jetpack_JSON_API_Get_Comment_Backup_Endpoint( array(
+ 'description' => 'Fetch a backup of a comment, along with all of its metadata',
+ 'group' => '__do_not_document',
+ 'method' => 'GET',
+ 'path' => '/sites/%s/comments/%d/backup',
+ 'stat' => 'comments:1:backup',
+ 'allow_jetpack_site_auth' => true,
+ 'path_labels' => array(
+ '$site' => '(int|string) The site ID, The site domain',
+ '$post' => '(int) The comment ID',
+ ),
+ 'response_format' => array(
+ 'comment' => '(array) Comment table row',
+ 'meta' => '(array) Associative array of key/value commentmeta data',
+ ),
+ 'example_request_data' => array(
+ 'headers' => array(
+ 'authorization' => 'Bearer YOUR_API_TOKEN'
+ ),
+ ),
+ 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/comments/1/backup'
+) );
+
+// GET /sites/%s/options/backup
+require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-get-option-backup-endpoint.php' );
+new Jetpack_JSON_API_Get_Option_Backup_Endpoint( array(
+ 'description' => 'Fetch a backup of an option',
+ 'group' => '__do_not_document',
+ 'method' => 'GET',
+ 'path' => '/sites/%s/options/backup',
+ 'stat' => 'options:backup',
+ 'allow_jetpack_site_auth' => true,
+ 'path_labels' => array(
+ '$site' => '(int|string) The site ID, The site domain',
+ ),
+ 'query_parameters' => array(
+ 'name' => '(string|array) One or more option names to include in the backup',
+ ),
+ 'response_format' => array(
+ 'options' => '(array) Associative array of option_name => option_value entries',
+ ),
+ 'example_request_data' => array(
+ 'headers' => array(
+ 'authorization' => 'Bearer YOUR_API_TOKEN'
+ )
+ ),
+ 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/options/backup'
+) );
// GET /sites/%s/posts/%d/backup
+require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-get-post-backup-endpoint.php' );
new Jetpack_JSON_API_Get_Post_Backup_Endpoint( array(
'description' => 'Fetch a backup of a post, along with all of its metadata',
'group' => '__do_not_document',
@@ -1159,3 +1210,133 @@ new Jetpack_JSON_API_Get_Post_Backup_Endpoint( array(
),
'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/posts/1/backup'
) );
+
+// GET /sites/%s/terms/%d/backup
+require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-get-term-backup-endpoint.php' );
+new Jetpack_JSON_API_Get_Term_Backup_Endpoint( array(
+ 'description' => 'Fetch a backup of a term, along with all of its metadata',
+ 'group' => '__do_not_document',
+ 'method' => 'GET',
+ 'path' => '/sites/%s/terms/%d/backup',
+ 'stat' => 'terms:1:backup',
+ 'allow_jetpack_site_auth' => true,
+ 'path_labels' => array(
+ '$site' => '(int|string) The site ID, The site domain',
+ '$term' => '(int) The term ID',
+ ),
+ 'response_format' => array(
+ 'term' => '(array) Term table row',
+ 'meta' => '(array) Metadata associated with the term',
+ ),
+ 'example_request_data' => array(
+ 'headers' => array(
+ 'authorization' => 'Bearer YOUR_API_TOKEN'
+ ),
+ ),
+ 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/terms/1/backup'
+) );
+
+// GET /sites/%s/users/%d/backup
+require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-get-user-backup-endpoint.php' );
+new Jetpack_JSON_API_Get_User_Backup_Endpoint( array(
+ 'description' => 'Fetch a backup of a user, along with all of its metadata',
+ 'group' => '__do_not_document',
+ 'method' => 'GET',
+ 'path' => '/sites/%s/users/%d/backup',
+ 'stat' => 'users:1:backup',
+ 'allow_jetpack_site_auth' => true,
+ 'path_labels' => array(
+ '$site' => '(int|string) The site ID, The site domain',
+ '$user' => '(int) The user ID',
+ ),
+ 'response_format' => array(
+ 'user' => '(array) User table row',
+ 'meta' => '(array) Associative array of key/value usermeta data',
+ ),
+ 'example_request_data' => array(
+ 'headers' => array(
+ 'authorization' => 'Bearer YOUR_API_TOKEN'
+ ),
+ ),
+ 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/users/1/backup'
+) );
+
+// USERS
+
+require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-user-connect-endpoint.php' );
+
+// POST /sites/%s/users/%d/connect
+new Jetpack_JSON_API_User_Connect_Endpoint( array(
+ 'description' => 'Creates or returns a new user given profile data',
+ 'group' => '__do_not_document',
+ 'method' => 'POST',
+ 'path' => '/sites/%s/users/%d/connect',
+ 'stat' => 'users:connect',
+ 'allow_jetpack_site_auth' => true,
+ 'path_labels' => array(
+ '$site' => '(int|string) The site ID, The site domain',
+ '$user_id' => '(int) The site user ID to connect',
+ ),
+ 'request_format' => array(
+ 'user_token' => '(string) The user token',
+ ),
+ 'response_format' => array(
+ 'success' => '(bool) Was the user connected',
+ ),
+ 'example_request_data' => array(
+ 'headers' => array(
+ 'authorization' => 'Bearer YOUR_API_TOKEN',
+ ),
+ 'body' => array(
+ 'user_token' => 'XDH55jndskjf3klh3',
+ )
+ ),
+ 'example_response' => '{
+ "success" => true
+ }',
+ 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/users/6/connect'
+) );
+
+require_once( $json_jetpack_endpoints_dir . 'class.jetpack-json-api-user-create-endpoint.php' );
+
+// POST /sites/%s/users/create
+new Jetpack_JSON_API_User_Create_Endpoint( array(
+ 'description' => 'Creates or returns a new user given profile data',
+ 'group' => '__do_not_document',
+ 'method' => 'POST',
+ 'path' => '/sites/%s/users/create',
+ 'stat' => 'users:create',
+ 'allow_jetpack_site_auth' => true,
+ 'path_labels' => array(
+ '$site' => '(int|string) The site ID, The site domain',
+ ),
+ 'request_format' => WPCOM_JSON_API_Site_User_Endpoint::$user_format,
+ 'response_format' => WPCOM_JSON_API_Site_User_Endpoint::$user_format,
+ 'example_request_data' => array(
+ 'headers' => array(
+ 'authorization' => 'Bearer YOUR_API_TOKEN'
+ ),
+ 'body' => array(
+ 'roles' => array(
+ array(
+ 'administrator',
+ )
+ ),
+ 'first_name' => 'John',
+ 'last_name' => 'Doe',
+ 'email' => 'john.doe@example.wordpress.org',
+ )
+ ),
+ 'example_response' => '{
+ "ID": 18342963,
+ "login": "binarysmash"
+ "email": false,
+ "name": "binarysmash",
+ "URL": "http:\/\/binarysmash.wordpress.com",
+ "avatar_URL": "http:\/\/0.gravatar.com\/avatar\/a178ebb1731d432338e6bb0158720fcc?s=96&d=identicon&r=G",
+ "profile_URL": "http:\/\/en.gravatar.com\/binarysmash",
+ "roles": [ "administrator" ]
+ }',
+ 'example_request' => 'https://public-api.wordpress.com/rest/v1/sites/example.wordpress.org/users/create'
+
+) );