diff options
author | Anthony G. Basile <blueness@gentoo.org> | 2017-04-16 04:35:35 -0400 |
---|---|---|
committer | Anthony G. Basile <blueness@gentoo.org> | 2017-04-16 04:35:35 -0400 |
commit | 38a805d24a890dea4b5e90851693afb4e2041c9e (patch) | |
tree | 5f4b08ad64e6750936303d18abc370851e0db260 /plugins/jetpack/_inc/lib | |
parent | Update plugin wordpress-mobile-pack 2.2.9 (diff) | |
download | blogs-gentoo-38a805d24a890dea4b5e90851693afb4e2041c9e.tar.gz blogs-gentoo-38a805d24a890dea4b5e90851693afb4e2041c9e.tar.bz2 blogs-gentoo-38a805d24a890dea4b5e90851693afb4e2041c9e.zip |
Update jetpack 4.8.2
Diffstat (limited to 'plugins/jetpack/_inc/lib')
6 files changed, 430 insertions, 168 deletions
diff --git a/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-react-page.php b/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-react-page.php index a20e28d6..6b27b71f 100644 --- a/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-react-page.php +++ b/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-react-page.php @@ -51,10 +51,8 @@ class Jetpack_React_Page extends Jetpack_Admin_Page { function jetpack_add_dashboard_sub_nav_item() { if ( Jetpack::is_development_mode() || Jetpack::is_active() ) { global $submenu; - if ( current_user_can( 'jetpack_manage_modules' ) || Jetpack::is_module_active( 'protect' ) || current_user_can( 'view_stats' ) ) { - $submenu['jetpack'][] = array( __( 'Dashboard', 'jetpack' ), 'jetpack_admin_page', Jetpack::admin_url( 'page=jetpack#/dashboard' ) ); - } elseif ( current_user_can( 'jetpack_admin_page' ) ) { - $submenu['jetpack'][] = array( __( 'Dashboard', 'jetpack' ), 'jetpack_admin_page', Jetpack::admin_url( 'page=jetpack#/apps' ) ); + if ( current_user_can( 'jetpack_admin_page' ) ) { + $submenu['jetpack'][] = array( __( 'Dashboard', 'jetpack' ), 'jetpack_admin_page', 'admin.php?page=jetpack#/dashboard' ); } } } @@ -65,9 +63,9 @@ class Jetpack_React_Page extends Jetpack_Admin_Page { * @since 4.3.0 */ function jetpack_add_settings_sub_nav_item() { - if ( ( Jetpack::is_development_mode() || Jetpack::is_active() ) && current_user_can( 'jetpack_admin_page' ) ) { + if ( ( Jetpack::is_development_mode() || Jetpack::is_active() ) && current_user_can( 'jetpack_admin_page' ) && current_user_can( 'edit_posts' ) ) { global $submenu; - $submenu['jetpack'][] = array( __( 'Settings', 'jetpack' ), 'jetpack_admin_page', Jetpack::admin_url( 'page=jetpack#/settings' ) ); + $submenu['jetpack'][] = array( __( 'Settings', 'jetpack' ), 'jetpack_admin_page', 'admin.php?page=jetpack#/settings' ); } } @@ -139,7 +137,10 @@ class Jetpack_React_Page extends Jetpack_Admin_Page { if ( false === $static_html ) { // If we still have nothing, display an error - esc_html_e( 'Error fetching static.html.', 'jetpack' ); + echo '<p>'; + esc_html_e( 'Error fetching static.html. Try running: ', 'jetpack' ); + echo '<code>yarn distclean && yarn build</code>'; + echo '</p>'; } else { // We got the static.html so let's display it @@ -203,9 +204,6 @@ class Jetpack_React_Page extends Jetpack_Admin_Page { wp_enqueue_script( 'jp-tracks', '//stats.wp.com/w.js', array(), gmdate( 'YW' ), true ); } - $localeSlug = explode( '_', jetpack_get_user_locale() ); - $localeSlug = $localeSlug[0]; - // Collecting roles that can view site stats $stats_roles = array(); $enabled_roles = function_exists( 'stats_get_option' ) ? stats_get_option( 'roles' ) : array( 'administrator' ); @@ -234,6 +232,17 @@ class Jetpack_React_Page extends Jetpack_Admin_Page { ? get_permalink( $last_post[0]->ID ) : get_home_url(); + // Get information about current theme. + $current_theme = wp_get_theme(); + + // Get all themes that Infinite Scroll provides support for natively. + $inf_scr_support_themes = array(); + foreach ( Jetpack::glob_php( JETPACK__PLUGIN_DIR . 'modules/infinite-scroll/themes' ) as $path ) { + if ( is_readable( $path ) ) { + $inf_scr_support_themes[] = basename( $path, '.php' ); + } + } + // Add objects to be passed to the initial state of the app wp_localize_script( 'react-plugin', 'Initial_State', array( 'WP_API_root' => esc_url_raw( rest_url() ), @@ -254,7 +263,6 @@ class Jetpack_React_Page extends Jetpack_Admin_Page { 'dismissedNotices' => $this->get_dismissed_jetpack_notices(), 'isDevVersion' => Jetpack::is_development_version(), 'currentVersion' => JETPACK__VERSION, - 'happinessGravIds' => jetpack_get_happiness_gravatar_ids(), 'getModules' => $modules, 'showJumpstart' => jetpack_show_jumpstart(), 'showHolidaySnow' => function_exists( 'jetpack_show_holiday_snow_option' ) ? jetpack_show_holiday_snow_option() : false, @@ -270,6 +278,7 @@ class Jetpack_React_Page extends Jetpack_Admin_Page { ), 'roles' => $stats_roles, ), + 'settings' => $this->get_flattened_settings( $modules ), 'settingNames' => array( 'jetpack_holiday_snow_enabled' => function_exists( 'jetpack_holiday_snow_option_name' ) ? jetpack_holiday_snow_option_name() : false, ), @@ -277,8 +286,30 @@ class Jetpack_React_Page extends Jetpack_Admin_Page { // 'othersLinked' => Jetpack::get_other_linked_admins(), 'currentUser' => jetpack_current_user_data(), ), + 'siteData' => array( + 'icon' => has_site_icon() + ? apply_filters( 'jetpack_photon_url', get_site_icon_url(), array( 'w' => 64 ) ) + : '', + 'siteVisibleToSearchEngines' => '1' == get_option( 'blog_public' ), + /** + * Whether promotions are visible or not. + * + * @since 4.8.0 + * + * @param bool $are_promotions_active Status of promotions visibility. True by default. + */ + 'showPromotions' => apply_filters( 'jetpack_show_promotions', true ), + 'isAutomatedTransfer' => jetpack_is_automated_transfer_site(), + ), + 'themeData' => array( + 'name' => $current_theme->get( 'Name' ), + 'hasUpdate' => (bool) get_theme_update_available( $current_theme ), + 'support' => array( + 'infinite-scroll' => current_theme_supports( 'infinite-scroll' ) || in_array( $current_theme->get_stylesheet(), $inf_scr_support_themes ), + ), + ), 'locale' => $this->get_i18n_data(), - 'localeSlug' => $localeSlug, + 'localeSlug' => join( '-', explode( '_', jetpack_get_user_locale() ) ), 'jetpackStateNotices' => array( 'messageCode' => Jetpack::state( 'message' ), 'errorCode' => Jetpack::state( 'error' ), @@ -289,37 +320,19 @@ class Jetpack_React_Page extends Jetpack_Admin_Page { 'lastPostUrl' => esc_url( $last_post ), ) ); } -} -/* - * List of happiness Gravatar IDs - * - * @todo move to functions.global.php when available - * @since 4.1.0 - * @return array - */ -function jetpack_get_happiness_gravatar_ids() { - return array( - '623f42e878dbd146ddb30ebfafa1375b', - '561be467af56cefa58e02782b7ac7510', - 'd8ad409290a6ae7b60f128a0b9a0c1c5', - '790618302648bd80fa8a55497dfd8ac8', - '6e238edcb0664c975ccb9e8e80abb307', - '4e6c84eeab0a1338838a9a1e84629c1a', - '9d4b77080c699629e846d3637b3a661c', - '4626de7797aada973c1fb22dfe0e5109', - '190cf13c9cd358521085af13615382d5', - 'f7006d10e9f7dd7bea89a001a2a2fd59', - '16acbc88e7aa65104ed289d736cb9698', - '4d5ad4219c6f676ea1e7d40d2e8860e8', - 'e301f7d01b09e7578fdfc1b1ec1bc08d', - '42f4c73f5337486e199f6e3b3910f168', - 'e7b26de48e76498cff880abca1eed8da', - '764fb02aaae2ff64c0625c763d82b74e', - '4988305772319fb9bc8fce0a7acb3aa1', - '5d8695c4b81592f1255721d2644627ca', - '0e2249a7de3404bc6d5207a45e911187', - ); + /** + * Returns an array of modules and settings both as first class members of the object. + * + * @param array $modules the result of an API request to get all modules. + * + * @return array flattened settings with modules. + */ + function get_flattened_settings( $modules ) { + $core_api_endpoint = new Jetpack_Core_API_Data(); + $settings = $core_api_endpoint->get_all_options(); + return $settings->data; + } } /* @@ -355,32 +368,6 @@ function jetpack_show_jumpstart() { return true; } -/* - * Gather data about the master user. - * - * @since 4.1.0 - * - * @return array - */ -function jetpack_master_user_data() { - $masterID = Jetpack_Options::get_option( 'master_user' ); - if ( ! get_user_by( 'id', $masterID ) ) { - return false; - } - - $jetpack_user = get_userdata( $masterID ); - $wpcom_user = Jetpack::get_connected_user_data( $jetpack_user->ID ); - $gravatar = get_avatar( $jetpack_user->ID, 40 ); - - $master_user_data = array( - 'jetpackUser' => $jetpack_user, - 'wpcomUser' => $wpcom_user, - 'gravatar' => $gravatar, - ); - - return $master_user_data; -} - /** * Gather data about the current user. * @@ -389,18 +376,18 @@ function jetpack_master_user_data() { * @return array */ function jetpack_current_user_data() { - global $current_user; + $current_user = wp_get_current_user(); $is_master_user = $current_user->ID == Jetpack_Options::get_option( 'master_user' ); $dotcom_data = Jetpack::get_connected_user_data(); // Add connected user gravatar to the returned dotcom_data. - $dotcom_data['avatar'] = get_avatar_url( $dotcom_data['email'] ); + $dotcom_data['avatar'] = get_avatar_url( $dotcom_data['email'], array( 'size' => 64, 'default' => 'mysteryman' ) ); $current_user_data = array( 'isConnected' => Jetpack::is_user_connected( $current_user->ID ), 'isMaster' => $is_master_user, 'username' => $current_user->user_login, 'wpcomUser' => $dotcom_data, - 'gravatar' => get_avatar( $current_user->ID, 40 ), + 'gravatar' => get_avatar( $current_user->ID, 40, 'mm', '', array( 'force_display' => true ) ), 'permissions' => array( 'admin_page' => current_user_can( 'jetpack_admin_page' ), 'connect' => current_user_can( 'jetpack_connect' ), @@ -409,6 +396,7 @@ function jetpack_current_user_data() { 'network_admin' => current_user_can( 'jetpack_network_admin_page' ), 'network_sites_page' => current_user_can( 'jetpack_network_sites_page' ), 'edit_posts' => current_user_can( 'edit_posts' ), + 'publish_posts' => current_user_can( 'publish_posts' ), 'manage_options' => current_user_can( 'manage_options' ), 'view_stats' => current_user_can( 'view_stats' ), 'manage_plugins' => current_user_can( 'install_plugins' ) diff --git a/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-settings-page.php b/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-settings-page.php index dd9b5ea1..0c8d5bf0 100644 --- a/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-settings-page.php +++ b/plugins/jetpack/_inc/lib/admin-pages/class.jetpack-settings-page.php @@ -24,7 +24,10 @@ class Jetpack_Settings_Page extends Jetpack_Admin_Page { // If static.html isn't there, there's nothing else we can do. if ( false === $static_html ) { - esc_html_e( 'Error fetching static.html.', 'jetpack' ); + echo '<p>'; + esc_html_e( 'Error fetching static.html. Try running: ', 'jetpack' ); + echo '<code>yarn distclean && yarn build</code>'; + echo '</p>'; return; } diff --git a/plugins/jetpack/_inc/lib/class.core-rest-api-endpoints.php b/plugins/jetpack/_inc/lib/class.core-rest-api-endpoints.php index 4fc6438f..4b257b67 100644 --- a/plugins/jetpack/_inc/lib/class.core-rest-api-endpoints.php +++ b/plugins/jetpack/_inc/lib/class.core-rest-api-endpoints.php @@ -202,6 +202,28 @@ class Jetpack_Core_Json_Api_Endpoints { ) ) ); + // Check if the API key for a specific service is valid or not + register_rest_route( 'jetpack/v4', '/module/(?P<service>[a-z\-]+)/key/check', array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $module_data_endpoint, 'key_check' ), + 'permission_callback' => __CLASS__ . '::update_settings_permission_check', + 'sanitize_callback' => 'sanitize_text_field', + ) ); + + register_rest_route( 'jetpack/v4', '/module/(?P<service>[a-z\-]+)/key/check', array( + 'methods' => WP_REST_Server::EDITABLE, + 'callback' => array( $module_data_endpoint, 'key_check' ), + 'permission_callback' => __CLASS__ . '::update_settings_permission_check', + 'sanitize_callback' => 'sanitize_text_field', + 'args' => array( + 'api_key' => array( + 'default' => '', + 'type' => 'string', + 'validate_callback' => __CLASS__ . '::validate_alphanum', + ), + ) + ) ); + // Update any Jetpack module option or setting register_rest_route( 'jetpack/v4', '/settings', array( 'methods' => WP_REST_Server::EDITABLE, @@ -663,7 +685,8 @@ class Jetpack_Core_Json_Api_Endpoints { public static function get_site_data() { if ( $site_id = Jetpack_Options::get_option( 'id' ) ) { - $response = Jetpack_Client::wpcom_json_api_request_as_blog( sprintf( '/sites/%d', $site_id ), '1.1' ); + + $response = Jetpack_Client::wpcom_json_api_request_as_blog( sprintf( '/sites/%d', $site_id ) .'?force=wpcom', '1.1' ); if ( 200 !== wp_remote_retrieve_response_code( $response ) ) { return new WP_Error( 'site_data_fetch_failed', esc_html__( 'Failed fetching site data. Try again later.', 'jetpack' ), array( 'status' => 400 ) ); @@ -1002,7 +1025,7 @@ class Jetpack_Core_Json_Api_Endpoints { // Carousel 'carousel_background_color' => array( - 'description' => esc_html__( 'Background color.', 'jetpack' ), + 'description' => esc_html__( 'Color scheme.', 'jetpack' ), 'type' => 'string', 'default' => 'black', 'enum' => array( @@ -1033,7 +1056,7 @@ class Jetpack_Core_Json_Api_Endpoints { 'jp_group' => 'comments', ), 'jetpack_comment_form_color_scheme' => array( - 'description' => esc_html__( "Color Scheme", 'jetpack' ), + 'description' => esc_html__( "Color scheme", 'jetpack' ), 'type' => 'string', 'default' => 'light', 'enum' => array( @@ -1165,32 +1188,16 @@ class Jetpack_Core_Json_Api_Endpoints { // Mobile Theme 'wp_mobile_excerpt' => array( 'description' => esc_html__( 'Excerpts', 'jetpack' ), - 'type' => 'string', - 'default' => 'disabled', - 'enum' => array( - 'enabled', - 'disabled', - ), - 'enum_labels' => array( - 'enabled' => esc_html__( 'Enable excerpts on front page and on archive pages', 'jetpack' ), - 'disabled' => esc_html__( 'Show full posts on front page and on archive pages', 'jetpack' ), - ), - 'validate_callback' => __CLASS__ . '::validate_list_item', + 'type' => 'boolean', + 'default' => 0, + 'validate_callback' => __CLASS__ . '::validate_boolean', 'jp_group' => 'minileven', ), 'wp_mobile_featured_images' => array( 'description' => esc_html__( 'Featured Images', 'jetpack' ), - 'type' => 'string', - 'default' => 'disabled', - 'enum' => array( - 'enabled', - 'disabled', - ), - 'enum_labels' => array( - 'enabled' => esc_html__( 'Display featured images', 'jetpack' ), - 'disabled' => esc_html__( 'Hide all featured images', 'jetpack' ), - ), - 'validate_callback' => __CLASS__ . '::validate_list_item', + 'type' => 'boolean', + 'default' => 0, + 'validate_callback' => __CLASS__ . '::validate_boolean', 'jp_group' => 'minileven', ), 'wp_mobile_app_promos' => array( @@ -1491,28 +1498,28 @@ class Jetpack_Core_Json_Api_Endpoints { 'description' => esc_html__( 'Google Search Console', 'jetpack' ), 'type' => 'string', 'default' => '', - 'validate_callback' => __CLASS__ . '::validate_alphanum', + 'validate_callback' => __CLASS__ . '::validate_verification_service', 'jp_group' => 'verification-tools', ), 'bing' => array( 'description' => esc_html__( 'Bing Webmaster Center', 'jetpack' ), 'type' => 'string', 'default' => '', - 'validate_callback' => __CLASS__ . '::validate_alphanum', + 'validate_callback' => __CLASS__ . '::validate_verification_service', 'jp_group' => 'verification-tools', ), 'pinterest' => array( 'description' => esc_html__( 'Pinterest Site Verification', 'jetpack' ), 'type' => 'string', 'default' => '', - 'validate_callback' => __CLASS__ . '::validate_alphanum', + 'validate_callback' => __CLASS__ . '::validate_verification_service', 'jp_group' => 'verification-tools', ), 'yandex' => array( - 'description' => esc_html__( 'Yandex Site Verification', 'jetpack' ), - 'type' => 'string', - 'default' => '', - 'validate_callback' => __CLASS__ . '::validate_alphanum', + 'description' => esc_html__( 'Yandex Site Verification', 'jetpack' ), + 'type' => 'string', + 'default' => '', + 'validate_callback' => __CLASS__ . '::validate_verification_service', 'jp_group' => 'verification-tools', ), 'enable_header_ad' => array( @@ -1606,6 +1613,23 @@ class Jetpack_Core_Json_Api_Endpoints { 'jp_group' => 'settings', ), + // Akismet - Not a module, but a plugin. The options can be passed and handled differently. + 'akismet_show_user_comments_approved' => array( + 'description' => '', + 'type' => 'boolean', + 'default' => 0, + 'validate_callback' => __CLASS__ . '::validate_boolean', + 'jp_group' => 'settings', + ), + + 'wordpress_api_key' => array( + 'description' => '', + 'type' => 'string', + 'default' => '', + 'validate_callback' => __CLASS__ . '::validate_alphanum', + 'jp_group' => 'settings', + ), + ); // Add modules to list so they can be toggled @@ -1754,13 +1778,31 @@ class Jetpack_Core_Json_Api_Endpoints { * @return bool */ public static function validate_alphanum( $value = '', $request, $param ) { - if ( ! empty( $value ) && ( ! is_string( $value ) || ! preg_match( '/[a-z0-9]+/i', $value ) ) ) { + if ( ! empty( $value ) && ( ! is_string( $value ) || ! preg_match( '/^[a-z0-9]+$/i', $value ) ) ) { return new WP_Error( 'invalid_param', sprintf( esc_html__( '%s must be an alphanumeric string.', 'jetpack' ), $param ) ); } return true; } /** + * Validates that the parameter is a tag or id for a verification service, or an empty string (to be able to clear the field). + * + * @since 4.6.0 + * + * @param string $value Value to check. + * @param WP_REST_Request $request + * @param string $param Name of the parameter passed to endpoint holding $value. + * + * @return bool + */ + public static function validate_verification_service( $value = '', $request, $param ) { + if ( ! empty( $value ) && ! ( is_string( $value ) && ( preg_match( '/^[a-z0-9_-]+$/i', $value ) || preg_match( '#^<meta name="([a-z0-9_\-.:]+)?" content="([a-z0-9_-]+)?" />$#i', $value ) ) ) ) { + return new WP_Error( 'invalid_param', sprintf( esc_html__( '%s must be an alphanumeric string or a verification tag.', 'jetpack' ), $param ) ); + } + return true; + } + + /** * Validates that the parameter is among the roles allowed for Stats. * * @since 4.3.0 @@ -2001,17 +2043,21 @@ class Jetpack_Core_Json_Api_Endpoints { * @return array */ public static function prepare_modules_for_response( $modules = '', $slug = null ) { - if ( get_option( 'permalink_structure' ) ) { - $sitemap_url = home_url( '/sitemap.xml' ); - $news_sitemap_url = home_url( '/news-sitemap.xml' ); + global $wp_rewrite; + + /** This filter is documented in modules/sitemaps/sitemaps.php */ + $location = apply_filters( 'jetpack_sitemap_location', '' ); + + if ( $wp_rewrite->using_index_permalinks() ) { + $sitemap_url = home_url( '/index.php' . $location . '/sitemap.xml' ); + $news_sitemap_url = home_url( '/index.php' . $location . '/news-sitemap.xml' ); + } else if ( $wp_rewrite->using_permalinks() ) { + $sitemap_url = home_url( $location . '/sitemap.xml' ); + $news_sitemap_url = home_url( $location . '/news-sitemap.xml' ); } else { - $sitemap_url = home_url( '/?jetpack-sitemap=true' ); - $news_sitemap_url = home_url( '/?jetpack-news-sitemap=true' ); + $sitemap_url = home_url( $location . '/?jetpack-sitemap=sitemap.xml' ); + $news_sitemap_url = home_url( $location . '/?jetpack-sitemap=news-sitemap.xml' ); } - /** This filter is documented in modules/sitemaps/sitemaps.php */ - $sitemap_url = apply_filters( 'jetpack_sitemap_location', $sitemap_url ); - /** This filter is documented in modules/sitemaps/sitemaps.php */ - $news_sitemap_url = apply_filters( 'jetpack_news_sitemap_location', $news_sitemap_url ); if ( is_null( $slug ) && isset( $modules['sitemaps'] ) ) { // Is a list of modules @@ -2121,16 +2167,6 @@ class Jetpack_Core_Json_Api_Endpoints { unset( $options['unignore_phrase'] ); break; - case 'minileven': - $options['wp_mobile_excerpt']['current_value'] = - 1 === intval( $options['wp_mobile_excerpt']['current_value'] ) ? - 'enabled' : 'disabled'; - - $options['wp_mobile_featured_images']['current_value'] = - 1 === intval( $options['wp_mobile_featured_images']['current_value'] ) ? - 'enabled' : 'disabled'; - break; - case 'stats': // It's local, but it must be broken apart since it's saved as an array. if ( ! function_exists( 'stats_get_options' ) ) { @@ -2237,22 +2273,21 @@ class Jetpack_Core_Json_Api_Endpoints { return false; } - // If the module is inactive, load the class to use the method. - if ( ! did_action( 'jetpack_module_loaded_' . $module ) ) { - // Class can't be found so do nothing. - if ( ! @include( Jetpack::get_module_path( $module ) ) ) { - return false; - } - } - // Do what is necessary for each module. switch ( $module ) { case 'monitor': - $monitor = new Jetpack_Monitor(); - $value = $monitor->user_receives_notifications( false ); + // Load the class to use the method. If class can't be found, do nothing. + if ( ! class_exists( 'Jetpack_Monitor' ) && ! include_once( Jetpack::get_module_path( $module ) ) ) { + return false; + } + $value = Jetpack_Monitor::user_receives_notifications( false ); break; case 'post-by-email': + // Load the class to use the method. If class can't be found, do nothing. + if ( ! class_exists( 'Jetpack_Post_By_Email' ) && ! include_once( Jetpack::get_module_path( $module ) ) ) { + return false; + } $post_by_email = new Jetpack_Post_By_Email(); $value = $post_by_email->get_post_by_email_address(); if ( $value === null ) { @@ -2337,7 +2372,7 @@ class Jetpack_Core_Json_Api_Endpoints { * @return bool */ private static function core_is_plugin_active( $plugin ) { - if ( ! function_exists( 'get_plugins' ) ) { + if ( ! function_exists( 'is_plugin_active' ) ) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } diff --git a/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-module-endpoints.php b/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-module-endpoints.php index 9a4959ef..158557ce 100644 --- a/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-module-endpoints.php +++ b/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-module-endpoints.php @@ -34,7 +34,9 @@ class Jetpack_Core_API_Module_Toggle_Endpoint * * @since 4.3.0 * - * @param string|WP_REST_Request $request { + * @param string|WP_REST_Request $request It's a WP_REST_Request when called from endpoint /module/<slug>/* + * and a string when called from Jetpack_Core_API_Data->update_data. + * { * Array of parameters received by request. * * @type string $slug Module slug. @@ -43,9 +45,19 @@ class Jetpack_Core_API_Module_Toggle_Endpoint * @return bool|WP_Error True if module was activated. Otherwise, a WP_Error instance with the corresponding error. */ public function activate_module( $request ) { - $module_slug = isset( $request['slug'] ) - ? $request['slug'] - : $request; + $module_slug = ''; + + if ( + ( + is_array( $request ) + || is_object( $request ) + ) + && isset( $request['slug'] ) + ) { + $module_slug = $request['slug']; + } else { + $module_slug = $request; + } if ( ! Jetpack::is_module( $module_slug ) ) { return new WP_Error( @@ -74,7 +86,9 @@ class Jetpack_Core_API_Module_Toggle_Endpoint * * @since 4.3.0 * - * @param string|WP_REST_Request $request { + * @param string|WP_REST_Request $request It's a WP_REST_Request when called from endpoint /module/<slug>/* + * and a string when called from Jetpack_Core_API_Data->update_data. + * { * Array of parameters received by request. * * @type string $slug Module slug. @@ -83,9 +97,19 @@ class Jetpack_Core_API_Module_Toggle_Endpoint * @return bool|WP_Error True if module was activated. Otherwise, a WP_Error instance with the corresponding error. */ public function deactivate_module( $request ) { - $module_slug = isset( $request['slug'] ) - ? $request['slug'] - : $request; + $module_slug = ''; + + if ( + ( + is_array( $request ) + || is_object( $request ) + ) + && isset( $request['slug'] ) + ) { + $module_slug = $request['slug']; + } else { + $module_slug = $request; + } if ( ! Jetpack::is_module( $module_slug ) ) { return new WP_Error( @@ -302,7 +326,7 @@ class Jetpack_Core_API_Data extends Jetpack_Core_API_XMLRPC_Consumer_Endpoint { return $this->get_module( $request ); } - return $this->get_all_options( $request ); + return $this->get_all_options(); } else { return $this->update_data( $request ); } @@ -356,15 +380,13 @@ class Jetpack_Core_API_Data extends Jetpack_Core_API_XMLRPC_Consumer_Endpoint { } /** - * Get information about all Jetpack module settings. + * Get information about all Jetpack module options and settings. * * @since 4.6.0 * - * @param WP_REST_Request $request The request sent to the WP REST API. - * - * @return array + * @return WP_REST_Response $response */ - public function get_all_options( $request ) { + public function get_all_options() { $response = array(); $modules = Jetpack::get_available_modules(); @@ -381,9 +403,39 @@ class Jetpack_Core_API_Data extends Jetpack_Core_API_XMLRPC_Consumer_Endpoint { } } - // Add the Holiday snow current value + $settings = Jetpack_Core_Json_Api_Endpoints::get_updateable_data_list( 'settings' ); $holiday_snow_option_name = Jetpack_Core_Json_Api_Endpoints::holiday_snow_option_name(); - $response[ $holiday_snow_option_name ] = get_option( $holiday_snow_option_name ) === 'letitsnow'; + + foreach ( $settings as $setting => $properties ) { + switch ( $setting ) { + case $holiday_snow_option_name: + $response[ $setting ] = get_option( $holiday_snow_option_name ) === 'letitsnow'; + break; + + case 'wordpress_api_key': + // When field is clear, return empty. Otherwise it would return "false". + if ( '' === get_option( 'wordpress_api_key', '' ) ) { + $response[ $setting ] = ''; + } else { + if ( ! class_exists( 'Akismet' ) ) { + if ( file_exists( WP_PLUGIN_DIR . '/akismet/class.akismet.php' ) ) { + require_once WP_PLUGIN_DIR . '/akismet/class.akismet.php'; + } + } + $response[ $setting ] = class_exists( 'Akismet' ) ? Akismet::get_api_key() : ''; + } + break; + + default: + $response[ $setting ] = Jetpack_Core_Json_Api_Endpoints::cast_value( get_option( $setting ), $settings[ $setting ] ); + break; + } + } + + if ( ! function_exists( 'is_plugin_active' ) ) { + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + } + $response['akismet'] = is_plugin_active( 'akismet/akismet.php' ); return rest_ensure_response( $response ); } @@ -483,7 +535,14 @@ class Jetpack_Core_API_Data extends Jetpack_Core_API_XMLRPC_Consumer_Endpoint { ? $toggle_module->activate_module( $option ) : $toggle_module->deactivate_module( $option ); - if ( is_wp_error( $toggle_result ) ) { + if ( + is_wp_error( $toggle_result ) + && 'already_inactive' === $toggle_result->get_error_code() + ) { + + // If the module is already inactive, we don't fail + $updated = true; + } elseif ( is_wp_error( $toggle_result ) ) { $error = $toggle_result->get_error_message(); } else { $updated = true; @@ -520,7 +579,12 @@ class Jetpack_Core_API_Data extends Jetpack_Core_API_XMLRPC_Consumer_Endpoint { continue; } - if ( ! Jetpack::is_module_active( $option_attrs['jp_group'] ) ) { + if ( + 'any' !== $request['slug'] + && ! Jetpack::is_module_active( $option_attrs['jp_group'] ) + ) { + + // We only take note of skipped options when updating one module $not_updated[ $option ] = esc_html__( 'The requested Jetpack module is inactive.', 'jetpack' ); continue; } @@ -731,6 +795,57 @@ class Jetpack_Core_API_Data extends Jetpack_Core_API_XMLRPC_Consumer_Endpoint { $updated = get_option( $option ) != $value ? update_option( $option, (bool) $value ? 'letitsnow' : '' ) : true; break; + case 'akismet_show_user_comments_approved': + + // Save Akismet option '1' or '0' like it's done in akismet/class.akismet-admin.php + $updated = get_option( $option ) != $value ? update_option( $option, (bool) $value ? '1' : '0' ) : true; + break; + + case 'wordpress_api_key': + + if ( ! file_exists( WP_PLUGIN_DIR . '/akismet/class.akismet.php' ) ) { + $error = esc_html__( 'Please install Akismet.', 'jetpack' ); + $updated = false; + break; + } + + if ( ! defined( 'AKISMET_VERSION' ) ) { + $error = esc_html__( 'Please activate Akismet.', 'jetpack' ); + $updated = false; + break; + } + + // Allow to clear the API key field + if ( '' === $value ) { + $updated = get_option( $option ) != $value ? update_option( $option, $value ) : true; + break; + } + + require_once WP_PLUGIN_DIR . '/akismet/class.akismet.php'; + require_once WP_PLUGIN_DIR . '/akismet/class.akismet-admin.php'; + + if ( class_exists( 'Akismet_Admin' ) && method_exists( 'Akismet_Admin', 'save_key' ) ) { + if ( Akismet::verify_key( $value ) === 'valid' ) { + $akismet_user = Akismet_Admin::get_akismet_user( $value ); + if ( $akismet_user ) { + if ( in_array( $akismet_user->status, array( 'active', 'active-dunning', 'no-sub' ) ) ) { + $updated = get_option( $option ) != $value ? update_option( $option, $value ) : true; + break; + } else { + $error = esc_html__( "Akismet user status doesn't allow to update the key", 'jetpack' ); + } + } else { + $error = esc_html__( 'Invalid Akismet user', 'jetpack' ); + } + } else { + $error = esc_html__( 'Invalid Akismet key', 'jetpack' ); + } + } else { + $error = esc_html__( 'Akismet is not installed or active', 'jetpack' ); + } + $updated = false; + break; + case 'google_analytics_tracking_id': $grouped_options = $grouped_options_current = (array) get_option( 'jetpack_wga' ); $grouped_options[ 'code' ] = $value; @@ -739,10 +854,6 @@ class Jetpack_Core_API_Data extends Jetpack_Core_API_XMLRPC_Consumer_Endpoint { $updated = $grouped_options_current != $grouped_options ? update_option( 'jetpack_wga', $grouped_options ) : true; break; - case 'wp_mobile_featured_images': - case 'wp_mobile_excerpt': - $value = ( 'enabled' === $value ) ? '1' : '0'; - // break intentionally omitted default: // If option value was the same, consider it done. $updated = get_option( $option ) != $value ? update_option( $option, $value ) : true; @@ -774,18 +885,14 @@ class Jetpack_Core_API_Data extends Jetpack_Core_API_XMLRPC_Consumer_Endpoint { foreach ( $not_updated as $not_updated_option => $not_updated_message ) { if ( ! empty( $not_updated_message ) ) { $not_updated_messages[] = sprintf( - /* Translators: the first variable is a module option or slug, or setting. The second is the error message . */ - __( 'Extra info for %1$s: %2$s', 'jetpack' ), + /* Translators: the first variable is a module option or slug, or setting. The second is the error message . */ + __( '%1$s: %2$s', 'jetpack' ), $not_updated_option, $not_updated_message ); } } if ( ! empty( $error ) ) { $error .= ' '; } - $error .= sprintf( - /* Translators: the plural variable is a comma-separated list. Example: dog, cat, bird. */ - _n( 'Option not updated: %s.', 'Options not updated: %s.', $not_updated_count, 'jetpack' ), - join( ', ', array_keys( $not_updated ) ) ); if ( ! empty( $not_updated_messages ) ) { $error .= ' ' . join( '. ', $not_updated_messages ); } @@ -844,6 +951,19 @@ class Jetpack_Core_API_Data extends Jetpack_Core_API_XMLRPC_Consumer_Endpoint { return current_user_can( 'jetpack_admin_page' ); } else { $module = Jetpack_Core_Json_Api_Endpoints::get_module_requested(); + if ( empty( $module ) ) { + $params = $request->get_json_params(); + if ( ! is_array( $params ) ) { + $params = $request->get_body_params(); + } + $options = Jetpack_Core_Json_Api_Endpoints::get_updateable_data_list( $params ); + foreach ( $options as $option => $definition ) { + if ( in_array( $options[ $option ]['jp_group'], array( 'after-the-deadline', 'post-by-email' ) ) ) { + $module = $options[ $option ]['jp_group']; + break; + } + } + } // User is trying to create, regenerate or delete its PbE || ATD settings. if ( 'post-by-email' === $module || 'after-the-deadline' === $module ) { return current_user_can( 'edit_posts' ) && current_user_can( 'jetpack_admin_page' ); @@ -873,6 +993,27 @@ class Jetpack_Core_API_Module_Data_Endpoint { } /** + * Decide against which service to check the key. + * + * @since 4.8.0 + * + * @param WP_REST_Request $request + * + * @return bool + */ + public function key_check( $request ) { + switch( $request['service'] ) { + case 'akismet': + $params = $request->get_json_params(); + if ( isset( $params['api_key'] ) && ! empty( $params['api_key'] ) ) { + return $this->check_akismet_key( $params['api_key'] ); + } + return $this->check_akismet_key(); + } + return false; + } + + /** * Get number of blocked intrusion attempts. * * @since 4.3.0 @@ -907,13 +1048,47 @@ class Jetpack_Core_API_Module_Data_Endpoint { } /** - * Is Akismet registered and active? + * Verify the Akismet API key. * - * @since 4.3.0 + * @since 4.8.0 * - * @return bool|WP_Error True if Akismet is active and registered. Otherwise, a WP_Error instance with the corresponding error. + * @param string $api_key Optional API key to check. + * + * @return array Information about the key. 'validKey' is true if key is valid, false otherwise. */ - private function akismet_is_active_and_registered() { + public function check_akismet_key( $api_key = '' ) { + $akismet_status = $this->akismet_class_exists(); + if ( is_wp_error( $akismet_status ) ) { + return rest_ensure_response( array( + 'validKey' => false, + 'invalidKeyCode' => $akismet_status->get_error_code(), + 'invalidKeyMessage' => $akismet_status->get_error_message(), + ) ); + } + + $key_status = Akismet::check_key_status( empty( $api_key ) ? Akismet::get_api_key() : $api_key ); + + if ( ! $key_status || 'invalid' === $key_status || 'failed' === $key_status ) { + return rest_ensure_response( array( + 'validKey' => false, + 'invalidKeyCode' => 'invalid_key', + 'invalidKeyMessage' => esc_html__( 'Invalid Akismet key. Please contact support.', 'jetpack' ), + ) ); + } + + return rest_ensure_response( array( + 'validKey' => isset( $key_status[1] ) && 'valid' === $key_status[1] + ) ); + } + + /** + * Check if Akismet class file exists and if class is loaded. + * + * @since 4.8.0 + * + * @return bool|WP_Error Returns true if class file exists and class is loaded, WP_Error otherwise. + */ + private function akismet_class_exists() { if ( ! file_exists( WP_PLUGIN_DIR . '/akismet/class.akismet.php' ) ) { return new WP_Error( 'not_installed', esc_html__( 'Please install Akismet.', 'jetpack' ), array( 'status' => 400 ) ); } @@ -922,6 +1097,21 @@ class Jetpack_Core_API_Module_Data_Endpoint { return new WP_Error( 'not_active', esc_html__( 'Please activate Akismet.', 'jetpack' ), array( 'status' => 400 ) ); } + return true; + } + + /** + * Is Akismet registered and active? + * + * @since 4.3.0 + * + * @return bool|WP_Error True if Akismet is active and registered. Otherwise, a WP_Error instance with the corresponding error. + */ + private function akismet_is_active_and_registered() { + if ( is_wp_error( $akismet_exists = $this->akismet_class_exists() ) ) { + return $akismet_exists; + } + // What about if Akismet is put in a sub-directory or maybe in mu-plugins? require_once WP_PLUGIN_DIR . '/akismet/class.akismet.php'; require_once WP_PLUGIN_DIR . '/akismet/class.akismet-admin.php'; diff --git a/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-xmlrpc-consumer-endpoint.php b/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-xmlrpc-consumer-endpoint.php index 6a54ed56..abfc8627 100644 --- a/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-xmlrpc-consumer-endpoint.php +++ b/plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-xmlrpc-consumer-endpoint.php @@ -19,7 +19,7 @@ abstract class Jetpack_Core_API_XMLRPC_Consumer_Endpoint { * * @param Jetpack_IXR_Client $xmlrpc */ - public function __construct( $xmlrpc ) { + public function __construct( $xmlrpc = null ) { $this->xmlrpc = $xmlrpc; } diff --git a/plugins/jetpack/_inc/lib/icalendar-reader.php b/plugins/jetpack/_inc/lib/icalendar-reader.php index e93a1f85..81758475 100644 --- a/plugins/jetpack/_inc/lib/icalendar-reader.php +++ b/plugins/jetpack/_inc/lib/icalendar-reader.php @@ -84,6 +84,51 @@ class iCalendarReader { return $vcal['VEVENT']; } + function apply_timezone_offset( $events ) { + if ( ! $events ) { + return $events; + } + + // get timezone offset from the timezone name. + $timezone_name = get_option( 'timezone_string' ); + if ( $timezone_name ) { + $timezone = new DateTimeZone( $timezone_name ); + } else { + // If the timezone isn't set then the GMT offset must be set. + // generate a DateInterval object from the timezone offset + $gmt_offset = get_option( 'gmt_offset' ) * HOUR_IN_MINUTES; + $timezone_offset_interval = date_interval_create_from_date_string( "{$gmt_offset} minutes" ); + $timezone = new DateTimeZone( 'UTC' ); + } + + $offsetted_events = array(); + + foreach ( $events as $event ) { + // Don't handle all-day events + if ( 8 < strlen( $event['DTSTART'] ) ) { + $start_time = preg_replace( '/Z$/', '', $event['DTSTART'] ); + $start_time = new DateTime( $start_time, $this->timezone ); + $start_time->setTimeZone( $timezone ); + + $end_time = preg_replace( '/Z$/', '', $event['DTEND'] ); + $end_time = new DateTime( $end_time, $this->timezone ); + $end_time->setTimeZone( $timezone ); + + if ( $timezone_offset_interval ) { + $start_time->add( $timezone_offset_interval ); + $end_time->add( $timezone_offset_interval ); + } + + $event['DTSTART'] = $start_time->format( 'YmdHis\Z' ); + $event['DTEND'] = $end_time->format( 'YmdHis\Z' ); + } + + $offsetted_events[] = $event; + } + + return $offsetted_events; + } + protected function filter_past_and_recurring_events( $events ) { $upcoming = array(); $set_recurring_events = array(); @@ -710,6 +755,7 @@ class iCalendarReader { ) ); $events = $this->get_events( $url, $args['number'] ); + $events = $this->apply_timezone_offset( $events ); if ( empty( $events ) ) return false; |