diff options
author | Anthony G. Basile <blueness@gentoo.org> | 2016-07-28 23:29:30 -0400 |
---|---|---|
committer | Anthony G. Basile <blueness@gentoo.org> | 2016-07-28 23:29:30 -0400 |
commit | 5c4552fad98db23b2698e8a598bf20f42cb430ef (patch) | |
tree | 61fc1f692646288704376f32d914eeef152e375e /plugins/jetpack/json-endpoints | |
parent | Update plugin jecpack to 4.0.4 (diff) | |
download | blogs-gentoo-5c4552fad98db23b2698e8a598bf20f42cb430ef.tar.gz blogs-gentoo-5c4552fad98db23b2698e8a598bf20f42cb430ef.tar.bz2 blogs-gentoo-5c4552fad98db23b2698e8a598bf20f42cb430ef.zip |
Update plugin jetpack to 4.1.1
Diffstat (limited to 'plugins/jetpack/json-endpoints')
30 files changed, 889 insertions, 709 deletions
diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-comment-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-comment-endpoint.php index 82359f63..d8de1295 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-comment-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-comment-endpoint.php @@ -121,7 +121,7 @@ abstract class WPCOM_JSON_API_Comment_Endpoint extends WPCOM_JSON_API_Endpoint { 'ID' => (int) $post->ID, 'title' => (string) get_the_title( $post->ID ), 'type' => (string) $post->post_type, - 'link' => (string) $this->get_post_link( $this->api->get_blog_id_for_output(), $post->ID ), + 'link' => (string) $this->links->get_post_link( $this->api->get_blog_id_for_output(), $post->ID ), ); break; case 'author' : @@ -155,7 +155,7 @@ abstract class WPCOM_JSON_API_Comment_Endpoint extends WPCOM_JSON_API_Endpoint { $response[$key] = (object) array( 'ID' => (int) $parent->comment_ID, 'type' => (string) ( $parent->comment_type ? $parent->comment_type : 'comment' ), - 'link' => (string) $this->get_comment_link( $blog_id, $parent->comment_ID ), + 'link' => (string) $this->links->get_comment_link( $blog_id, $parent->comment_ID ), ); } else { $response[$key] = false; @@ -177,14 +177,12 @@ abstract class WPCOM_JSON_API_Comment_Endpoint extends WPCOM_JSON_API_Endpoint { case 'meta' : $response[$key] = (object) array( 'links' => (object) array( - 'self' => (string) $this->get_comment_link( $this->api->get_blog_id_for_output(), $comment->comment_ID ), - 'help' => (string) $this->get_comment_link( $this->api->get_blog_id_for_output(), $comment->comment_ID, 'help' ), - 'site' => (string) $this->get_site_link( $this->api->get_blog_id_for_output() ), - 'post' => (string) $this->get_post_link( $this->api->get_blog_id_for_output(), $comment->comment_post_ID ), - 'replies' => (string) $this->get_comment_link( $this->api->get_blog_id_for_output(), $comment->comment_ID, 'replies/' ), -// 'author' => (string) $this->get_user_link( $comment->user_id ), -// 'via' => (string) $this->get_post_link( $ping_origin_blog_id, $ping_origin_post_id ), // Ping/trackbacks - 'likes' => (string) $this->get_comment_link( $this->api->get_blog_id_for_output(), $comment->comment_ID, 'likes/' ), + 'self' => (string) $this->links->get_comment_link( $this->api->get_blog_id_for_output(), $comment->comment_ID ), + 'help' => (string) $this->links->get_comment_link( $this->api->get_blog_id_for_output(), $comment->comment_ID, 'help' ), + 'site' => (string) $this->links->get_site_link( $this->api->get_blog_id_for_output() ), + 'post' => (string) $this->links->get_post_link( $this->api->get_blog_id_for_output(), $comment->comment_post_ID ), + 'replies' => (string) $this->links->get_comment_link( $this->api->get_blog_id_for_output(), $comment->comment_ID, 'replies/' ), + 'likes' => (string) $this->links->get_comment_link( $this->api->get_blog_id_for_output(), $comment->comment_ID, 'likes/' ), ), ); break; 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 517630a6..6f79222a 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,13 +10,19 @@ class WPCOM_JSON_API_Get_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_End $args = $this->query_args(); - if ( false === strpos( $path, '/posts/slug:' ) ) { - $get_by = 'ID'; - } else { - $get_by = 'name'; + if ( false !== strpos( $path, '/posts/slug:' ) ) { + $post_id = $this->get_platform()->get_site( $blog_id )->get_post_id_by_name( $post_id ); + if ( is_wp_error( $post_id ) ) { + return $post_id; + } } - $return = $this->get_post_by( $get_by, $post_id, $args['context'] ); + if ( defined( 'IS_WPCOM' ) && IS_WPCOM && + ! in_array( get_post_type( $post_id ), array( false, 'post', 'page', 'revision' ) ) ) { + $this->load_theme_functions(); + } + + $return = $this->get_post_by( 'ID', $post_id, $args['context'] ); if ( !$return || is_wp_error( $return ) ) { return $return; 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 852b6e89..95a42b41 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 @@ -1,5 +1,4 @@ <?php - class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { public static $site_format = array( @@ -28,6 +27,24 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { 'meta' => '(object) Meta data', ); + protected static $no_member_fields = array( + 'ID', + 'name', + 'description', + 'URL', + 'jetpack', + 'post_count', + 'subscribers_count', + 'lang', + 'locale', + 'icon', + 'logo', + 'visible', + 'is_private', + 'is_following', + 'meta', + ); + protected static $site_options_format = array( 'timezone', 'gmt_offset', @@ -68,21 +85,26 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { 'frame_nonce', 'page_on_front', 'page_for_posts', + 'headstart', 'ak_vp_bundle_enabled' ); - protected static $jetpack_response_field_additions = array( + protected static $jetpack_response_field_additions = array( + 'subscribers_count', + ); + + protected static $jetpack_response_field_member_additions = array( 'capabilities', 'plan', - 'subscribers_count' ); - protected static $jetpack_response_option_additions = array( + protected static $jetpack_response_option_additions = array( 'publicize_permanently_disabled', 'ak_vp_bundle_enabled' ); private $site; + // protected $compact = null; protected $fields_to_include = '_all'; protected $options_to_include = '_all'; @@ -103,6 +125,11 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { return $blog_id; } + // TODO: enable this when we can do so without being interfered with by + // other endpoints that might be wrapping this one. + // Uncomment and see failing test: test_jetpack_site_should_have_true_jetpack_property_via_site_meta + // $this->filter_fields_and_options(); + $response = $this->build_current_site_response(); /** This action is documented in json-endpoints/class.wpcom-json-api-site-settings-endpoint.php */ @@ -118,40 +145,36 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { $this->options_to_include = empty( $query_args['options'] ) ? '_all' : array_map( 'trim', explode( ',', $query_args['options'] ) ); } - protected function include_response_field( $field ) { - if ( is_array( $this->fields_to_include ) ) { - return in_array( $field, $this->fields_to_include ); - } - return true; - } - /** * Collects the necessary information to return for a site's response. * * @return (array) */ public function build_current_site_response() { + $blog_id = (int) $this->api->get_blog_id_for_output(); - $this->site = wpcom_get_sal_site( $blog_id ); + $this->site = $this->get_platform()->get_site( $blog_id ); - // Allow update in later versions /** - * Filter the structure of information about the site to return. - * - * @module json-api - * - * @since 3.9.3 - * - * @param array $site_format Data structure. - */ - $response_format = apply_filters( 'sites_site_format', self::$site_format ); + * Filter the structure of information about the site to return. + * + * @module json-api + * + * @since 3.9.3 + * + * @param array $site_format Data structure. + */ $default_fields = array_keys( apply_filters( 'sites_site_format', self::$site_format ) ); $response_keys = is_array( $this->fields_to_include ) ? array_intersect( $default_fields, $this->fields_to_include ) : $default_fields; + if ( ! is_user_member_of_blog( get_current_user(), $blog_id ) ) { + $response_keys = array_intersect( $response_keys, self::$no_member_fields ); + } + return $this->render_response_keys( $response_keys ); } @@ -179,13 +202,13 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { $response[ $key ] = $this->site->blog_id; break; case 'name' : - $response[ $key ] = (string) htmlspecialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ); + $response[ $key ] = $this->site->get_name(); break; case 'description' : - $response[ $key ] = (string) htmlspecialchars_decode( get_bloginfo( 'description' ), ENT_QUOTES ); + $response[ $key ] = $this->site->get_description(); break; case 'URL' : - $response[ $key ] = (string) home_url(); + $response[ $key ] = $this->site->get_url(); break; case 'user_can_manage' : $response[ $key ] = $this->site->user_can_manage(); @@ -200,7 +223,7 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { break; case 'post_count' : if ( $is_user_logged_in ) { - $response[ $key ] = (int) wp_count_posts( 'post' )->publish; + $response[ $key ] = $this->site->get_post_count(); } break; case 'icon' : @@ -217,7 +240,7 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { $response[ $key ] = $this->site->is_following(); break; case 'options': - // small optimisation - don't recalculate + // small optimisation - don't recalculate $all_options = apply_filters( 'sites_site_options_format', self::$site_options_format ); $options_response_keys = is_array( $this->options_to_include ) ? @@ -228,7 +251,7 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { $this->site->after_render_options( $options ); - $response[ $key ] = $options; + $response[ $key ] = (object) $options; break; case 'meta': $this->build_meta_response( $response ); @@ -242,16 +265,16 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { case 'jetpack' : $response[ $key ] = $this->site->is_jetpack(); break; - case 'single_user_site' : + case 'single_user_site' : $response[ $key ] = $this->site->is_single_user_site(); break; - case 'is_vip' : + case 'is_vip' : $response[ $key ] = $this->site->is_vip(); break; case 'is_multisite' : $response[ $key ] = $this->site->is_multisite(); break; - case 'capabilities' : + case 'capabilities' : $response[ $key ] = $this->site->get_capabilities(); break; case 'jetpack_modules': @@ -270,148 +293,141 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { protected function render_option_keys( &$options_response_keys ) { if ( ! current_user_can( 'edit_posts' ) ) { - return; + return array(); } - global $wp_version; - $options = array(); + $site = $this->site; - $custom_front_page = ( 'page' === get_option( 'show_on_front' ) ); + $custom_front_page = $site->is_custom_front_page(); + foreach ( $options_response_keys as $key ) { switch ( $key ) { case 'timezone' : - $options[ $key ] = (string) get_option( 'timezone_string' ); + $options[ $key ] = $site->get_timezone(); break; case 'gmt_offset' : - $options[ $key ] = (float) get_option( 'gmt_offset' ); + $options[ $key ] = $site->get_gmt_offset(); break; case 'videopress_enabled' : - $options[ $key ] = $this->site->has_videopress(); + $options[ $key ] = $site->has_videopress(); break; case 'upgraded_filetypes_enabled' : - $options[ $key ] = $this->site->upgraded_filetypes_enabled(); + $options[ $key ] = $site->upgraded_filetypes_enabled(); break; case 'login_url' : - $options[ $key ] = wp_login_url(); + $options[ $key ] = $site->get_login_url(); break; case 'admin_url' : - $options[ $key ] = get_admin_url(); + $options[ $key ] = $site->get_admin_url(); break; case 'is_mapped_domain' : - $options[ $key ] = $this->site->is_mapped_domain(); + $options[ $key ] = $site->is_mapped_domain(); break; case 'is_redirect' : - $options[ $key ] = $this->site->is_redirect(); + $options[ $key ] = $site->is_redirect(); break; case 'unmapped_url' : - $options[ $key ] = get_site_url( $this->site->blog_id ); + $options[ $key ] = $site->get_unmapped_url(); break; case 'featured_images_enabled' : - $options[ $key ] = $this->site->featured_images_enabled(); + $options[ $key ] = $site->featured_images_enabled(); break; case 'theme_slug' : - $options[ $key ] = get_option( 'stylesheet' ); + $options[ $key ] = $site->get_theme_slug(); break; case 'header_image' : - $options[ $key ] = get_theme_mod( 'header_image_data' ); + $options[ $key ] = $site->get_header_image(); break; case 'background_color' : - $options[ $key ] = get_theme_mod( 'background_color' ); + $options[ $key ] = $site->get_background_color(); break; case 'image_default_link_type' : - $options[ $key ] = get_option( 'image_default_link_type' ); + $options[ $key ] = $site->get_image_default_link_type(); break; case 'image_thumbnail_width' : - $options[ $key ] = (int) get_option( 'thumbnail_size_w' ); + $options[ $key ] = $site->get_image_thumbnail_width(); break; case 'image_thumbnail_height' : - $options[ $key ] = (int) get_option( 'thumbnail_size_h' ); + $options[ $key ] = $site->get_image_thumbnail_height(); break; case 'image_thumbnail_crop' : - $options[ $key ] = get_option( 'thumbnail_crop' ); + $options[ $key ] = $site->get_image_thumbnail_crop(); break; case 'image_medium_width' : - $options[ $key ] = (int) get_option( 'medium_size_w' ); + $options[ $key ] = $site->get_image_medium_width(); break; case 'image_medium_height' : - $options[ $key ] = (int) get_option( 'medium_size_h' ); + $options[ $key ] = $site->get_image_medium_height(); break; case 'image_large_width' : - $options[ $key ] = (int) get_option( 'large_size_w' ); + $options[ $key ] = $site->get_image_large_width(); break; case 'image_large_height' : - $options[ $key ] = (int) get_option( 'large_size_h' ); + $options[ $key ] = $site->get_image_large_height(); break; case 'permalink_structure' : - $options[ $key ] = get_option( 'permalink_structure' ); + $options[ $key ] = $site->get_permalink_structure(); break; case 'post_formats' : - $options[ $key ] = $this->site->get_post_formats(); + $options[ $key ] = $site->get_post_formats(); break; case 'default_post_format' : - $options[ $key ] = get_option( 'default_post_format' ); + $options[ $key ] = $site->get_default_post_format(); break; case 'default_category' : - $options[ $key ] = (int) get_option( 'default_category' ); + $options[ $key ] = $site->get_default_category(); break; case 'allowed_file_types' : - $options[ $key ] = $this->site->allowed_file_types(); + $options[ $key ] = $site->allowed_file_types(); break; case 'show_on_front' : - $options[ $key ] = get_option( 'show_on_front' ); + $options[ $key ] = $site->get_show_on_front(); break; /** This filter is documented in modules/likes.php */ case 'default_likes_enabled' : - $options[ $key ] = (bool) apply_filters( 'wpl_is_enabled_sitewide', ! get_option( 'disabled_likes' ) ); + $options[ $key ] = $site->get_default_likes_enabled(); break; case 'default_sharing_status' : - $default_sharing_status = false; - if ( class_exists( 'Sharing_Service' ) ) { - $ss = new Sharing_Service(); - $blog_services = $ss->get_blog_services(); - $default_sharing_status = ! empty( $blog_services['visible'] ); - } - $options[ $key ] = (bool) $default_sharing_status; + $options[ $key ] = $site->get_default_sharing_status(); break; case 'default_comment_status' : - $options[ $key ] = 'closed' !== get_option( 'default_comment_status' ); + $options[ $key ] = $site->get_default_comment_status(); break; case 'default_ping_status' : - $options[ $key ] = 'closed' !== get_option( 'default_ping_status' ); + $options[ $key ] = $site->default_ping_status(); break; case 'software_version' : - $options[ $key ] = $wp_version; + $options[ $key ] = $site->get_wordpress_version(); break; case 'created_at' : - $options[ $key ] = $this->site->get_registered_date(); + $options[ $key ] = $site->get_registered_date(); break; case 'wordads' : - $options[ $key ] = $this->site->has_wordads(); + $options[ $key ] = $site->has_wordads(); break; case 'publicize_permanently_disabled' : - $publicize_permanently_disabled = false; - if ( function_exists( 'is_publicize_permanently_disabled' ) ) { - $publicize_permanently_disabled = is_publicize_permanently_disabled( $this->site->blog_id ); - } - $options[ $key ] = $publicize_permanently_disabled; + $options[ $key ] = $site->is_publicize_permanently_disabled(); break; case 'frame_nonce' : - $options[ $key ] = $this->site->get_frame_nonce(); + $options[ $key ] = $site->get_frame_nonce(); break; case 'page_on_front' : if ( $custom_front_page ) { - $options[ $key ] = (int) get_option( 'page_on_front' ); + $options[ $key ] = $site->get_page_on_front(); } break; case 'page_for_posts' : if ( $custom_front_page ) { - $options[ $key ] = (int) get_option( 'page_for_posts' ); + $options[ $key ] = $site->get_page_for_posts(); } break; + case 'headstart' : + $options[ $key ] = $site->is_headstart(); + break; case 'ak_vp_bundle_enabled' : - $options[ $key ] = $this->site->get_ak_vp_bundle_enabled(); + $options[ $key ] = $site->get_ak_vp_bundle_enabled(); } } @@ -419,22 +435,20 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { } protected function build_meta_response( &$response ) { - $xmlrpc_scheme = apply_filters( 'wpcom_json_api_xmlrpc_scheme', parse_url( get_option( 'home' ), PHP_URL_SCHEME ) ); - $xmlrpc_url = site_url( 'xmlrpc.php', $xmlrpc_scheme ); $response['meta'] = (object) array( 'links' => (object) array( - 'self' => (string) $this->get_site_link( $this->site->blog_id ), - 'help' => (string) $this->get_site_link( $this->site->blog_id, 'help' ), - 'posts' => (string) $this->get_site_link( $this->site->blog_id, 'posts/' ), - 'comments' => (string) $this->get_site_link( $this->site->blog_id, 'comments/' ), - 'xmlrpc' => (string) $xmlrpc_url, + 'self' => (string) $this->links->get_site_link( $this->site->blog_id ), + 'help' => (string) $this->links->get_site_link( $this->site->blog_id, 'help' ), + 'posts' => (string) $this->links->get_site_link( $this->site->blog_id, 'posts/' ), + 'comments' => (string) $this->links->get_site_link( $this->site->blog_id, 'comments/' ), + 'xmlrpc' => (string) $this->site->get_xmlrpc_url(), ), ); } // apply any WPCOM-only response components to a Jetpack site response public function decorate_jetpack_response( &$response ) { - $this->site = wpcom_get_sal_site( $blog_id ); + $this->site = $this->get_platform()->get_site( $response->ID ); // ensure the response is marked as being from Jetpack $response->jetpack = true; @@ -445,14 +459,32 @@ class WPCOM_JSON_API_GET_Site_Endpoint extends WPCOM_JSON_API_Endpoint { $response->{ $key } = $value; } + if ( is_user_member_of_blog( get_current_user(), $response->ID ) ) { + $wpcom_member_response = $this->render_response_keys( self::$jetpack_response_field_member_additions ); + + foreach( $wpcom_member_response as $key => $value ) { + $response->{ $key } = $value; + } + } else { + // ensure private data is not rendered for non members of the site + unset( $response->options ); + unset( $response->is_vip ); + unset( $response->single_user_site ); + unset( $response->is_private ); + unset( $response->capabilities ); + unset( $response->lang ); + unset( $response->user_can_manage ); + unset( $response->is_multisite ); + unset( $response->plan ); + } + // render additional options if ( $response->options ) { $wpcom_options_response = $this->render_option_keys( self::$jetpack_response_option_additions ); - foreach( $wpcom_options_response as $key => $value ) { + foreach ( $wpcom_options_response as $key => $value ) { $response->options[ $key ] = $value; } - return (string) get_bloginfo( 'language' ); } 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 6f693e91..898df417 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,11 +1,4 @@ <?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_GET_Site_V1_2_Endpoint extends WPCOM_JSON_API_GET_Site_Endpoint { public static $site_format = array( @@ -13,7 +6,9 @@ class WPCOM_JSON_API_GET_Site_V1_2_Endpoint extends WPCOM_JSON_API_GET_Site_Endp 'name' => '(string) Title of site', 'description' => '(string) Tagline or description of site', 'URL' => '(string) Full URL to the site', + 'capabilities' => '(array) Array of capabilities for the current user on this site.', 'jetpack' => '(bool) Whether the site is a Jetpack site or not', + 'is_multisite' => '(bool) Whether the site is a Multisite site or not. Always true for WP.com sites.', 'post_count' => '(int) The number of posts the site has', 'subscribers_count' => '(int) The number of subscribers the site has', 'locale' => '(string) Primary locale code of the site', @@ -21,31 +16,23 @@ class WPCOM_JSON_API_GET_Site_V1_2_Endpoint extends WPCOM_JSON_API_GET_Site_Endp 'logo' => '(array) The site logo, set in the Customizer', 'visible' => '(bool) If this site is visible in the user\'s site list', 'is_private' => '(bool) If the site is a private site or not', + 'single_user_site' => '(bool) Whether the site is single user. Only returned for WP.com sites and for Jetpack sites with version 3.4 or higher.', + 'is_vip' => '(bool) If the site is a VIP site or not.', 'is_following' => '(bool) If the current user is subscribed to this site in the reader', 'options' => '(array) An array of options/settings for the blog. Only viewable by users with post editing rights to the site. Note: Post formats is deprecated, please see /sites/$id/post-formats/', + 'plan' => '(array) Details of the current plan for this site.', 'updates' => '(array) An array of available updates for plugins, themes, wordpress, and languages.', 'jetpack_modules' => '(array) A list of active Jetpack modules.', 'meta' => '(object) Meta data', ); + function callback( $path = '', $blog_id = 0 ) { add_filter( 'sites_site_format', array( $this, 'site_format' ) ); return parent::callback( $path, $blog_id ); } - //V1.2 renames lang to locale - protected function process_locale( $key, $is_user_logged_in ) { - if ( $is_user_logged_in && 'locale' == $key ) { - if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { - if ( ! is_jetpack_site() ) { - return (string) get_blog_lang_code(); - } - } - } - return false; - } - public function site_format( $format ) { return self::$site_format; } diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-term-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-term-endpoint.php new file mode 100644 index 00000000..fcb9a6f7 --- /dev/null +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-get-term-endpoint.php @@ -0,0 +1,38 @@ +<?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_Get_Term_Endpoint extends WPCOM_JSON_API_Endpoint { + // /sites/%s/taxonomies/%s/terms/slug:%s -> $blog_id, $taxonomy, $slug + function callback( $path = '', $blog_id = 0, $taxonomy = 'category', $slug = 0 ) { + $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) ); + if ( is_wp_error( $blog_id ) ) { + return $blog_id; + } + + if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { + $this->load_theme_functions(); + } + + $taxonomy_meta = get_taxonomy( $taxonomy ); + if ( false === $taxonomy_meta || ( ! $taxonomy_meta->public && + ! current_user_can( $taxonomy_meta->cap->assign_terms ) ) ) { + return new WP_Error( 'invalid_taxonomy', 'The taxonomy does not exist', 400 ); + } + + $args = $this->query_args(); + $term = $this->get_taxonomy( $slug, $taxonomy, $args['context'] ); + if ( ! $term || is_wp_error( $term ) ) { + return $term; + } + + /** This action is documented in json-endpoints/class.wpcom-json-api-site-settings-endpoint.php */ + do_action( 'wpcom_json_api_objects', 'terms' ); + + return $term; + } +} diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-comments-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-comments-endpoint.php index 9b80601d..cdb0d466 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-comments-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-comments-endpoint.php @@ -229,7 +229,9 @@ class WPCOM_JSON_API_List_Comments_Endpoint extends WPCOM_JSON_API_Comment_Endpo if ( $args['hierarchical'] ) { $walker = new WPCOM_JSON_API_List_Comments_Walker; $comment_ids = $walker->paged_walk( $comments, get_option( 'thread_comments_depth', -1 ), isset( $args['page'] ) ? $args['page'] : 1 , $args['number'] ); - $comments = array_map( 'get_comment', $comment_ids ); + if ( ! empty( $comment_ids ) ) { + $comments = array_map( 'get_comment', $comment_ids ); + } } $return = array(); @@ -244,10 +246,12 @@ class WPCOM_JSON_API_List_Comments_Endpoint extends WPCOM_JSON_API_Comment_Endpo break; case 'comments' : $return_comments = array(); - foreach ( $comments as $comment ) { - $the_comment = $this->get_comment( $comment->comment_ID, $args['context'] ); - if ( $the_comment && !is_wp_error( $the_comment ) ) { - $return_comments[] = $the_comment; + if ( ! empty( $comments ) ) { + foreach ( $comments as $comment ) { + $the_comment = $this->get_comment( $comment->comment_ID, $args['context'] ); + if ( $the_comment && !is_wp_error( $the_comment ) ) { + $return_comments[] = $the_comment; + } } } diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-embeds-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-embeds-endpoint.php index e5cfd7f3..35efd1d3 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-embeds-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-embeds-endpoint.php @@ -36,4 +36,4 @@ class WPCOM_JSON_API_List_Embeds_Endpoint extends WPCOM_JSON_API_Endpoint { return $output; } -} +}
\ No newline at end of file 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 a5b2354c..fc2e479a 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 @@ -40,7 +40,6 @@ class WPCOM_JSON_API_List_Media_v1_1_Endpoint extends WPCOM_JSON_API_Endpoint { 'post_type' => 'attachment', 'post_status' => 'inherit', 'post_parent' => isset( $args['post_ID'] ) ? $args['post_ID'] : null, - 'offset' => isset( $args['offset'] ) ? $args['offset'] : null, 'posts_per_page' => $args['number'], 'post_mime_type' => isset( $args['mime_type'] ) ? $args['mime_type'] : null, 'order' => isset( $args['order'] ) ? $args['order'] : 'DESC', diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-post-type-taxonomies-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-post-type-taxonomies-endpoint.php new file mode 100644 index 00000000..be037134 --- /dev/null +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-post-type-taxonomies-endpoint.php @@ -0,0 +1,71 @@ +<?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_Post_Type_Taxonomies_Endpoint extends WPCOM_JSON_API_Endpoint { + static $taxonomy_keys_to_include = array( + 'name' => 'name', + 'label' => 'label', + 'labels' => 'labels', + 'description' => 'description', + 'hierarchical' => 'hierarchical', + 'public' => 'public', + 'cap' => 'capabilities', + ); + + // /sites/%s/post-types/%s/taxonomies -> $blog_id, $post_type + function callback( $path = '', $blog_id = 0, $post_type = 'post' ) { + $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) ); + if ( is_wp_error( $blog_id ) ) { + return $blog_id; + } + + if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { + $this->load_theme_functions(); + } + + /** This filter is documented in jetpack/json-endpoints/class.wpcom-json-api-list-post-types-endpoint.php */ + if ( apply_filters( 'rest_api_localize_response', false ) ) { + // API localization occurs after the initial taxonomies have been + // registered, so re-register if localizing response + create_initial_taxonomies(); + } + + $args = $this->query_args(); + + $post_type_object = get_post_type_object( $post_type ); + if ( ! $post_type_object || ( ! $post_type_object->publicly_queryable && ( + ! current_user_can( $post_type_object->cap->edit_posts ) ) ) ) { + return new WP_Error( 'unknown_post_type', 'Unknown post type', 404 ); + } + + // Get a list of available taxonomies + $taxonomy_objects = get_object_taxonomies( $post_type, 'objects' ); + + // Construct array of formatted objects + $formatted_taxonomy_objects = array(); + foreach ( $taxonomy_objects as $taxonomy_object ) { + // Omit private taxonomies unless user has assign capability + if ( ! $taxonomy_object->public && ! current_user_can( $taxonomy_object->cap->assign_terms ) ) { + continue; + } + + // Include only the desired keys in the response + $formatted_taxonomy_object = array(); + foreach ( self::$taxonomy_keys_to_include as $key => $value ) { + $formatted_taxonomy_object[ $value ] = $taxonomy_object->{ $key }; + } + + $formatted_taxonomy_objects[] = $formatted_taxonomy_object; + } + + return array( + 'found' => count( $formatted_taxonomy_objects ), + 'taxonomies' => $formatted_taxonomy_objects, + ); + } +} diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-post-types-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-post-types-endpoint.php index e7521abe..c18719f0 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-post-types-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-post-types-endpoint.php @@ -8,6 +8,7 @@ class WPCOM_JSON_API_List_Post_Types_Endpoint extends WPCOM_JSON_API_Endpoint { 'description' => 'description', 'map_meta_cap' => 'map_meta_cap', 'cap' => 'capabilities', + 'hierarchical' => 'hierarchical', ); // /sites/%s/post-types -> $blog_id @@ -23,9 +24,15 @@ class WPCOM_JSON_API_List_Post_Types_Endpoint extends WPCOM_JSON_API_Endpoint { $args = $this->query_args(); - // API localization occurs after the initial post types have been - // registered, so re-register if localizing response + /** + * Whether API responses should be returned in a custom locale. False + * for Jetpack; may be true for WP.com requests. + * + * @since 3.9.2 + */ if ( apply_filters( 'rest_api_localize_response', false ) ) { + // API localization occurs after the initial post types have been + // registered, so re-register if localizing response create_initial_post_types(); } 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 ca1c5a10..1ab369f0 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 @@ -104,7 +104,7 @@ class WPCOM_JSON_API_List_Posts_Endpoint extends WPCOM_JSON_API_Post_Endpoint { if ( isset( $args['meta_key'] ) ) { $show = false; - if ( $this->is_metadata_public( $args['meta_key'] ) ) + if ( WPCOM_JSON_API_Metadata::is_public( $args['meta_key'] ) ) $show = true; if ( current_user_can( 'edit_post_meta', $query['post_type'], $args['meta_key'] ) ) $show = true; 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 1f009365..61953a1f 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 @@ -115,7 +115,7 @@ class WPCOM_JSON_API_List_Posts_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_E if ( isset( $args['meta_key'] ) ) { $show = false; - if ( $this->is_metadata_public( $args['meta_key'] ) ) + if ( WPCOM_JSON_API_Metadata::is_public( $args['meta_key'] ) ) $show = true; if ( current_user_can( 'edit_post_meta', $query['post_type'], $args['meta_key'] ) ) $show = true; @@ -296,7 +296,7 @@ class WPCOM_JSON_API_List_Posts_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_E if ( ! is_array( $args['type'] ) ) { $return[$key] = (object) array( 'links' => (object) array( - 'counts' => (string) $this->get_site_link( $blog_id, 'post-counts/' . $args['type'] ), + 'counts' => (string) $this->links->get_site_link( $blog_id, 'post-counts/' . $args['type'] ), ) ); } diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-shortcodes-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-shortcodes-endpoint.php index 28a42350..9b2fc1aa 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-shortcodes-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-shortcodes-endpoint.php @@ -19,9 +19,9 @@ class WPCOM_JSON_API_List_Shortcodes_Endpoint extends WPCOM_JSON_API_Endpoint { foreach ( $shortcode_tags as $tag => $class ) { if ( '__return_false' == $class ) continue; - $output['shortcodes'][] = $tag; + $output['shortcodes'][] = $tag; } return $output; } -} +}
\ No newline at end of file diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-terms-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-terms-endpoint.php new file mode 100644 index 00000000..c015e34a --- /dev/null +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-terms-endpoint.php @@ -0,0 +1,87 @@ +<?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_Terms_Endpoint extends WPCOM_JSON_API_Endpoint { + // /sites/%s/taxonomies/%s/terms -> $blog_id, $taxonomy + function callback( $path = '', $blog_id = 0, $taxonomy = 'category' ) { + $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) ); + if ( is_wp_error( $blog_id ) ) { + return $blog_id; + } + + if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { + $this->load_theme_functions(); + } + + $taxonomy_meta = get_taxonomy( $taxonomy ); + if ( false === $taxonomy_meta || ( ! $taxonomy_meta->public && + ! current_user_can( $taxonomy_meta->cap->assign_terms ) ) ) { + return new WP_Error( 'invalid_taxonomy', 'The taxonomy does not exist', 400 ); + } + + $args = $this->query_args(); + $args = $this->process_args( $args ); + + $formatted_terms = $this->get_formatted_terms( $taxonomy, $args ); + + if ( ! empty( $formatted_terms ) ) { + /** This action is documented in json-endpoints/class.wpcom-json-api-site-settings-endpoint.php */ + do_action( 'wpcom_json_api_objects', 'terms', count( $formatted_terms ) ); + } + + return array( + 'found' => (int) $this->get_found( $taxonomy, $args ), + 'terms' => (array) $formatted_terms + ); + } + + function process_args( $args ) { + $args['get'] = 'all'; + + if ( $args['number'] < 1 ) { + $args['number'] = 100; + } elseif ( 1000 < $args['number'] ) { + return new WP_Error( 'invalid_number', 'The number parameter must be less than or equal to 1000.', 400 ); + } + + if ( isset( $args['page'] ) ) { + if ( $args['page'] < 1 ) { + $args['page'] = 1; + } + + $args['offset'] = ( $args['page'] - 1 ) * $args['number']; + unset( $args['page'] ); + } + + if ( $args['offset'] < 0 ) { + $args['offset'] = 0; + } + + $args['orderby'] = $args['order_by']; + unset( $args['order_by'] ); + + unset( $args['context'], $args['pretty'], $args['http_envelope'], $args['fields'] ); + return $args; + } + + function get_found( $taxonomy, $args ) { + unset( $args['offset'] ); + return wp_count_terms( $taxonomy, $args ); + } + + function get_formatted_terms( $taxonomy, $args ) { + $terms = get_terms( $taxonomy, $args ); + + $formatted_terms = array(); + foreach ( $terms as $term ) { + $formatted_terms[] = $this->format_taxonomy( $term, $taxonomy, 'display' ); + } + + return $formatted_terms; + } +} diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-users-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-users-endpoint.php index 225bfa0a..fe658f99 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-users-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-list-users-endpoint.php @@ -19,13 +19,14 @@ class WPCOM_JSON_API_List_Users_Endpoint extends WPCOM_JSON_API_Endpoint { 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 ); + } elseif ( 1000 < $args['number'] ) { + return new WP_Error( 'invalid_number', 'The NUMBER parameter must be less than or equal to 1000.', 400 ); } if ( $authors_only ) { - if ( empty( $args['type'] ) ) + if ( empty( $args['type'] ) ) { $args['type'] = 'post'; + } if ( ! $this->is_post_type_allowed( $args['type'] ) ) { return new WP_Error( 'unknown_post_type', 'Unknown post type', 404 ); @@ -47,8 +48,9 @@ class WPCOM_JSON_API_List_Users_Endpoint extends WPCOM_JSON_API_Endpoint { 'fields' => 'ID', ); - if ( $authors_only ) + if ( $authors_only ) { $query['who'] = 'authors'; + } if ( ! empty( $args['search'] ) ) { $query['search'] = $args['search']; @@ -72,7 +74,7 @@ class WPCOM_JSON_API_List_Users_Endpoint extends WPCOM_JSON_API_Endpoint { foreach ( array_keys( $this->response_format ) as $key ) { switch ( $key ) { case 'found' : - $return[$key] = (int) $user_query->get_total(); + $return[ $key ] = (int) $user_query->get_total(); break; case 'users' : $users = array(); @@ -89,7 +91,7 @@ class WPCOM_JSON_API_List_Users_Endpoint extends WPCOM_JSON_API_Endpoint { } } - $return[$key] = $users; + $return[ $key ] = $users; break; } } diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-menus-v1-1-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-menus-v1-1-endpoint.php index c77ce8d3..fe61e71a 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-menus-v1-1-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-menus-v1-1-endpoint.php @@ -454,11 +454,14 @@ class WPCOM_JSON_API_Menus_Complexify extends WPCOM_JSON_API_Menus_Translator { protected function location_name_exists( $location_name ) { $widget_location_names = wp_list_pluck( WPCOM_JSON_API_Menus_Widgets::get(), 'name' ); + $existing_locations = get_nav_menu_locations(); + if ( ! is_array( get_registered_nav_menus() ) ) { return false; } return array_key_exists( $location_name, get_registered_nav_menus() ) || + array_key_exists( $location_name, $existing_locations ) || in_array( $location_name, $widget_location_names ); } 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 9dc1a1fa..d28d9697 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 @@ -272,7 +272,7 @@ abstract class WPCOM_JSON_API_Post_Endpoint extends WPCOM_JSON_API_Endpoint { $response[$key] = (object) array( 'ID' => (int) $parent->ID, 'type' => (string) $parent->post_type, - 'link' => (string) $this->get_post_link( $this->api->get_blog_id_for_output(), $parent->ID ), + 'link' => (string) $this->links->get_post_link( $this->api->get_blog_id_for_output(), $parent->ID ), 'title' => $parent_title, ); } else { @@ -443,7 +443,7 @@ abstract class WPCOM_JSON_API_Post_Endpoint extends WPCOM_JSON_API_Endpoint { foreach ( (array) has_meta( $post_id ) as $meta ) { // Don't expose protected fields. $show = false; - if ( $this->is_metadata_public( $meta['meta_key'] ) ) + if ( WPCOM_JSON_API_Metadata::is_public( $meta['meta_key'] ) ) $show = true; if ( current_user_can( 'edit_post_meta', $post_id , $meta['meta_key'] ) ) $show = true; @@ -467,13 +467,11 @@ abstract class WPCOM_JSON_API_Post_Endpoint extends WPCOM_JSON_API_Endpoint { case 'meta' : $response[$key] = (object) array( 'links' => (object) array( - 'self' => (string) $this->get_post_link( $this->api->get_blog_id_for_output(), $post->ID ), - 'help' => (string) $this->get_post_link( $this->api->get_blog_id_for_output(), $post->ID, 'help' ), - 'site' => (string) $this->get_site_link( $this->api->get_blog_id_for_output() ), -// 'author' => (string) $this->get_user_link( $post->post_author ), -// 'via' => (string) $this->get_post_link( $reblog_origin_blog_id, $reblog_origin_post_id ), - 'replies' => (string) $this->get_post_link( $this->api->get_blog_id_for_output(), $post->ID, 'replies/' ), - 'likes' => (string) $this->get_post_link( $this->api->get_blog_id_for_output(), $post->ID, 'likes/' ), + 'self' => (string) $this->links->get_post_link( $this->api->get_blog_id_for_output(), $post->ID ), + 'help' => (string) $this->links->get_post_link( $this->api->get_blog_id_for_output(), $post->ID, 'help' ), + 'site' => (string) $this->links->get_site_link( $this->api->get_blog_id_for_output() ), + 'replies' => (string) $this->links->get_post_link( $this->api->get_blog_id_for_output(), $post->ID, 'replies/' ), + 'likes' => (string) $this->links->get_post_link( $this->api->get_blog_id_for_output(), $post->ID, 'likes/' ), ), ); break; @@ -665,7 +663,11 @@ abstract class WPCOM_JSON_API_Post_Endpoint extends WPCOM_JSON_API_Endpoint { return new WP_Error( 'invalid_post', 'Invalid post', 400 ); } - $posts = get_posts( array( 'name' => $name ) ); + $posts = get_posts( array( + 'name' => $name, + 'numberposts' => 1, + 'post_type' => $this->_get_whitelisted_post_types(), + ) ); if ( ! $posts || ! isset( $posts[0]->ID ) || ! $posts[0]->ID ) { $page = get_page_by_path( $name ); 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 30783d14..93dade64 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 @@ -43,6 +43,7 @@ abstract class WPCOM_JSON_API_Post_v1_1_Endpoint extends WPCOM_JSON_API_Endpoint 'menu_order' => '(int) (Pages Only) The order pages should appear in.', 'page_template' => '(string) (Pages Only) The page template this page is using.', 'publicize_URLs' => '(array:URL) Array of Twitter and Facebook URLs published by this post.', + 'terms' => '(object) Hash of taxonomy names mapping to a hash of terms keyed by term name.', 'tags' => '(object:tag) Hash of tags (keyed by tag name) applied to the post.', 'categories' => '(object:category) Hash of categories (keyed by category name) applied to the post.', 'attachments' => '(object:attachment) Hash of post attachments (keyed by attachment ID). Returns the most recent 20 attachments. Use the `/sites/$site/media` endpoint to query the attachments beyond the default of 20 that are returned here.', @@ -66,31 +67,6 @@ abstract class WPCOM_JSON_API_Post_v1_1_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' ); - - // whitelist of metadata that can be accessed - /** This filter is documented in json-endpoints/class.wpcom-json-api-post-endpoint.php */ - 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' ); - } - /** * Get a post by a specified field and value * @@ -100,15 +76,14 @@ abstract class WPCOM_JSON_API_Post_v1_1_Endpoint extends WPCOM_JSON_API_Endpoint * @return array Post **/ function get_post_by( $field, $field_value, $context = 'display' ) { - global $blog_id; - /** This filter is documented in class.json-api-endpoints.php */ - $is_jetpack = true === apply_filters( 'is_jetpack_site', false, $blog_id ); + // validate input + if ( ! in_array( $field, array( 'ID', 'name' ) ) ) { + return new WP_Error( 'invalid_field', 'Invalid API FIELD', 400 ); + } - if ( defined( 'GEO_LOCATION__CLASS' ) && class_exists( GEO_LOCATION__CLASS ) ) { - $geo = call_user_func( array( GEO_LOCATION__CLASS, 'init' ) ); - } else { - $geo = false; + if ( ! in_array( $context, array( 'display', 'edit' ) ) ) { + return new WP_Error( 'invalid_context', 'Invalid API CONTEXT', 400 ); } if ( 'display' === $context ) { @@ -123,415 +98,178 @@ abstract class WPCOM_JSON_API_Post_v1_1_Endpoint extends WPCOM_JSON_API_Endpoint add_shortcode( 'gallery', array( &$this, 'win8_gallery_shortcode' ) ); } - switch ( $field ) { - case 'name' : - $post_id = $this->get_post_id_by_name( $field_value ); - if ( is_wp_error( $post_id ) ) { - return $post_id; - } - break; - default : - $post_id = (int) $field_value; - break; - } + // fetch SAL post + $post = $this->get_sal_post_by( $field, $field_value, $context ); - $post = get_post( $post_id, OBJECT, $context ); + if ( is_wp_error( $post ) ) { + return $post; + } - if ( !$post || is_wp_error( $post ) ) { - return new WP_Error( 'unknown_post', 'Unknown post', 404 ); - } + $GLOBALS['post'] = $post; - if ( ! $this->is_post_type_allowed( $post->post_type ) && ( ! function_exists( 'is_post_freshly_pressed' ) || ! is_post_freshly_pressed( $post->ID ) ) ) { - return new WP_Error( 'unknown_post', 'Unknown post', 404 ); + // TODO: not sure where this one should go + if ( 'display' === $context ) { + setup_postdata( $post ); } - // Permissions - $capabilities = $this->get_current_user_capabilities( $post ); + $response = $this->render_response_keys( $post, $context, array_keys( $this->post_object_format ) ); - switch ( $context ) { - case 'edit' : - if ( ! $capabilities['edit_post'] ) { - return new WP_Error( 'unauthorized', 'User cannot edit post', 403 ); - } - break; - case 'display' : - break; - default : - return new WP_Error( 'invalid_context', 'Invalid API CONTEXT', 400 ); - } + unset( $GLOBALS['post'] ); - $can_view = $this->user_can_view_post( $post->ID ); - if ( !$can_view || is_wp_error( $can_view ) ) { - return $can_view; - } + return $response; + } - $GLOBALS['post'] = $post; + protected function get_sal_post_by( $field, $field_value, $context ) { + global $blog_id; - if ( 'display' === $context ) { - setup_postdata( $post ); - } + $site = $this->get_platform()->get_site( $blog_id ); + + $post = ( $field === 'name' ) ? + $site->get_post_by_name( $field_value, $context ) : + $site->get_post_by_id( $field_value, $context ); - $response = array(); - foreach ( array_keys( $this->post_object_format ) as $key ) { + return $post; + } + + private function render_response_keys( $post, $context, $keys ) { + foreach ( $keys as $key ) { switch ( $key ) { case 'ID' : // explicitly cast all output $response[$key] = (int) $post->ID; break; case 'site_ID' : - $response[$key] = (int) $this->api->get_blog_id_for_output(); + $response[$key] = $post->site->get_id(); break; case 'author' : - $response[$key] = (object) $this->get_author( $post, 'edit' === $context && $capabilities['edit_post'] ); + $response[$key] = $post->get_author(); break; case 'date' : - $response[$key] = (string) $this->format_date( $post->post_date_gmt, $post->post_date ); + $response[$key] = $post->get_date(); break; case 'modified' : - $response[$key] = (string) $this->format_date( $post->post_modified_gmt, $post->post_modified ); + $response[$key] = $post->get_modified_date(); break; case 'title' : - if ( 'display' === $context ) { - $response[$key] = (string) get_the_title( $post->ID ); - } else { - $response[$key] = (string) htmlspecialchars_decode( $post->post_title, ENT_QUOTES ); - } + $response[$key] = $post->get_title(); break; case 'URL' : - if ( 'revision' === $post->post_type ) { - $response[$key] = (string) esc_url_raw( get_permalink( $post->post_parent ) ); - } else { - $response[$key] = (string) esc_url_raw( get_permalink( $post->ID ) ); - } + $response[$key] = $post->get_url(); break; case 'short_URL' : - $response[$key] = (string) esc_url_raw( wp_get_shortlink( $post->ID ) ); + $response[$key] = $post->get_shortlink(); break; case 'content' : - if ( 'display' === $context ) { - add_filter( 'the_password_form', array( $this, 'the_password_form' ) ); - $response[$key] = (string) $this->get_the_post_content_for_display(); - remove_filter( 'the_password_form', array( $this, 'the_password_form' ) ); - } else { - $response[$key] = (string) $post->post_content; - } + $response[$key] = $post->get_content(); break; case 'excerpt' : - if ( 'display' === $context ) { - add_filter( 'the_password_form', array( $this, 'the_password_form' ) ); - ob_start(); - the_excerpt(); - $response[$key] = (string) ob_get_clean(); - remove_filter( 'the_password_form', array( $this, 'the_password_form' ) ); - } else { - $response[$key] = htmlspecialchars_decode( (string) $post->post_excerpt, ENT_QUOTES ); - } + $response[$key] = $post->get_excerpt(); break; case 'status' : - $response[$key] = (string) get_post_status( $post->ID ); + $response[$key] = $post->get_status(); break; case 'sticky' : - $response[$key] = (bool) is_sticky( $post->ID ); + $response[$key] = $post->is_sticky(); break; case 'slug' : - $response[$key] = (string) $post->post_name; + $response[$key] = $post->get_slug(); break; case 'guid' : - $response[$key] = (string) $post->guid; + $response[$key] = $post->get_guid(); break; case 'password' : - $response[$key] = (string) $post->post_password; - if ( 'edit' === $context ) { - $response[$key] = htmlspecialchars_decode( (string) $response[$key], ENT_QUOTES ); - } + $response[$key] = $post->get_password(); break; case 'parent' : // (object|false) - if ( $post->post_parent ) { - $parent = get_post( $post->post_parent ); - if ( 'display' === $context ) { - $parent_title = (string) get_the_title( $parent->ID ); - } else { - $parent_title = (string) htmlspecialchars_decode( $post->post_title, ENT_QUOTES ); - } - $response[$key] = (object) array( - 'ID' => (int) $parent->ID, - 'type' => (string) $parent->post_type, - 'link' => (string) $this->get_post_link( $this->api->get_blog_id_for_output(), $parent->ID ), - 'title' => $parent_title, - ); - } else { - $response[$key] = false; - } + $response[$key] = $post->get_parent(); break; case 'type' : - $response[$key] = (string) $post->post_type; + $response[$key] = $post->get_type(); break; case 'discussion' : - $response[$key] = array( - 'comments_open' => (bool) comments_open( $post->ID ), - 'comment_status' => (string) $post->comment_status, - 'pings_open' => (bool) pings_open( $post->ID ), - 'ping_status' => (string) $post->ping_status, - 'comment_count' => (int) $post->comment_count, - ); + $response[$key] = $post->get_discussion(); break; case 'likes_enabled' : - /** This filter is documented in modules/likes.php */ - $sitewide_likes_enabled = (bool) apply_filters( 'wpl_is_enabled_sitewide', ! get_option( 'disabled_likes' ) ); - $post_likes_switched = (bool) get_post_meta( $post->ID, 'switch_like_status', true ); - $post_likes_enabled = $sitewide_likes_enabled; - if ( $post_likes_switched ) { - $post_likes_enabled = ! $post_likes_enabled; - } - $response[$key] = (bool) $post_likes_enabled; + $response[$key] = $post->is_likes_enabled(); break; case 'sharing_enabled' : - $show = true; - /** This filter is documented in modules/sharedaddy/sharing-service.php */ - $show = apply_filters( 'sharing_show', $show, $post ); - - $switched_status = get_post_meta( $post->ID, 'sharing_disabled', false ); - - if ( !empty( $switched_status ) ) - $show = false; - $response[$key] = (bool) $show; + $response[$key] = $post->is_sharing_enabled(); break; case 'like_count' : - $response[$key] = (int) $this->api->post_like_count( $blog_id, $post->ID ); + $response[$key] = $post->get_like_count(); break; case 'i_like' : - $response[$key] = (bool) $this->api->is_liked( $blog_id, $post->ID ); + $response[$key] = $post->is_liked(); break; case 'is_reblogged': - $response[$key] = (bool) $this->api->is_reblogged( $blog_id, $post->ID ); + $response[$key] = $post->is_reblogged(); break; case 'is_following': - $response[$key] = (bool) $this->api->is_following( $blog_id ); + $response[$key] = $post->is_following(); break; case 'global_ID': - $response[$key] = (string) $this->api->add_global_ID( $blog_id, $post->ID ); + $response[$key] = $post->get_global_id(); break; case 'featured_image' : - if ( $is_jetpack && ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) { - $response[ $key ] = get_post_meta( $post->ID, '_jetpack_featured_image', true ); - } else { - $image_attributes = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ), 'full' ); - if ( is_array( $image_attributes ) && isset( $image_attributes[0] ) ) { - $response[ $key ] = (string) $image_attributes[0]; - } else { - $response[ $key ] = ''; - } - } + $response[$key] = $post->get_featured_image(); break; case 'post_thumbnail' : - $response[$key] = null; - - $thumb_id = get_post_thumbnail_id( $post->ID ); - if ( ! empty( $thumb_id ) ) { - $attachment = get_post( $thumb_id ); - if ( ! empty( $attachment ) ) - $featured_image_object = $this->get_attachment( $attachment ); - - if ( ! empty( $featured_image_object ) ) { - $response[$key] = (object) $featured_image_object; - } - } + $response[$key] = $post->get_post_thumbnail(); break; case 'format' : - $response[$key] = (string) get_post_format( $post->ID ); - if ( !$response[$key] ) { - $response[$key] = 'standard'; - } + $response[$key] = $post->get_format(); break; case 'geo' : // (object|false) - if ( !$geo ) { - $response[$key] = false; - } else { - $geo_data = $geo->get_geo( 'post', $post->ID ); - $response[$key] = false; - if ( $geo_data ) { - $geo_data = array_intersect_key( $geo_data, array( 'latitude' => true, 'longitude' => true, 'address' => true, 'public' => true ) ); - if ( $geo_data ) { - $response[$key] = (object) array( - 'latitude' => isset( $geo_data['latitude'] ) ? (float) $geo_data['latitude'] : 0, - 'longitude' => isset( $geo_data['longitude'] ) ? (float) $geo_data['longitude'] : 0, - 'address' => isset( $geo_data['address'] ) ? (string) $geo_data['address'] : '', - ); - } else { - $response[$key] = false; - } - // Private - if ( !isset( $geo_data['public'] ) || !$geo_data['public'] ) { - if ( 'edit' !== $context || ! $capabilities['edit_post'] ) { - // user can't access - $response[$key] = false; - } - } - } - } + $response[$key] = $post->get_geo(); break; case 'menu_order': - $response[$key] = (int) $post->menu_order; + $response[$key] = $post->get_menu_order(); break; case 'page_template': - $response[$key] = (string) get_post_meta( $post->ID, '_wp_page_template', true ); + $response[$key] = $post->get_page_template(); break; case 'publicize_URLs' : - $publicize_URLs = array(); - $publicize = get_post_meta( $post->ID, 'publicize_results', true ); - if ( $publicize ) { - foreach ( $publicize as $service => $data ) { - switch ( $service ) { - case 'twitter' : - foreach ( $data as $datum ) { - $publicize_URLs[] = esc_url_raw( "https://twitter.com/{$datum['user_id']}/status/{$datum['post_id']}" ); - } - break; - case 'fb' : - foreach ( $data as $datum ) { - $publicize_URLs[] = esc_url_raw( "https://www.facebook.com/permalink.php?story_fbid={$datum['post_id']}&id={$datum['user_id']}" ); - } - break; - } - } - } - $response[$key] = (array) $publicize_URLs; + $response[$key] = $post->get_publicize_urls(); + break; + case 'terms': + $response[$key] = $post->get_terms(); break; case 'tags' : - $response[$key] = array(); - $terms = wp_get_post_tags( $post->ID ); - foreach ( $terms as $term ) { - if ( !empty( $term->name ) ) { - $response[$key][$term->name] = $this->format_taxonomy( $term, 'post_tag', 'display' ); - } - } - $response[$key] = (object) $response[$key]; + $response[$key] = $post->get_tags(); break; case 'categories': - $response[$key] = array(); - $terms = wp_get_object_terms( $post->ID, 'category', array( 'fields' => 'all' ) ); - foreach ( $terms as $term ) { - if ( !empty( $term->name ) ) { - $response[$key][$term->name] = $this->format_taxonomy( $term, 'category', 'display' ); - } - } - $response[$key] = (object) $response[$key]; + $response[$key] = $post->get_categories(); break; case 'attachments': - $response[$key] = array(); - $_attachments = new WP_Query( array( 'post_parent' => $post->ID, 'post_status' => 'inherit', 'post_type' => 'attachment', 'posts_per_page' => '20' ) ); - foreach ( $_attachments->posts as $attachment ) { - $response[$key][$attachment->ID] = $this->get_media_item_v1_1( $attachment->ID ); - } - $response['attachment_count'] = $_attachments->found_posts; - $response[$key] = (object) $response[$key]; + list( $attachments, $attachment_count ) = $post->get_attachments_and_count(); + $response[$key] = $attachments; + $response['attachment_count'] = $attachment_count; break; case 'metadata' : // (array|false) - $metadata = array(); - foreach ( (array) has_meta( $post_id ) as $meta ) { - // Don't expose protected fields. - $show = false; - if ( $this->is_metadata_public( $meta['meta_key'] ) ) - $show = true; - if ( current_user_can( 'edit_post_meta', $post_id , $meta['meta_key'] ) ) - $show = true; - - if ( !$show ) - continue; - - $metadata[] = array( - 'id' => $meta['meta_id'], - 'key' => $meta['meta_key'], - 'value' => maybe_unserialize( $meta['meta_value'] ), - ); - } - - if ( ! empty( $metadata ) ) { - $response[$key] = $metadata; - } else { - $response[$key] = false; - } + $response[$key] = $post->get_metadata(); break; case 'meta' : - $response[$key] = (object) array( - 'links' => (object) array( - 'self' => (string) $this->get_post_link( $this->api->get_blog_id_for_output(), $post->ID ), - 'help' => (string) $this->get_post_link( $this->api->get_blog_id_for_output(), $post->ID, 'help' ), - 'site' => (string) $this->get_site_link( $this->api->get_blog_id_for_output() ), -// 'author' => (string) $this->get_user_link( $post->post_author ), -// 'via' => (string) $this->get_post_link( $reblog_origin_blog_id, $reblog_origin_post_id ), - 'replies' => (string) $this->get_post_link( $this->api->get_blog_id_for_output(), $post->ID, 'replies/' ), - 'likes' => (string) $this->get_post_link( $this->api->get_blog_id_for_output(), $post->ID, 'likes/' ), - ), - ); - - // add autosave link if a more recent autosave exists - if ( 'edit' === $context ) { - $autosave = wp_get_post_autosave( $post_id ); - if ( $autosave && $autosave->post_modified > $post->post_modified ) - $response[$key]->links->autosave = (string) $this->get_post_link( $this->api->get_blog_id_for_output(), $post->ID ) . '/autosave'; - } - + $response[$key] = $post->get_meta(); break; case 'capabilities' : - $response[$key] = $capabilities; + $response[$key] = $post->get_current_user_capabilities(); break; case 'revisions' : - if ( 'edit' !== $context ) { - continue; - } - $revisions = array(); - $post_revisions = wp_get_post_revisions( $post->ID ); - - foreach ( $post_revisions as $_post ) { - $revisions[] = $_post->ID; + $revisions = $post->get_revisions(); + if ( $revisions ) { + $response[$key] = $revisions; } - - $response[$key] = $revisions; - break; case 'other_URLs' : - $other_urls = array(); - - if ( 'publish' !== $post->post_status ) { - $other_urls = $this->get_post_permalink_suggestions( $post->ID, $post->post_title ); - } - - $response[$key] = (object) $other_urls; + $response[$key] = $post->get_other_urls(); break; } } - // WPCOM_JSON_API_Post_Endpoint::find_featured_worthy_media( $post ); - // $response['featured_media'] = self::find_featured_media( $response ); - - unset( $GLOBALS['post'] ); return $response; } - // No Blog ID parameter. No Post ID parameter. Depends on globals. - // Expects setup_postdata() to already have been run - function get_the_post_content_for_display() { - global $pages, $page; - - $old_pages = $pages; - $old_page = $page; - - $content = join( "\n\n", $pages ); - $content = preg_replace( '/<!--more(.*?)?-->/', '', $content ); - $pages = array( $content ); - $page = 1; - - ob_start(); - the_content(); - $return = ob_get_clean(); - - $pages = $old_pages; - $page = $old_page; - - return $return; - } - + // TODO: factor this out function get_blog_post( $blog_id, $post_id, $context = 'display' ) { $blog_id = $this->api->get_blog_id( $blog_id ); if ( !$blog_id || is_wp_error( $blog_id ) ) { @@ -543,26 +281,6 @@ abstract class WPCOM_JSON_API_Post_v1_1_Endpoint extends WPCOM_JSON_API_Endpoint return $post; } - /** - * Supporting featured media in post endpoints. Currently on for wpcom blogs - * since it's calling WPCOM_JSON_API_Read_Endpoint methods which presently - * rely on wpcom specific functionality. - * - * @param WP_Post $post - * @return object list of featured media - */ - public static function find_featured_media( &$post ) { - - if ( class_exists( 'WPCOM_JSON_API_Read_Endpoint' ) ) { - return WPCOM_JSON_API_Read_Endpoint::find_featured_worthy_media( (array) $post ); - } else { - return (object) array(); - } - - } - - - function win8_gallery_shortcode( $attr ) { global $post; @@ -623,90 +341,4 @@ abstract class WPCOM_JSON_API_Post_v1_1_Endpoint extends WPCOM_JSON_API_Endpoint } } } - - /** - * Returns attachment object. - * - * @param $attachment attachment row - * - * @return (object) - */ - function get_attachment( $attachment ) { - $metadata = wp_get_attachment_metadata( $attachment->ID ); - - $result = array( - 'ID' => (int) $attachment->ID, - 'URL' => (string) wp_get_attachment_url( $attachment->ID ), - 'guid' => (string) $attachment->guid, - 'mime_type' => (string) $attachment->post_mime_type, - 'width' => (int) isset( $metadata['width'] ) ? $metadata['width'] : 0, - 'height' => (int) isset( $metadata['height'] ) ? $metadata['height'] : 0, - ); - - if ( isset( $metadata['duration'] ) ) { - $result['duration'] = (int) $metadata['duration']; - } - - /** This filter is documented in class.jetpack-sync.php */ - return (object) apply_filters( 'get_attachment', $result ); - } - - /** - * Get post-specific user capabilities - * @param WP_Post $post post object - * @return array array of post-level permissions; 'publish_post', 'delete_post', 'edit_post' - */ - function get_current_user_capabilities( $post ) { - return array( - 'publish_post' => current_user_can( 'publish_post', $post ), - 'delete_post' => current_user_can( 'delete_post', $post ), - 'edit_post' => current_user_can( 'edit_post', $post ) - ); - } - - /** - * Get extra post permalink suggestions - * @param int $postID - * @param string $title - * @return array array of permalink suggestions: 'permalink_URL', 'suggested_slug' - */ - function get_post_permalink_suggestions( $postID, $title ) { - $suggestions = array(); - list( $suggestions['permalink_URL'], $suggestions['suggested_slug'] ) = get_sample_permalink( $postID, $title ); - return $suggestions; - } - - /** - * Get post ID by name - * - * Attempts to match name on post title and page path - * - * @param string $name - * - * @return int|object Post ID on success, WP_Error object on failure - **/ - protected function get_post_id_by_name( $name ) { - $name = sanitize_title( $name ); - - if ( ! $name ) { - return new WP_Error( 'invalid_post', 'Invalid post', 400 ); - } - - $posts = get_posts( array( 'name' => $name ) ); - - if ( ! $posts || ! isset( $posts[0]->ID ) || ! $posts[0]->ID ) { - $page = get_page_by_path( $name ); - - if ( ! $page ) { - return new WP_Error( 'unknown_post', 'Unknown post', 404 ); - } - - $post_id = $page->ID; - } else { - $post_id = (int) $posts[0]->ID; - } - - return $post_id; - } - } diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-render-embed-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-render-embed-endpoint.php index fe4cf85b..30c90e46 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-render-embed-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-render-embed-endpoint.php @@ -29,13 +29,6 @@ class WPCOM_JSON_API_Render_Embed_Endpoint extends WPCOM_JSON_API_Render_Endpoin return new WP_Error( 'invalid_embed_url', 'The embed_url parameter must be a valid URL.', 400 ); } - // in order for oEmbed to fire in the `$wp_embed->shortcode` method, we need to set a post as the current post - $_posts = get_posts( array( 'posts_per_page' => 1, 'suppress_filters' => false ) ); - if ( ! empty( $_posts ) ) { - global $post; - $post = array_shift( $_posts ); - } - global $wp_embed; $render = $this->process_render( array( $this, 'do_embed' ), $embed_url ); @@ -54,8 +47,4 @@ class WPCOM_JSON_API_Render_Embed_Endpoint extends WPCOM_JSON_API_Render_Endpoin return $return; } - function do_embed( $embed_url ) { - global $wp_embed; - return $wp_embed->shortcode( array(), $embed_url ); - } }
\ No newline at end of file diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-render-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-render-endpoint.php index 273429e0..f2de7fc3 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-render-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-render-endpoint.php @@ -8,7 +8,7 @@ abstract class WPCOM_JSON_API_Render_Endpoint extends WPCOM_JSON_API_Endpoint { * props to o2's o2_Read_API::poll() function for inspiration. * * In short we figure out what scripts load for a "normal" page load by executing wp_head and wp_footer - * then we render our shortcode (to both get our result, and to have the shortcode files enqueue their resources) + * then we render the embed/shortcode (to both get our result, and to have the shortcode files enqueue their resources) * then we load wp_head and wp_footer again to see what new resources were added * finally we find out the url to the source file and any extra info (like media or init js) */ @@ -96,7 +96,7 @@ abstract class WPCOM_JSON_API_Render_Endpoint extends WPCOM_JSON_API_Endpoint { $media = esc_attr( $wp_styles->registered[ $handle ]->args ); } - // add to an aray so we can return all this info + // add to an array so we can return all this info $styles[ $handle ] = array ( 'src' => $src, 'media' => $media, @@ -121,4 +121,25 @@ abstract class WPCOM_JSON_API_Render_Endpoint extends WPCOM_JSON_API_Endpoint { return $ver; } + /** + * given a shortcode, process and return the result + */ + function do_shortcode( $shortcode ) { + return do_shortcode( $shortcode ); + } + + /** + * given a one-line embed URL, process and return the result + */ + function do_embed( $embed_url ) { + // in order for oEmbed to fire in the `$wp_embed->shortcode` method, we need to set a post as the current post + $_posts = get_posts( array( 'posts_per_page' => 1, 'suppress_filters' => false ) ); + if ( ! empty( $_posts ) ) { + global $post; + $post = array_shift( $_posts ); + } + + global $wp_embed; + return $wp_embed->shortcode( array(), $embed_url ); + } }
\ No newline at end of file diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-render-shortcode-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-render-shortcode-endpoint.php index 055f84d1..8b52cfde 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-render-shortcode-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-render-shortcode-endpoint.php @@ -41,10 +41,4 @@ class WPCOM_JSON_API_Render_Shortcode_Endpoint extends WPCOM_JSON_API_Render_End return $return; } - - function do_shortcode( $shortcode ) { - $result = do_shortcode( $shortcode ); - return $result; - } - }
\ No newline at end of file diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-sharing-buttons-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-sharing-buttons-endpoint.php index e497caff..2bca8261 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-sharing-buttons-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-sharing-buttons-endpoint.php @@ -30,10 +30,10 @@ abstract class WPCOM_JSON_API_Sharing_Button_Endpoint extends WPCOM_JSON_API_End // Status is either "disabled" or the visibility value $response['visibility'] = $this->get_button_visibility( $button ); } - - if ( ! empty( $button->genericon ) ) { + + if ( ! empty( $button->icon ) ) { // Only pre-defined sharing buttons include genericon - $response['genericon'] = $button->genericon; + $response['genericon'] = $button->icon; } if ( method_exists( $button, 'get_options' ) ) { 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 d0218514..efcc84d5 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 @@ -192,7 +192,13 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { 'twitter_via' => (string) get_option( 'twitter_via' ), 'jetpack-twitter-cards-site-tag' => (string) get_option( 'jetpack-twitter-cards-site-tag' ), 'eventbrite_api_token' => $eventbrite_api_token, - 'holidaysnow' => $holiday_snow + 'holidaysnow' => $holiday_snow, + 'gmt_offset' => get_option( 'gmt_offset' ), + 'timezone_string' => get_option( 'timezone_string' ), + 'jetpack_testimonial' => (bool) get_option( 'jetpack_testimonial', '0' ), + 'jetpack_testimonial_posts_per_page' => (int) get_option( 'jetpack_testimonial_posts_per_page', '10' ), + 'jetpack_portfolio' => (bool) get_option( 'jetpack_portfolio', '0' ), + 'jetpack_portfolio_posts_per_page' => (int) get_option( 'jetpack_portfolio_posts_per_page', '10' ), ); //allow future versions of this endpoint to support additional settings keys @@ -346,11 +352,22 @@ 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': // settings are stored as 1|0 $coerce_value = (int) $value; if ( update_option( $key, $coerce_value ) ) { - $updated[ $key ] = $value; + $updated[ $key ] = (bool) $value; + } + break; + + case 'jetpack_testimonial_posts_per_page': + case 'jetpack_portfolio_posts_per_page': + // settings are stored as numeric + $coerce_value = (int) $value; + if ( update_option( $key, $coerce_value ) ) { + $updated[ $key ] = $coerce_value; } break; @@ -388,6 +405,24 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { } break; + case 'timezone_string': + // Map UTC+- timezones to gmt_offsets and set timezone_string to empty + // https://github.com/WordPress/WordPress/blob/4.4.2/wp-admin/options.php#L175 + if ( ! empty( $value ) && preg_match( '/^UTC[+-]/', $value ) ) { + $gmt_offset = preg_replace( '/UTC\+?/', '', $value ); + if ( update_option( 'gmt_offset', $gmt_offset ) ) { + $updated[ 'gmt_offset' ] = $gmt_offset; + } + + $value = ''; + } + + // Always set timezone_string either with the given value or with an + // empty string + if ( update_option( $key, $value ) ) { + $updated[ $key ] = $value; + } + break; default: //allow future versions of this endpoint to support additional settings keys @@ -410,7 +445,6 @@ class WPCOM_JSON_API_Site_Settings_Endpoint extends WPCOM_JSON_API_Endpoint { if ( update_option( $key, $value ) ) { $updated[ $key ] = $value; } - } } 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 84a83849..7a61ce12 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 @@ -43,12 +43,9 @@ class WPCOM_JSON_API_Site_User_Endpoint extends WPCOM_JSON_API_Endpoint { return $this->get_user( $user->ID ); } else if ( 'POST' === $this->api->method ) { if ( ! current_user_can_for_blog( $blog_id, 'promote_users' ) ) { - return new WP_Error( 'unauthorized', 'User cannot promote users for specified site', 403 ); + return new WP_Error( 'unauthorized_no_promote_cap', 'User cannot promote users for specified site', 403 ); } - if ( get_current_user_id() == $user_id ) { - return new WP_Error( 'unauthorized', 'You cannot change your own role', 403 ); - } - return $this->update_user( $user_id ); + return $this->update_user( $user_id, $blog_id ); } else { return new WP_Error( 'bad_request', 'An unsupported request method was used.' ); } @@ -69,15 +66,25 @@ class WPCOM_JSON_API_Site_User_Endpoint extends WPCOM_JSON_API_Endpoint { * * @return (array) */ - public function update_user( $user_id ) { + public function update_user( $user_id, $blog_id ) { $input = $this->input(); $user['ID'] = $user_id; - if ( ! ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ) { + $is_wpcom = defined( 'IS_WPCOM' ) && IS_WPCOM; + + if ( get_current_user_id() == $user_id && isset( $input['roles'] ) ) { + return new WP_Error( 'unauthorized', 'You cannot change your own role', 403 ); + } + + if ( $is_wpcom && $user_id !== get_current_user_id() && $user_id == wpcom_get_blog_owner( $blog_id ) ) { + return new WP_Error( 'unauthorized_edit_owner', 'Current user can not edit blog owner', 403 ); + } + + if ( ! $is_wpcom ) { foreach ( $input as $key => $value ) { if ( ! is_array( $value ) ) { $value = trim( $value ); } - $value = wp_unslash( $value ); + $value = wp_unslash( $value ); switch ( $key ) { case 'first_name': case 'last_name': diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-invites-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-invites-endpoint.php index 85a1ab92..689cef88 100644 --- a/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-invites-endpoint.php +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-invites-endpoint.php @@ -36,7 +36,7 @@ class WPCOM_JSON_API_Update_Invites_Endpoint extends WPCOM_JSON_API_Endpoint { 'invite_key' => $invite_id, 'deleted' => $this->delete_invite(), ); - } else { + } else if ( $this->api->ends_with( $this->path, '/resend' ) ) { $returnValue = array( 'result' => $this->is_wpcom ? $this->resend_wpcom_invite() : $this->resend_self_hosted_invite() ); 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 dcf84a35..53932601 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 @@ -89,6 +89,10 @@ class WPCOM_JSON_API_Update_Post_Endpoint extends WPCOM_JSON_API_Post_Endpoint { return new WP_Error( 'invalid_input', 'Invalid request input', 400 ); } + if ( isset( $input['status'] ) && 'trash' === $input['status'] && ! current_user_can( 'delete_post', $post_id ) ) { + return new WP_Error( 'unauthorized', 'User cannot delete post', 403 ); + } + $post = get_post( $post_id ); $_post_type = ( ! empty( $input['type'] ) ) ? $input['type'] : $post->post_type; $post_type = get_post_type_object( $_post_type ); @@ -559,7 +563,7 @@ class WPCOM_JSON_API_Update_Post_Endpoint extends WPCOM_JSON_API_Post_Endpoint { if ( ! empty( $meta->id ) || ! empty( $meta->previous_value ) ) { continue; - } elseif ( ! empty( $meta->key ) && ! empty( $meta->value ) && ( current_user_can( 'add_post_meta', $post_id, $unslashed_meta_key ) ) || $this->is_metadata_public( $meta->key ) ) { + } elseif ( ! empty( $meta->key ) && ! empty( $meta->value ) && ( current_user_can( 'add_post_meta', $post_id, $unslashed_meta_key ) ) || WPCOM_JSON_API_Metadata::is_public( $meta->key ) ) { add_post_meta( $post_id, $meta->key, $meta->value ); } @@ -568,11 +572,11 @@ class WPCOM_JSON_API_Update_Post_Endpoint extends WPCOM_JSON_API_Post_Endpoint { if ( ! isset( $meta->value ) ) { continue; - } elseif ( ! empty( $meta->id ) && ! empty( $existing_meta_item->meta_key ) && ( current_user_can( 'edit_post_meta', $post_id, $unslashed_existing_meta_key ) || $this->is_metadata_public( $meta->key ) ) ) { + } elseif ( ! empty( $meta->id ) && ! empty( $existing_meta_item->meta_key ) && ( current_user_can( 'edit_post_meta', $post_id, $unslashed_existing_meta_key ) || WPCOM_JSON_API_Metadata::is_public( $meta->key ) ) ) { update_metadata_by_mid( 'post', $meta->id, $meta->value ); - } elseif ( ! empty( $meta->key ) && ! empty( $meta->previous_value ) && ( current_user_can( 'edit_post_meta', $post_id, $unslashed_meta_key ) || $this->is_metadata_public( $meta->key ) ) ) { + } elseif ( ! empty( $meta->key ) && ! empty( $meta->previous_value ) && ( current_user_can( 'edit_post_meta', $post_id, $unslashed_meta_key ) || WPCOM_JSON_API_Metadata::is_public( $meta->key ) ) ) { update_post_meta( $post_id, $meta->key,$meta->value, $meta->previous_value ); - } elseif ( ! empty( $meta->key ) && ( current_user_can( 'edit_post_meta', $post_id, $unslashed_meta_key ) || $this->is_metadata_public( $meta->key ) ) ) { + } elseif ( ! empty( $meta->key ) && ( current_user_can( 'edit_post_meta', $post_id, $unslashed_meta_key ) || WPCOM_JSON_API_Metadata::is_public( $meta->key ) ) ) { update_post_meta( $post_id, $meta->key, $meta->value ); } @@ -685,7 +689,7 @@ class WPCOM_JSON_API_Update_Post_Endpoint extends WPCOM_JSON_API_Post_Endpoint { return $featured_image; } - $featured_image_id = $this->handle_media_sideload( $featured_image, $post_id ); + $featured_image_id = $this->handle_media_sideload( $featured_image, $post_id, 'image' ); if ( empty( $featured_image_id ) || ! is_int( $featured_image_id ) ) return false; 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 9f0bf598..d69c7d08 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 @@ -36,16 +36,21 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_ if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { remove_action( 'save_post', array( $GLOBALS['publicize_ui']->publicize, 'async_publicize_post' ), 100, 2 ); add_action( 'rest_api_inserted_post', array( $GLOBALS['publicize_ui']->publicize, 'async_publicize_post' ) ); - } - // 'future' is an alias for 'publish' for now - if ( 'future' === $input['status'] ) { - $input['status'] = 'publish'; + if ( $this->should_load_theme_functions( $post_id ) ) { + $this->load_theme_functions(); + } } + if ( $new ) { $input = $this->input( true ); + // 'future' is an alias for 'publish' for now + if ( 'future' === $input['status'] ) { + $input['status'] = 'publish'; + } + if ( 'revision' === $input['type'] ) { if ( ! isset( $input['parent'] ) ) { return new WP_Error( 'invalid_input', 'Invalid request input', 400 ); @@ -94,6 +99,15 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_ return new WP_Error( 'invalid_input', 'Invalid request input', 400 ); } + if ( isset( $input['status'] ) && 'trash' === $input['status'] && ! current_user_can( 'delete_post', $post_id ) ) { + return new WP_Error( 'unauthorized', 'User cannot delete post', 403 ); + } + + // 'future' is an alias for 'publish' for now + if ( isset( $input['status'] ) && 'future' === $input['status'] ) { + $input['status'] = 'publish'; + } + $post = get_post( $post_id ); $_post_type = ( ! empty( $input['type'] ) ) ? $input['type'] : $post->post_type; $post_type = get_post_type_object( $_post_type ); @@ -149,26 +163,50 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_ unset( $input['parent'] ); } - $tax_input = array(); + $input['terms'] = isset( $input['terms'] ) ? (array) $input['terms'] : array(); - foreach ( array( 'categories' => 'category', 'tags' => 'post_tag' ) as $key => $taxonomy ) { - if ( ! isset( $input[ $key ] ) ) { - continue; + // Convert comma-separated terms to array before attempting to + // merge with hardcoded taxonomies + foreach ( $input['terms'] as $taxonomy => $terms ) { + if ( is_string( $terms ) ) { + $input['terms'][ $taxonomy ] = explode( ',', $terms ); + } else if ( ! is_array( $terms ) ) { + $input['terms'][ $taxonomy ] = array(); } + } - $tax_input[ $taxonomy ] = array(); + // For each hard-coded taxonomy, merge into terms object + foreach ( array( 'categories' => 'category', 'tags' => 'post_tag' ) as $taxonomy_key => $taxonomy ) { + if ( ! isset( $input[ $taxonomy_key ] ) ) { + continue; + } - $is_hierarchical = is_taxonomy_hierarchical( $taxonomy ); + if ( ! isset( $input['terms'][ $taxonomy ] ) ) { + $input['terms'][ $taxonomy ] = array(); + } - if ( is_array( $input[$key] ) ) { - $terms = $input[$key]; - } else { - $terms = explode( ',', $input[$key] ); + $terms = $input[ $taxonomy_key ]; + if ( is_string( $terms ) ) { + $terms = explode( ',', $terms ); + } else if ( ! is_array( $terms ) ) { + continue; } + $input['terms'][ $taxonomy ] = array_merge( + $input['terms'][ $taxonomy ], + $terms + ); + } + + $tax_input = array(); + + foreach ( $input['terms'] as $taxonomy => $terms ) { + $tax_input[ $taxonomy ] = array(); + $is_hierarchical = is_taxonomy_hierarchical( $taxonomy ); + foreach ( $terms as $term ) { /** - * `curl --data 'category[]=123'` should be interpreted as a category ID, + * `curl --data 'terms[category][]=123'` should be interpreted as a category ID, * not a category whose name is '123'. * * Consequence: To add a category/tag whose name is '123', the client must @@ -190,7 +228,7 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_ $tax = get_taxonomy( $taxonomy ); // see https://core.trac.wordpress.org/ticket/26409 - if ( 'category' === $taxonomy && ! current_user_can( $tax->cap->edit_terms ) ) { + if ( $is_hierarchical && ! current_user_can( $tax->cap->edit_terms ) ) { continue; } else if ( ! current_user_can( $tax->cap->assign_terms ) ) { continue; @@ -201,10 +239,10 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_ if ( ! is_wp_error( $term_info ) ) { if ( $is_hierarchical ) { - // Categories must be added by ID + // Hierarchical terms must be added by ID $tax_input[$taxonomy][] = (int) $term_info['term_id']; } else { - // Tags must be added by name + // Non-hierarchical terms must be added by name if ( is_int( $term ) ) { $term = get_term( $term, $taxonomy ); $tax_input[$taxonomy][] = $term->name; @@ -216,11 +254,11 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_ } } - if ( isset( $input['categories'] ) && empty( $tax_input['category'] ) && 'revision' !== $post_type->name ) { + if ( isset( $input['terms']['category'] ) && empty( $tax_input['category'] ) && 'revision' !== $post_type->name ) { $tax_input['category'][] = get_option( 'default_category' ); } - unset( $input['tags'], $input['categories'] ); + unset( $input['terms'], $input['tags'], $input['categories'] ); $insert = array(); @@ -573,7 +611,7 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_ if ( ! empty( $meta->id ) || ! empty( $meta->previous_value ) ) { continue; - } elseif ( ! empty( $meta->key ) && ! empty( $meta->value ) && ( current_user_can( 'add_post_meta', $post_id, $unslashed_meta_key ) ) || $this->is_metadata_public( $meta->key ) ) { + } elseif ( ! empty( $meta->key ) && ! empty( $meta->value ) && ( current_user_can( 'add_post_meta', $post_id, $unslashed_meta_key ) ) || WPCOM_JSON_API_Metadata::is_public( $meta->key ) ) { add_post_meta( $post_id, $meta->key, $meta->value ); } @@ -582,11 +620,11 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_ if ( ! isset( $meta->value ) ) { continue; - } elseif ( ! empty( $meta->id ) && ! empty( $existing_meta_item->meta_key ) && ( current_user_can( 'edit_post_meta', $post_id, $unslashed_existing_meta_key ) || $this->is_metadata_public( $meta->key ) ) ) { + } elseif ( ! empty( $meta->id ) && ! empty( $existing_meta_item->meta_key ) && ( current_user_can( 'edit_post_meta', $post_id, $unslashed_existing_meta_key ) || WPCOM_JSON_API_Metadata::is_public( $meta->key ) ) ) { update_metadata_by_mid( 'post', $meta->id, $meta->value ); - } elseif ( ! empty( $meta->key ) && ! empty( $meta->previous_value ) && ( current_user_can( 'edit_post_meta', $post_id, $unslashed_meta_key ) || $this->is_metadata_public( $meta->key ) ) ) { + } elseif ( ! empty( $meta->key ) && ! empty( $meta->previous_value ) && ( current_user_can( 'edit_post_meta', $post_id, $unslashed_meta_key ) || WPCOM_JSON_API_Metadata::is_public( $meta->key ) ) ) { update_post_meta( $post_id, $meta->key,$meta->value, $meta->previous_value ); - } elseif ( ! empty( $meta->key ) && ( current_user_can( 'edit_post_meta', $post_id, $unslashed_meta_key ) || $this->is_metadata_public( $meta->key ) ) ) { + } elseif ( ! empty( $meta->key ) && ( current_user_can( 'edit_post_meta', $post_id, $unslashed_meta_key ) || WPCOM_JSON_API_Metadata::is_public( $meta->key ) ) ) { update_post_meta( $post_id, $meta->key, $meta->value ); } @@ -617,7 +655,8 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_ $return['media_errors'] = $media_results['errors']; if ( 'publish' !== $post->post_status ) { - $return['other_URLs'] = (object) $this->get_post_permalink_suggestions( $post_id, $input['title'] ); + $sal_site = $this->get_sal_post_by( 'ID', $post_id, $args['context'] ); + $return['other_URLs'] = (object) $sal_site->get_permalink_suggestions( $input['title'] ); } /** This action is documented in json-endpoints/class.wpcom-json-api-site-settings-endpoint.php */ @@ -696,7 +735,7 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_ return $featured_image; } - $featured_image_id = $this->handle_media_sideload( $featured_image, $post_id ); + $featured_image_id = $this->handle_media_sideload( $featured_image, $post_id, 'image' ); if ( empty( $featured_image_id ) || ! is_int( $featured_image_id ) ) return false; @@ -724,4 +763,15 @@ class WPCOM_JSON_API_Update_Post_v1_1_Endpoint extends WPCOM_JSON_API_Post_v1_1_ return $_user->ID; } + + protected function should_load_theme_functions( $post_id = null ) { + if ( empty( $post_id ) ) { + $input = $this->input( true ); + $type = $input['type']; + } else { + $type = get_post_type( $post_id ); + } + + return ! empty( $type ) && ! in_array( $type, array( 'post', 'page', '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 cd7dae8b..6acef29b 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 @@ -11,16 +11,20 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { remove_action( 'save_post', array( $GLOBALS['publicize_ui']->publicize, 'async_publicize_post' ), 100, 2 ); add_action( 'rest_api_inserted_post', array( $GLOBALS['publicize_ui']->publicize, 'async_publicize_post' ) ); - } - // 'future' is an alias for 'publish' for now - if ( isset( $input['status'] ) && 'future' === $input['status'] ) { - $input['status'] = 'publish'; + if ( $this->should_load_theme_functions( $post_id ) ) { + $this->load_theme_functions(); + } } if ( $new ) { $input = $this->input( true ); + // 'future' is an alias for 'publish' for now + if ( isset( $input['status'] ) && 'future' === $input['status'] ) { + $input['status'] = 'publish'; + } + if ( 'revision' === $input['type'] ) { if ( ! isset( $input['parent'] ) ) { return new WP_Error( 'invalid_input', 'Invalid request input', 400 ); @@ -69,6 +73,15 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos return new WP_Error( 'invalid_input', 'Invalid request input', 400 ); } + if ( isset( $input['status'] ) && 'trash' === $input['status'] && ! current_user_can( 'delete_post', $post_id ) ) { + return new WP_Error( 'unauthorized', 'User cannot delete post', 403 ); + } + + // 'future' is an alias for 'publish' for now + if ( isset( $input['status'] ) && 'future' === $input['status'] ) { + $input['status'] = 'publish'; + } + $post = get_post( $post_id ); $_post_type = ( ! empty( $input['type'] ) ) ? $input['type'] : $post->post_type; $post_type = get_post_type_object( $_post_type ); @@ -124,22 +137,54 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos unset( $input['parent'] ); } - /* add taxonomies by name */ - $tax_input = array(); - foreach ( array( 'categories' => 'category', 'tags' => 'post_tag' ) as $key => $taxonomy ) { - if ( ! isset( $input[ $key ] ) ) { - continue; + foreach ( array( '', '_by_id' ) as $term_key_suffix ) { + $term_input_key = 'terms' . $term_key_suffix; + if ( isset( $input[ $term_input_key ] ) ) { + $input[ $term_input_key ] = (array) $input[ $term_input_key ]; + } else { + $input[ $term_input_key ] = array(); } - $tax_input[ $taxonomy ] = array(); + // Convert comma-separated terms to array before attempting to + // merge with hardcoded taxonomies + foreach ( $input[ $term_input_key ] as $taxonomy => $terms ) { + if ( is_string( $terms ) ) { + $input[ $term_input_key ][ $taxonomy ] = explode( ',', $terms ); + } else if ( ! is_array( $terms ) ) { + $input[ $term_input_key ][ $taxonomy ] = array(); + } + } - $is_hierarchical = is_taxonomy_hierarchical( $taxonomy ); + // For each hard-coded taxonomy, merge into terms object + foreach ( array( 'categories' => 'category', 'tags' => 'post_tag' ) as $key_prefix => $taxonomy ) { + $taxonomy_key = $key_prefix . $term_key_suffix; + if ( ! isset( $input[ $taxonomy_key ] ) ) { + continue; + } - if ( is_array( $input[$key] ) ) { - $terms = $input[$key]; - } else { - $terms = explode( ',', $input[$key] ); + if ( ! isset( $input[ $term_input_key ][ $taxonomy ] ) ) { + $input[ $term_input_key ][ $taxonomy ] = array(); + } + + $terms = $input[ $taxonomy_key ]; + if ( is_string( $terms ) ) { + $terms = explode( ',', $terms ); + } else if ( ! is_array( $terms ) ) { + continue; + } + + $input[ $term_input_key ][ $taxonomy ] = array_merge( + $input[ $term_input_key ][ $taxonomy ], + $terms + ); } + } + + /* add terms by name */ + $tax_input = array(); + foreach ( $input['terms'] as $taxonomy => $terms ) { + $tax_input[ $taxonomy ] = array(); + $is_hierarchical = is_taxonomy_hierarchical( $taxonomy ); foreach ( $terms as $term ) { /** @@ -154,7 +199,7 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos $tax = get_taxonomy( $taxonomy ); // see https://core.trac.wordpress.org/ticket/26409 - if ( 'category' === $taxonomy && ! current_user_can( $tax->cap->edit_terms ) ) { + if ( $is_hierarchical && ! current_user_can( $tax->cap->edit_terms ) ) { continue; } else if ( ! current_user_can( $tax->cap->assign_terms ) ) { continue; @@ -165,22 +210,18 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos if ( ! is_wp_error( $term_info ) ) { if ( $is_hierarchical ) { - // Categories must be added by ID + // Hierarchical terms must be added by ID $tax_input[$taxonomy][] = (int) $term_info['term_id']; } else { - // Tags must be added by name + // Non-hierarchical terms must be added by name $tax_input[$taxonomy][] = $term; } } } } - /* add taxonomies by ID */ - foreach ( array( 'categories_by_id' => 'category', 'tags_by_id' => 'post_tag' ) as $key => $taxonomy ) { - if ( ! isset( $input[ $key ] ) ) { - continue; - } - + /* add terms by ID */ + foreach ( $input['terms_by_id'] as $taxonomy => $terms ) { // combine with any previous selections if ( ! isset( $tax_input[ $taxonomy ] ) || ! is_array( $tax_input[ $taxonomy ] ) ) { $tax_input[ $taxonomy ] = array(); @@ -188,12 +229,6 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos $is_hierarchical = is_taxonomy_hierarchical( $taxonomy ); - if ( is_array( $input[$key] ) ) { - $terms = $input[$key]; - } else { - $terms = explode( ',', $input[$key] ); - } - foreach ( $terms as $term ) { $term = (string) $term; // ctype_digit compat if ( ! ctype_digit( $term ) ) { @@ -215,12 +250,12 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos } } - if ( ( isset( $input['categories'] ) || isset( $input['categories_by_id'] ) ) - && empty( $tax_input['category'] ) && 'revision' !== $post_type->name ) { + if ( ( isset( $input['terms']['category'] ) || isset( $input['terms_by_id']['category'] ) ) + && empty( $tax_input['category'] ) && 'revision' !== $post_type->name ) { $tax_input['category'][] = get_option( 'default_category' ); } - unset( $input['tags'], $input['categories'], $input['tags_by_id'], $input['categories_by_id'] ); + unset( $input['terms'], $input['tags'], $input['categories'], $input['terms_by_id'], $input['tags_by_id'], $input['categories_by_id'] ); $insert = array(); @@ -573,7 +608,7 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos if ( ! empty( $meta->id ) || ! empty( $meta->previous_value ) ) { continue; - } elseif ( ! empty( $meta->key ) && ! empty( $meta->value ) && ( current_user_can( 'add_post_meta', $post_id, $unslashed_meta_key ) ) || $this->is_metadata_public( $meta->key ) ) { + } elseif ( ! empty( $meta->key ) && ! empty( $meta->value ) && ( current_user_can( 'add_post_meta', $post_id, $unslashed_meta_key ) ) || WPCOM_JSON_API_Metadata::is_public( $meta->key ) ) { add_post_meta( $post_id, $meta->key, $meta->value ); } @@ -582,11 +617,11 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos if ( ! isset( $meta->value ) ) { continue; - } elseif ( ! empty( $meta->id ) && ! empty( $existing_meta_item->meta_key ) && ( current_user_can( 'edit_post_meta', $post_id, $unslashed_existing_meta_key ) || $this->is_metadata_public( $meta->key ) ) ) { + } elseif ( ! empty( $meta->id ) && ! empty( $existing_meta_item->meta_key ) && ( current_user_can( 'edit_post_meta', $post_id, $unslashed_existing_meta_key ) || WPCOM_JSON_API_Metadata::is_public( $meta->key ) ) ) { update_metadata_by_mid( 'post', $meta->id, $meta->value ); - } elseif ( ! empty( $meta->key ) && ! empty( $meta->previous_value ) && ( current_user_can( 'edit_post_meta', $post_id, $unslashed_meta_key ) || $this->is_metadata_public( $meta->key ) ) ) { + } elseif ( ! empty( $meta->key ) && ! empty( $meta->previous_value ) && ( current_user_can( 'edit_post_meta', $post_id, $unslashed_meta_key ) || WPCOM_JSON_API_Metadata::is_public( $meta->key ) ) ) { update_post_meta( $post_id, $meta->key,$meta->value, $meta->previous_value ); - } elseif ( ! empty( $meta->key ) && ( current_user_can( 'edit_post_meta', $post_id, $unslashed_meta_key ) || $this->is_metadata_public( $meta->key ) ) ) { + } elseif ( ! empty( $meta->key ) && ( current_user_can( 'edit_post_meta', $post_id, $unslashed_meta_key ) || WPCOM_JSON_API_Metadata::is_public( $meta->key ) ) ) { update_post_meta( $post_id, $meta->key, $meta->value ); } @@ -616,8 +651,9 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos if ( ! empty( $media_results['errors'] ) ) $return['media_errors'] = $media_results['errors']; - if ( ! $new && 'publish' !== $post->post_status && isset( $input['title'] ) ) { - $return['other_URLs'] = (object) $this->get_post_permalink_suggestions( $post_id, $input['title'] ); + if ( 'publish' !== $return['status'] && isset( $input['title'] )) { + $sal_site = $this->get_sal_post_by( 'ID', $post_id, $args['context'] ); + $return['other_URLs'] = (object) $sal_site->get_permalink_suggestions( $input['title'] ); } /** This action is documented in json-endpoints/class.wpcom-json-api-site-settings-endpoint.php */ @@ -625,4 +661,15 @@ class WPCOM_JSON_API_Update_Post_v1_2_Endpoint extends WPCOM_JSON_API_Update_Pos return $return; } + + protected function should_load_theme_functions( $post_id = null ) { + if ( empty( $post_id ) ) { + $input = $this->input( true ); + $type = $input['type']; + } else { + $type = get_post_type( $post_id ); + } + + return ! empty( $type ) && ! in_array( $type, array( 'post', 'page', 'revision' ) ); + } } diff --git a/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-term-endpoint.php b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-term-endpoint.php new file mode 100644 index 00000000..499a4295 --- /dev/null +++ b/plugins/jetpack/json-endpoints/class.wpcom-json-api-update-term-endpoint.php @@ -0,0 +1,164 @@ +<?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_Update_Term_Endpoint extends WPCOM_JSON_API_Taxonomy_Endpoint { + // /sites/%s/taxonomies/%s/terms/new -> $blog_id, $taxonomy + // /sites/%s/taxonomies/%s/terms/slug:%s -> $blog_id, $taxonomy, $slug + // /sites/%s/taxonomies/%s/terms/slug:%s/delete -> $blog_id, $taxonomy, $slug + function callback( $path = '', $blog_id = 0, $taxonomy = 'category', $slug = 0 ) { + $blog_id = $this->api->switch_to_blog_and_validate_user( $this->api->get_blog_id( $blog_id ) ); + if ( is_wp_error( $blog_id ) ) { + return $blog_id; + } + + if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) { + $this->load_theme_functions(); + } + + $user = wp_get_current_user(); + if ( ! $user || is_wp_error( $user ) || ! $user->ID ) { + return new WP_Error( 'authorization_required', 'An active access token must be used to manage taxonomies.', 403 ); + } + + $taxonomy_meta = get_taxonomy( $taxonomy ); + if ( false === $taxonomy_meta || ( + ! $taxonomy_meta->public && + ! current_user_can( $taxonomy_meta->cap->manage_terms ) && + ! current_user_can( $taxonomy_meta->cap->edit_terms ) && + ! current_user_can( $taxonomy_meta->cap->delete_terms ) ) ) { + return new WP_Error( 'invalid_taxonomy', 'The taxonomy does not exist', 400 ); + } + + if ( $this->api->ends_with( $path, '/delete' ) ) { + return $this->delete_term( $path, $blog_id, $slug, $taxonomy ); + } else if ( $this->api->ends_with( $path, '/new' ) ) { + return $this->new_term( $path, $blog_id, $taxonomy ); + } + + return $this->update_term( $path, $blog_id, $slug, $taxonomy ); + } + + // /sites/%s/taxonomies/%s/terms/new -> $blog_id, $taxonomy + function new_term( $path, $blog_id, $taxonomy ) { + $args = $this->query_args(); + $input = $this->input(); + if ( ! is_array( $input ) || ! $input || ! strlen( $input['name'] ) ) { + return new WP_Error( 'invalid_input', 'Unknown data passed', 400 ); + } + + $tax = get_taxonomy( $taxonomy ); + if ( ! current_user_can( $tax->cap->manage_terms ) ) { + return new WP_Error( 'unauthorized', 'User cannot edit taxonomy', 403 ); + } + + if ( ! isset( $input['parent'] ) || ! is_taxonomy_hierarchical( $taxonomy ) ) { + $input['parent'] = 0; + } + + if ( $term = get_term_by( 'name', $input['name'], $taxonomy ) ) { + // 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 ) { + return new WP_Error( 'duplicate', 'A taxonomy with that name already exists', 409 ); + } + } + + $data = wp_insert_term( addslashes( $input['name'] ), $taxonomy, array( + 'description' => addslashes( $input['description'] ), + 'parent' => $input['parent'] + ) ); + + if ( is_wp_error( $data ) ) { + return $data; + } + + $term = get_term_by( 'id', $data['term_id'], $taxonomy ); + + $return = $this->get_taxonomy( $term->slug, $taxonomy, $args['context'] ); + if ( ! $return || is_wp_error( $return ) ) { + return $return; + } + + /** This action is documented in json-endpoints/class.wpcom-json-api-site-settings-endpoint.php */ + do_action( 'wpcom_json_api_objects', 'terms' ); + return $return; + } + + // /sites/%s/taxonomies/%s/terms/slug:%s -> $blog_id, $taxonomy, $slug + function update_term( $path, $blog_id, $slug, $taxonomy ) { + $tax = get_taxonomy( $taxonomy ); + if ( ! current_user_can( $tax->cap->edit_terms ) ) { + return new WP_Error( 'unauthorized', 'User cannot edit taxonomy', 403 ); + } + + $term = get_term_by( 'slug', $slug, $taxonomy ); + if ( ! $term || is_wp_error( $term ) ) { + return new WP_Error( 'unknown_taxonomy', 'Unknown taxonomy', 404 ); + } + + $args = $this->query_args(); + $input = $this->input( false ); + if ( ! is_array( $input ) || ! $input ) { + return new WP_Error( 'invalid_input', 'Invalid request input', 400 ); + } + + $update = array(); + if ( ! empty( $input['parent'] ) || is_taxonomy_hierarchical( $taxonomy ) ) { + $update['parent'] = $input['parent']; + } + + if ( ! empty( $input['description'] ) ) { + $update['description'] = addslashes( $input['description'] ); + } + + if ( ! empty( $input['name'] ) ) { + $update['name'] = addslashes( $input['name'] ); + } + + $data = wp_update_term( $term->term_id, $taxonomy, $update ); + $term = get_term_by( 'id', $data['term_id'], $taxonomy ); + + $return = $this->get_taxonomy( $term->slug, $taxonomy, $args['context'] ); + if ( ! $return || is_wp_error( $return ) ) { + return $return; + } + + /** This action is documented in json-endpoints/class.wpcom-json-api-site-settings-endpoint.php */ + do_action( 'wpcom_json_api_objects', 'terms' ); + return $return; + } + + // /sites/%s/taxonomies/%s/terms/slug:%s/delete -> $blog_id, $taxonomy, $slug + function delete_term( $path, $blog_id, $slug, $taxonomy ) { + $term = get_term_by( 'slug', $slug, $taxonomy ); + $tax = get_taxonomy( $taxonomy ); + if ( ! current_user_can( $tax->cap->delete_terms ) ) { + return new WP_Error( 'unauthorized', 'User cannot edit taxonomy', 403 ); + } + + if ( ! $term || is_wp_error( $term ) ) { + return new WP_Error( 'unknown_taxonomy', 'Unknown taxonomy', 404 ); + } + + $args = $this->query_args(); + $return = $this->get_taxonomy( $term->slug, $taxonomy, $args['context'] ); + if ( ! $return || is_wp_error( $return ) ) { + return $return; + } + + /** This action is documented in json-endpoints/class.wpcom-json-api-site-settings-endpoint.php */ + do_action( 'wpcom_json_api_objects', 'terms' ); + + wp_delete_term( $term->term_id, $taxonomy ); + + return array( + 'slug' => (string) $term->slug, + 'success' => true + ); + } +} 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 3236862d..fca8173e 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 @@ -148,6 +148,8 @@ class Jetpack_JSON_API_Plugins_Modify_Endpoint extends Jetpack_JSON_API_Plugins_ remove_action( 'upgrader_process_complete', 'wp_version_check' ); remove_action( 'upgrader_process_complete', 'wp_update_themes' ); + $result = false; + foreach ( $this->plugins as $plugin ) { if ( ! in_array( $plugin, $plugin_updates_needed ) ) { |