summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnthony G. Basile <blueness@gentoo.org>2017-04-16 04:35:35 -0400
committerAnthony G. Basile <blueness@gentoo.org>2017-04-16 04:35:35 -0400
commit38a805d24a890dea4b5e90851693afb4e2041c9e (patch)
tree5f4b08ad64e6750936303d18abc370851e0db260 /plugins/jetpack/_inc/lib
parentUpdate plugin wordpress-mobile-pack 2.2.9 (diff)
downloadblogs-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')
-rw-r--r--plugins/jetpack/_inc/lib/admin-pages/class.jetpack-react-page.php130
-rw-r--r--plugins/jetpack/_inc/lib/admin-pages/class.jetpack-settings-page.php5
-rw-r--r--plugins/jetpack/_inc/lib/class.core-rest-api-endpoints.php161
-rw-r--r--plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-module-endpoints.php254
-rw-r--r--plugins/jetpack/_inc/lib/core-api/class.jetpack-core-api-xmlrpc-consumer-endpoint.php2
-rw-r--r--plugins/jetpack/_inc/lib/icalendar-reader.php46
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;