示例#1
0
 /**
  * Get or delete API key
  */
 public function configuration_load()
 {
     if (isset($_POST['action']) && $_POST['action'] == 'jetpack_protect_save_whitelist' && wp_verify_nonce($_POST['_wpnonce'], 'jetpack-protect')) {
         $whitelist = str_replace(' ', '', $_POST['whitelist']);
         $whitelist = explode(PHP_EOL, $whitelist);
         $result = jetpack_protect_save_whitelist($whitelist);
         $this->whitelist_saved = !is_wp_error($result);
         $this->whitelist_error = is_wp_error($result);
     }
     if (isset($_POST['action']) && 'get_protect_key' == $_POST['action'] && wp_verify_nonce($_POST['_wpnonce'], 'jetpack-protect')) {
         $result = $this->get_protect_key();
         // Only redirect on success
         // If it fails we need access to $this->api_key_error
         if ($result) {
             wp_safe_redirect(Jetpack::module_configuration_url('protect'));
         }
     }
     $this->api_key = get_site_option('jetpack_protect_key', false);
     $this->whitelist = get_site_option('jetpack_protect_whitelist', array());
     $this->user_ip = jetpack_protect_get_ip();
 }
示例#2
0
 /**
  * Manage Protect Settings
  *
  * ## OPTIONS
  *
  * whitelist: Whitelist an IP address.  You can also read or clear the whitelist.
  *
  *
  * ## EXAMPLES
  *
  * wp jetpack protect whitelist <ip address>
  * wp jetpack protect whitelist list
  * wp jetpack protect whitelist clear
  *
  * @synopsis <whitelist> [<ip|ip_low-ip_high|list|clear>]
  */
 public function protect($args, $assoc_args)
 {
     $action = isset($args[0]) ? $args[0] : 'prompt';
     if (!in_array($action, array('whitelist'))) {
         WP_CLI::error(sprintf(__('%s is not a valid command.', 'jetpack'), $action));
     }
     // Check if module is active
     if (!Jetpack::is_module_active(__FUNCTION__)) {
         WP_CLI::error(sprintf(_x('%s is not active. You can activate it with "wp jetpack module activate %s"', '"wp jetpack module activate" is a command - do not translate', 'jetpack'), __FUNCTION__, __FUNCTION__));
     }
     if (in_array($action, array('whitelist'))) {
         if (isset($args[1])) {
             $action = 'whitelist';
         } else {
             $action = 'prompt';
         }
     }
     switch ($action) {
         case 'whitelist':
             $whitelist = array();
             $new_ip = $args[1];
             $current_whitelist = get_site_option('jetpack_protect_whitelist');
             // Build array of IPs that are already whitelisted.
             // Re-build manually instead of using jetpack_protect_format_whitelist() so we can easily get
             // low & high range params for jetpack_protect_ip_address_is_in_range();
             foreach ($current_whitelist as $whitelisted) {
                 // IP ranges
                 if ($whitelisted->range) {
                     // Is it already whitelisted?
                     if (jetpack_protect_ip_address_is_in_range($new_ip, $whitelisted->range_low, $whitelisted->range_high)) {
                         WP_CLI::error(sprintf(__("%s has already been whitelisted", 'jetpack'), $new_ip));
                         break;
                     }
                     $whitelist[] = $whitelisted->range_low . " - " . $whitelisted->range_high;
                 } else {
                     // Individual IPs
                     // Check if the IP is already whitelisted (single IP only)
                     if ($new_ip == $whitelisted->ip_address) {
                         WP_CLI::error(sprintf(__("%s has already been whitelisted", 'jetpack'), $new_ip));
                         break;
                     }
                     $whitelist[] = $whitelisted->ip_address;
                 }
             }
             /*
              * List the whitelist
              * Done here because it's easier to read the $whitelist array after it's been rebuilt
              */
             if (isset($args[1]) && 'list' == $args[1]) {
                 if (!empty($whitelist)) {
                     WP_CLI::success(__('Here are your whitelisted IPs:', 'jetpack'));
                     foreach ($whitelist as $ip) {
                         WP_CLI::line("\t" . str_pad($ip, 24));
                     }
                 } else {
                     WP_CLI::line(__('Whitelist is empty.', "jetpack"));
                 }
                 break;
             }
             /*
              * Clear the whitelist
              */
             if (isset($args[1]) && 'clear' == $args[1]) {
                 if (!empty($whitelist)) {
                     $whitelist = array();
                     jetpack_protect_save_whitelist($whitelist);
                     WP_CLI::success(__('Cleared all whitelisted IPs', 'jetpack'));
                 } else {
                     WP_CLI::line(__('Whitelist is empty.', "jetpack"));
                 }
                 break;
             }
             // Append new IP to whitelist array
             array_push($whitelist, $new_ip);
             // Save whitelist if there are no errors
             $result = jetpack_protect_save_whitelist($whitelist);
             if (is_wp_error($result)) {
                 WP_CLI::error(__($result, 'jetpack'));
             }
             WP_CLI::success(sprintf(__('%s has been whitelisted.', 'jetpack'), $new_ip));
             break;
         case 'prompt':
             WP_CLI::error(__('No command found.', 'jetpack') . "\n" . __('Please enter the IP address you want to whitelist.', 'jetpack') . "\n" . _x('You can save a range of IPs {low_range}-{high_range}. No spaces allowed.  (example: 1.1.1.1-2.2.2.2)', 'Instructions on how to whitelist IP ranges - low_range/high_range should be translated.', 'jetpack') . "\n" . _x("You can also 'list' or 'clear' the whitelist.", "'list' and 'clear' are commands and should not be translated", 'jetpack') . "\n");
             break;
     }
 }
 /**
  * Updates site settings for authorized users
  *
  * @return (array)
  */
 public function update_settings()
 {
     // $this->input() retrieves posted arguments whitelisted and casted to the $request_format
     // specs that get passed in when this class is instantiated
     /**
      * Filters the settings to be updated on the site.
      *
      * @since 3.6.0
      *
      * @param array $input Associative array of site settings to be updated.
      */
     $input = apply_filters('rest_api_update_site_settings', $this->input());
     $jetpack_relatedposts_options = array();
     $sharing_options = array();
     $updated = array();
     foreach ($input as $key => $value) {
         if (!is_array($value)) {
             $value = trim($value);
         }
         $value = wp_unslash($value);
         switch ($key) {
             case 'default_ping_status':
             case 'default_comment_status':
                 // settings are stored as closed|open
                 $coerce_value = $value ? 'open' : 'closed';
                 if (update_option($key, $coerce_value)) {
                     $updated[$key] = $value;
                 }
                 break;
             case 'jetpack_protect_whitelist':
                 if (function_exists('jetpack_protect_save_whitelist')) {
                     $result = jetpack_protect_save_whitelist($value);
                     if (is_wp_error($result)) {
                         return $result;
                     }
                     $updated[$key] = jetpack_protect_format_whitelist();
                 }
                 break;
             case 'jetpack_sync_non_public_post_stati':
                 Jetpack_Options::update_option('sync_non_public_post_stati', $value);
                 break;
             case 'jetpack_relatedposts_enabled':
             case 'jetpack_relatedposts_show_thumbnails':
             case 'jetpack_relatedposts_show_headline':
                 if (!$this->jetpack_relatedposts_supported()) {
                     break;
                 }
                 if ('jetpack_relatedposts_enabled' === $key && method_exists('Jetpack', 'is_module_active') && $this->jetpack_relatedposts_supported()) {
                     $before_action = Jetpack::is_module_active('related-posts');
                     if ($value) {
                         Jetpack::activate_module('related-posts', false, false);
                     } else {
                         Jetpack::deactivate_module('related-posts');
                     }
                     $after_action = Jetpack::is_module_active('related-posts');
                     if ($after_action == $before_action) {
                         break;
                     }
                 }
                 $just_the_key = substr($key, 21);
                 $jetpack_relatedposts_options[$just_the_key] = $value;
                 break;
             case 'social_notifications_like':
             case 'social_notifications_reblog':
             case 'social_notifications_subscribe':
                 // settings are stored as on|off
                 $coerce_value = $value ? 'on' : 'off';
                 if (update_option($key, $coerce_value)) {
                     $updated[$key] = $value;
                 }
                 break;
             case 'wga':
                 if (!isset($value['code']) || !preg_match('/^$|^UA-[\\d-]+$/i', $value['code'])) {
                     return new WP_Error('invalid_code', 'Invalid UA ID');
                 }
                 $wga = get_option('wga', array());
                 $wga['code'] = $value['code'];
                 // maintain compatibility with wp-google-analytics
                 if (update_option('wga', $wga)) {
                     $updated[$key] = $value;
                 }
                 $enabled_or_disabled = $wga['code'] ? 'enabled' : 'disabled';
                 do_action('jetpack_bump_stats_extras', 'google-analytics', $enabled_or_disabled);
                 $business_plugins = WPCOM_Business_Plugins::instance();
                 $business_plugins->activate_plugin('wp-google-analytics');
                 break;
             case 'jetpack_comment_likes_enabled':
                 // settings are stored as 1|0
                 $coerce_value = (int) $value;
                 if (update_option($key, $coerce_value)) {
                     $updated[$key] = $value;
                 }
                 break;
                 // Sharing options
             // Sharing options
             case 'sharing_button_style':
             case 'sharing_show':
             case 'sharing_open_links':
                 $sharing_options[preg_replace('/^sharing_/', '', $key)] = $value;
                 break;
             case 'sharing_label':
                 $sharing_options[$key] = $value;
                 break;
                 // Keyring token option
             // Keyring token option
             case 'eventbrite_api_token':
                 // These options can only be updated for sites hosted on WordPress.com
                 if (defined('IS_WPCOM') && IS_WPCOM) {
                     if (empty($value) || WPCOM_JSON_API::is_falsy($value)) {
                         if (delete_option($key)) {
                             $updated[$key] = null;
                         }
                     } else {
                         if (update_option($key, $value)) {
                             $updated[$key] = (int) $value;
                         }
                     }
                 }
                 break;
                 // no worries, we've already whitelisted and casted arguments above
             // no worries, we've already whitelisted and casted arguments above
             default:
                 if (update_option($key, $value)) {
                     $updated[$key] = $value;
                 }
         }
     }
     if (count($jetpack_relatedposts_options)) {
         // track new jetpack_relatedposts options against old
         $old_relatedposts_options = Jetpack_Options::get_option('relatedposts');
         if (Jetpack_Options::update_option('relatedposts', $jetpack_relatedposts_options)) {
             foreach ($jetpack_relatedposts_options as $key => $value) {
                 if ($value !== $old_relatedposts_options[$key]) {
                     $updated['jetpack_relatedposts_' . $key] = $value;
                 }
             }
         }
     }
     if (!empty($sharing_options) && class_exists('Sharing_Service')) {
         $ss = new Sharing_Service();
         // Merge current values with updated, since Sharing_Service expects
         // all values to be included when updating
         $current_sharing_options = $ss->get_global_options();
         foreach ($current_sharing_options as $key => $val) {
             if (!isset($sharing_options[$key])) {
                 $sharing_options[$key] = $val;
             }
         }
         $updated_social_options = $ss->set_global_options($sharing_options);
         if (isset($input['sharing_button_style'])) {
             $updated['sharing_button_style'] = (string) $updated_social_options['button_style'];
         }
         if (isset($input['sharing_label'])) {
             // Sharing_Service won't report label as updated if set to default
             $updated['sharing_label'] = (string) $sharing_options['sharing_label'];
         }
         if (isset($input['sharing_show'])) {
             $updated['sharing_show'] = (array) $updated_social_options['show'];
         }
         if (isset($input['sharing_open_links'])) {
             $updated['sharing_open_links'] = (string) $updated_social_options['open_links'];
         }
     }
     return array('updated' => $updated);
 }
 /**
  * Fires when the Jetpack > Settings page is saved.
  *
  * @since 2.9
  */
 public function save_network_settings_page()
 {
     if (!wp_verify_nonce($_POST['_wpnonce'], 'jetpack-network-settings')) {
         // no nonce, push back to settings page
         wp_safe_redirect(add_query_arg(array('page' => 'jetpack-settings'), network_admin_url('admin.php')));
         exit;
     }
     // try to save the Protect whitelist before anything else, since that action can result in errors
     $whitelist = str_replace(' ', '', $_POST['global-whitelist']);
     $whitelist = explode(PHP_EOL, $whitelist);
     $result = jetpack_protect_save_whitelist($whitelist, $global = true);
     if (is_wp_error($result)) {
         wp_safe_redirect(add_query_arg(array('page' => 'jetpack-settings', 'error' => 'jetpack_protect_whitelist'), network_admin_url('admin.php')));
         exit;
     }
     /*
      * Fields
      *
      * auto-connect - Checkbox for global Jetpack connection
      * sub-site-connection-override - Allow sub-site admins to (dis)reconnect with their own Jetpack account
      */
     $auto_connect = 0;
     if (isset($_POST['auto-connect'])) {
         $auto_connect = 1;
     }
     $sub_site_connection_override = 0;
     if (isset($_POST['sub-site-connection-override'])) {
         $sub_site_connection_override = 1;
     }
     /* Remove the toggles for 2.9, re-evaluate how they're done and added for a 3.0 release. They don't feel quite right yet.
     		$manage_auto_activated_modules = 0;
     		if ( isset( $_POST['manage_auto_activated_modules'] ) ) {
     			$manage_auto_activated_modules = 1;
     		}
     
     		$modules = array();
     		if ( isset( $_POST['modules'] ) ) {
     			$modules = $_POST['modules'];
     		}
     		*/
     $data = array('auto-connect' => $auto_connect, 'sub-site-connection-override' => $sub_site_connection_override);
     update_site_option($this->settings_name, $data);
     wp_safe_redirect(add_query_arg(array('page' => 'jetpack-settings', 'updated' => 'true'), network_admin_url('admin.php')));
     exit;
 }
 /**
  * If it's a valid Jetpack module and configuration parameters have been sent, update it.
  *
  * @since 4.3.0
  *
  * @param WP_REST_Request $data {
  *     Array of parameters received by request.
  *
  *     @type string $slug Module slug.
  * }
  *
  * @return bool|WP_Error True if module was updated. Otherwise, a WP_Error instance with the corresponding error.
  */
 public function update_data($data)
 {
     // If it's null, we're trying to update many module options from different modules.
     if (is_null($data['slug'])) {
         // Value admitted by Jetpack_Core_Json_Api_Endpoints::get_updateable_data_list that will make it return all module options.
         // It will not be passed. It's just checked in this method to pass that method a string or array.
         $data['slug'] = 'any';
     } else {
         if (!Jetpack::is_module($data['slug'])) {
             return new WP_Error('not_found', esc_html__('The requested Jetpack module was not found.', 'jetpack'), array('status' => 404));
         }
         if (!Jetpack::is_module_active($data['slug'])) {
             return new WP_Error('inactive', esc_html__('The requested Jetpack module is inactive.', 'jetpack'), array('status' => 409));
         }
     }
     // Get parameters to update the module.
     $params = $data->get_json_params();
     // Exit if no parameters were passed.
     if (!is_array($params)) {
         return new WP_Error('missing_options', esc_html__('Missing options.', 'jetpack'), array('status' => 404));
     }
     // Get available module options.
     $options = Jetpack_Core_Json_Api_Endpoints::get_updateable_data_list('any' === $data['slug'] ? $params : $data['slug']);
     // Prepare to toggle module if needed
     $toggle_module = new Jetpack_Core_API_Module_Toggle_Endpoint(new Jetpack_IXR_Client());
     // Options that are invalid or failed to update.
     $invalid = array_keys(array_diff_key($params, $options));
     $not_updated = array();
     // Remove invalid options
     $params = array_intersect_key($params, $options);
     // Used if response is successful. The message can be overwritten and additional data can be added here.
     $response = array('code' => 'success', 'message' => esc_html__('The requested Jetpack data updates were successful.', 'jetpack'));
     // If there are modules to activate, activate them first so they're ready when their options are set.
     foreach ($params as $option => $value) {
         if ('modules' === $options[$option]['jp_group']) {
             // Used if there was an error. Can be overwritten with specific error messages.
             $error = '';
             // Set to true if the module toggling was successful.
             $updated = false;
             // Check if user can toggle the module.
             if ($toggle_module->can_request()) {
                 // Activate or deactivate the module according to the value passed.
                 $toggle_result = $value ? $toggle_module->activate_module($option) : $toggle_module->deactivate_module($option);
                 if (is_wp_error($toggle_result)) {
                     $error = $toggle_result->get_error_message();
                 } else {
                     $updated = true;
                 }
             } else {
                 $error = Jetpack_Core_Json_Api_Endpoints::$user_permissions_error_msg;
             }
             // The module was not toggled.
             if (!$updated) {
                 $not_updated[$option] = $error;
             }
             // Remove module from list so we don't go through it again.
             unset($params[$option]);
         }
     }
     foreach ($params as $option => $value) {
         // Used if there was an error. Can be overwritten with specific error messages.
         $error = '';
         // Set to true if the option update was successful.
         $updated = false;
         // Get option attributes, including the group it belongs to.
         $option_attrs = $options[$option];
         // If this is a module option and the related module isn't active for any reason, continue with the next one.
         if ('settings' !== $option_attrs['jp_group']) {
             if (!Jetpack::is_module($option_attrs['jp_group'])) {
                 $not_updated[$option] = esc_html__('The requested Jetpack module was not found.', 'jetpack');
                 continue;
             }
             if (!Jetpack::is_module_active($option_attrs['jp_group'])) {
                 $not_updated[$option] = esc_html__('The requested Jetpack module is inactive.', 'jetpack');
                 continue;
             }
         }
         // Properly cast value based on its type defined in endpoint accepted args.
         $value = Jetpack_Core_Json_Api_Endpoints::cast_value($value, $option_attrs);
         switch ($option) {
             case 'monitor_receive_notifications':
                 $monitor = new Jetpack_Monitor();
                 // If we got true as response, consider it done.
                 $updated = true === $monitor->update_option_receive_jetpack_monitor_notification($value);
                 break;
             case 'post_by_email_address':
                 if ('create' == $value) {
                     $result = $this->_process_post_by_email('jetpack.createPostByEmailAddress', esc_html__('Unable to create the Post by Email address. Please try again later.', 'jetpack'));
                 } elseif ('regenerate' == $value) {
                     $result = $this->_process_post_by_email('jetpack.regeneratePostByEmailAddress', esc_html__('Unable to regenerate the Post by Email address. Please try again later.', 'jetpack'));
                 } elseif ('delete' == $value) {
                     $result = $this->_process_post_by_email('jetpack.deletePostByEmailAddress', esc_html__('Unable to delete the Post by Email address. Please try again later.', 'jetpack'));
                 } else {
                     $result = false;
                 }
                 // If we got an email address (create or regenerate) or 1 (delete), consider it done.
                 if (preg_match('/[a-z0-9]+@post.wordpress.com/', $result)) {
                     $response[$option] = $result;
                     $updated = true;
                 } elseif (1 == $result) {
                     $updated = true;
                 } elseif (is_array($result) && isset($result['message'])) {
                     $error = $result['message'];
                 }
                 break;
             case 'jetpack_protect_key':
                 $protect = Jetpack_Protect_Module::instance();
                 if ('create' == $value) {
                     $result = $protect->get_protect_key();
                 } else {
                     $result = false;
                 }
                 // If we got one of Protect keys, consider it done.
                 if (preg_match('/[a-z0-9]{40,}/i', $result)) {
                     $response[$option] = $result;
                     $updated = true;
                 }
                 break;
             case 'jetpack_protect_global_whitelist':
                 $updated = jetpack_protect_save_whitelist(explode(PHP_EOL, str_replace(array(' ', ','), array('', "\n"), $value)));
                 if (is_wp_error($updated)) {
                     $error = $updated->get_error_message();
                 }
                 break;
             case 'show_headline':
             case 'show_thumbnails':
                 $grouped_options = $grouped_options_current = (array) Jetpack_Options::get_option('relatedposts');
                 $grouped_options[$option] = $value;
                 // If option value was the same, consider it done.
                 $updated = $grouped_options_current != $grouped_options ? Jetpack_Options::update_option('relatedposts', $grouped_options) : true;
                 break;
             case 'google':
             case 'bing':
             case 'pinterest':
             case 'yandex':
                 $grouped_options = $grouped_options_current = (array) get_option('verification_services_codes');
                 $grouped_options[$option] = $value;
                 // If option value was the same, consider it done.
                 $updated = $grouped_options_current != $grouped_options ? update_option('verification_services_codes', $grouped_options) : true;
                 break;
             case 'sharing_services':
                 if (!class_exists('Sharing_Service') && !@(include JETPACK__PLUGIN_DIR . 'modules/sharedaddy/sharing-service.php')) {
                     break;
                 }
                 $sharer = new Sharing_Service();
                 // If option value was the same, consider it done.
                 $updated = $value != $sharer->get_blog_services() ? $sharer->set_blog_services($value['visible'], $value['hidden']) : true;
                 break;
             case 'button_style':
             case 'sharing_label':
             case 'show':
                 if (!class_exists('Sharing_Service') && !@(include JETPACK__PLUGIN_DIR . 'modules/sharedaddy/sharing-service.php')) {
                     break;
                 }
                 $sharer = new Sharing_Service();
                 $grouped_options = $sharer->get_global_options();
                 $grouped_options[$option] = $value;
                 $updated = $sharer->set_global_options($grouped_options);
                 break;
             case 'custom':
                 if (!class_exists('Sharing_Service') && !@(include JETPACK__PLUGIN_DIR . 'modules/sharedaddy/sharing-service.php')) {
                     break;
                 }
                 $sharer = new Sharing_Service();
                 $updated = $sharer->new_service(stripslashes($value['sharing_name']), stripslashes($value['sharing_url']), stripslashes($value['sharing_icon']));
                 // Return new custom service
                 $response[$option] = $updated;
                 break;
             case 'sharing_delete_service':
                 if (!class_exists('Sharing_Service') && !@(include JETPACK__PLUGIN_DIR . 'modules/sharedaddy/sharing-service.php')) {
                     break;
                 }
                 $sharer = new Sharing_Service();
                 $updated = $sharer->delete_service($value);
                 break;
             case 'jetpack-twitter-cards-site-tag':
                 $value = trim(ltrim(strip_tags($value), '@'));
                 $updated = get_option($option) !== $value ? update_option($option, $value) : true;
                 break;
             case 'onpublish':
             case 'onupdate':
             case 'Bias Language':
             case 'Cliches':
             case 'Complex Expression':
             case 'Diacritical Marks':
             case 'Double Negative':
             case 'Hidden Verbs':
             case 'Jargon Language':
             case 'Passive voice':
             case 'Phrases to Avoid':
             case 'Redundant Expression':
             case 'guess_lang':
                 if (in_array($option, array('onpublish', 'onupdate'))) {
                     $atd_option = 'AtD_check_when';
                 } elseif ('guess_lang' == $option) {
                     $atd_option = 'AtD_guess_lang';
                     $option = 'true';
                 } else {
                     $atd_option = 'AtD_options';
                 }
                 $user_id = get_current_user_id();
                 $grouped_options_current = AtD_get_options($user_id, $atd_option);
                 unset($grouped_options_current['name']);
                 $grouped_options = $grouped_options_current;
                 if ($value && !isset($grouped_options[$option])) {
                     $grouped_options[$option] = $value;
                 } elseif (!$value && isset($grouped_options[$option])) {
                     unset($grouped_options[$option]);
                 }
                 // If option value was the same, consider it done, otherwise try to update it.
                 $options_to_save = implode(',', array_keys($grouped_options));
                 $updated = $grouped_options != $grouped_options_current ? AtD_update_setting($user_id, $atd_option, $options_to_save) : true;
                 break;
             case 'ignored_phrases':
             case 'unignore_phrase':
                 $user_id = get_current_user_id();
                 $atd_option = 'AtD_ignored_phrases';
                 $grouped_options = $grouped_options_current = explode(',', AtD_get_setting($user_id, $atd_option));
                 if ('ignored_phrases' == $option) {
                     $grouped_options = explode(',', $value);
                 } else {
                     $index = array_search($value, $grouped_options);
                     if (false !== $index) {
                         unset($grouped_options[$index]);
                         $grouped_options = array_values($grouped_options);
                     }
                 }
                 $ignored_phrases = implode(',', array_filter(array_map('strip_tags', $grouped_options)));
                 $updated = $grouped_options != $grouped_options_current ? AtD_update_setting($user_id, $atd_option, $ignored_phrases) : true;
                 break;
             case 'admin_bar':
             case 'roles':
             case 'count_roles':
             case 'blog_id':
             case 'do_not_track':
             case 'hide_smile':
             case 'version':
                 $grouped_options = $grouped_options_current = (array) get_option('stats_options');
                 $grouped_options[$option] = $value;
                 // If option value was the same, consider it done.
                 $updated = $grouped_options_current != $grouped_options ? update_option('stats_options', $grouped_options) : true;
                 break;
             case Jetpack_Core_Json_Api_Endpoints::holiday_snow_option_name():
                 $updated = get_option($option) != $value ? update_option($option, (bool) $value ? 'letitsnow' : '') : true;
                 break;
             case 'wp_mobile_featured_images':
             case 'wp_mobile_excerpt':
                 $value = 'enabled' === $value ? '1' : '0';
                 // break intentionally omitted
             // break intentionally omitted
             default:
                 // If option value was the same, consider it done.
                 $updated = get_option($option) != $value ? update_option($option, $value) : true;
                 break;
         }
         // The option was not updated.
         if (!$updated) {
             $not_updated[$option] = $error;
         }
     }
     if (empty($invalid) && empty($not_updated)) {
         // The option was updated.
         return rest_ensure_response($response);
     } else {
         $invalid_count = count($invalid);
         $not_updated_count = count($not_updated);
         $error = '';
         if ($invalid_count > 0) {
             $error = sprintf(_n('Invalid option: %s.', 'Invalid options: %s.', $invalid_count, 'jetpack'), join(', ', $invalid));
         }
         if ($not_updated_count > 0) {
             $not_updated_messages = array();
             foreach ($not_updated as $not_updated_option => $not_updated_message) {
                 if (!empty($not_updated_message)) {
                     $not_updated_messages[] = sprintf(__('Extra info for %1$s: %2$s', 'jetpack'), $not_updated_option, $not_updated_message);
                 }
             }
             if (!empty($error)) {
                 $error .= ' ';
             }
             $error .= sprintf(_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);
             }
         }
         // There was an error because some options were updated but others were invalid or failed to update.
         return new WP_Error('some_updated', esc_html($error), array('status' => 400));
     }
 }
 /**
  * If it's a valid Jetpack module and configuration parameters have been sent, update it.
  *
  * @since 4.1.0
  *
  * @param WP_REST_Request $data {
  *     Array of parameters received by request.
  *
  *     @type string $slug Module slug.
  * }
  *
  * @return bool|WP_Error True if module was updated. Otherwise, a WP_Error instance with the corresponding error.
  */
 public static function update_module($data)
 {
     if (!Jetpack::is_module($data['slug'])) {
         return new WP_Error('not_found', esc_html__('The requested Jetpack module was not found.', 'jetpack'), array('status' => 404));
     }
     if (!Jetpack::is_module_active($data['slug'])) {
         return new WP_Error('inactive', esc_html__('The requested Jetpack module is inactive.', 'jetpack'), array('status' => 409));
     }
     // Get parameters to update the module.
     $param = $data->get_json_params();
     // Exit if no parameters were passed.
     if (!is_array($param)) {
         return new WP_Error('missing_option', esc_html__('Missing option.', 'jetpack'), array('status' => 404));
     }
     // Get option name and value.
     $option = key($param);
     $value = current($param);
     // Get available module options.
     $options = self::get_module_available_options();
     // If option is invalid, don't go any further.
     if (!in_array($option, array_keys($options))) {
         return new WP_Error('invalid_param', esc_html(sprintf(__('The option %s is invalid for this module.', 'jetpack'), $option)), array('status' => 404));
     }
     // Used if response is successful. The message can be overwritten and additional data can be added here.
     $response = array('code' => 'success', 'message' => esc_html__('The requested Jetpack module was updated.', 'jetpack'));
     // Used if there was an error. Can be overwritten with specific error messages.
     /* Translators: the variable is a module option name. */
     $error = sprintf(__('The option %s was not updated.', 'jetpack'), $option);
     // Set to true if the option update was successful.
     $updated = false;
     // Properly cast value based on its type defined in endpoint accepted args.
     $value = self::cast_value($value, $options[$option]);
     switch ($option) {
         case 'monitor_receive_notifications':
             $monitor = new Jetpack_Monitor();
             // If we got true as response, consider it done.
             $updated = true === $monitor->update_option_receive_jetpack_monitor_notification($value);
             break;
         case 'post_by_email_address':
             if ('create' == $value) {
                 $result = self::_process_post_by_email('jetpack.createPostByEmailAddress', esc_html__('Unable to create the Post by Email address. Please try again later.', 'jetpack'));
             } elseif ('regenerate' == $value) {
                 $result = self::_process_post_by_email('jetpack.regeneratePostByEmailAddress', esc_html__('Unable to regenerate the Post by Email address. Please try again later.', 'jetpack'));
             } elseif ('delete' == $value) {
                 $result = self::_process_post_by_email('jetpack.deletePostByEmailAddress', esc_html__('Unable to delete the Post by Email address. Please try again later.', 'jetpack'));
             } else {
                 $result = false;
             }
             // If we got an email address (create or regenerate) or 1 (delete), consider it done.
             if (preg_match('/[a-z0-9]+@post.wordpress.com/', $result)) {
                 $response[$option] = $result;
                 $updated = true;
             } elseif (1 == $result) {
                 $updated = true;
             } elseif (is_array($result) && isset($result['message'])) {
                 $error = $result['message'];
             }
             break;
         case 'jetpack_protect_key':
             $protect = Jetpack_Protect_Module::instance();
             if ('create' == $value) {
                 $result = $protect->get_protect_key();
             } else {
                 $result = false;
             }
             // If we got one of Protect keys, consider it done.
             if (preg_match('/[a-z0-9]{40,}/i', $result)) {
                 $response[$option] = $result;
                 $updated = true;
             }
             break;
         case 'jetpack_protect_global_whitelist':
             $updated = jetpack_protect_save_whitelist(explode(PHP_EOL, str_replace(' ', '', $value)));
             if (is_wp_error($updated)) {
                 $error = $updated->get_error_message();
             }
             break;
         case 'show_headline':
         case 'show_thumbnails':
             $grouped_options = $grouped_options_current = Jetpack_Options::get_option('relatedposts');
             $grouped_options[$option] = $value;
             // If option value was the same, consider it done.
             $updated = $grouped_options_current != $grouped_options ? Jetpack_Options::update_option('relatedposts', $grouped_options) : true;
             break;
         case 'google':
         case 'bing':
         case 'pinterest':
             $grouped_options = $grouped_options_current = get_option('verification_services_codes');
             $grouped_options[$option] = $value;
             // If option value was the same, consider it done.
             $updated = $grouped_options_current != $grouped_options ? update_option('verification_services_codes', $grouped_options) : true;
             break;
         case 'sharing_services':
             $sharer = new Sharing_Service();
             // If option value was the same, consider it done.
             $updated = $value != $sharer->get_blog_services() ? $sharer->set_blog_services($value['visible'], $value['hidden']) : true;
             break;
         case 'button_style':
         case 'sharing_label':
         case 'show':
             $sharer = new Sharing_Service();
             $grouped_options = $sharer->get_global_options();
             $grouped_options[$option] = $value;
             $updated = $sharer->set_global_options($grouped_options);
             break;
         case 'custom':
             $sharer = new Sharing_Service();
             $updated = $sharer->new_service(stripslashes($value['sharing_name']), stripslashes($value['sharing_url']), stripslashes($value['sharing_icon']));
             // Return new custom service
             $response[$option] = $updated;
             break;
         case 'sharing_delete_service':
             $sharer = new Sharing_Service();
             $updated = $sharer->delete_service($value);
             break;
         case 'jetpack-twitter-cards-site-tag':
             $value = trim(ltrim(strip_tags($value), '@'));
             $updated = get_option($option) !== $value ? update_option($option, $value) : true;
             break;
         case 'onpublish':
         case 'onupdate':
         case 'Bias Language':
         case 'Cliches':
         case 'Complex Expression':
         case 'Diacritical Marks':
         case 'Double Negative':
         case 'Hidden Verbs':
         case 'Jargon Language':
         case 'Passive voice':
         case 'Phrases to Avoid':
         case 'Redundant Expression':
         case 'guess_lang':
             if (in_array($option, array('onpublish', 'onupdate'))) {
                 $atd_option = 'AtD_check_when';
             } elseif ('guess_lang' == $option) {
                 $atd_option = 'AtD_guess_lang';
                 $option = 'true';
             } else {
                 $atd_option = 'AtD_options';
             }
             $user_id = get_current_user_id();
             $grouped_options_current = AtD_get_options($user_id, $atd_option);
             unset($grouped_options_current['name']);
             $grouped_options = $grouped_options_current;
             if ($value && !isset($grouped_options[$option])) {
                 $grouped_options[$option] = $value;
             } elseif (!$value && isset($grouped_options[$option])) {
                 unset($grouped_options[$option]);
             }
             // If option value was the same, consider it done, otherwise try to update it.
             $options_to_save = implode(',', array_keys($grouped_options));
             $updated = $grouped_options != $grouped_options_current ? AtD_update_setting($user_id, $atd_option, $options_to_save) : true;
             break;
         case 'ignored_phrases':
         case 'unignore_phrase':
             $user_id = get_current_user_id();
             $atd_option = 'AtD_ignored_phrases';
             $grouped_options = $grouped_options_current = explode(',', AtD_get_setting($user_id, $atd_option));
             if ('ignored_phrases' == $option) {
                 $grouped_options[] = $value;
             } else {
                 $index = array_search($value, $grouped_options);
                 if (false !== $index) {
                     unset($grouped_options[$index]);
                     $grouped_options = array_values($grouped_options);
                 }
             }
             $ignored_phrases = implode(',', array_filter(array_map('strip_tags', $grouped_options)));
             $updated = $grouped_options != $grouped_options_current ? AtD_update_setting($user_id, $atd_option, $ignored_phrases) : true;
             break;
         default:
             // If option value was the same, consider it done.
             $updated = get_option($option) != $value ? update_option($option, $value) : true;
             break;
     }
     // The option was not updated.
     if (!$updated) {
         return new WP_Error('module_option_not_updated', esc_html($error), array('status' => 400));
     }
     // The option was updated.
     return rest_ensure_response($response);
 }
 /**
  * Updates site settings for authorized users
  *
  * @return (array)
  */
 public function update_settings()
 {
     // $this->input() retrieves posted arguments whitelisted and casted to the $request_format
     // specs that get passed in when this class is instantiated
     /**
      * Filters the settings to be updated on the site.
      *
      * @module json-api
      *
      * @since 3.6.0
      *
      * @param array $input Associative array of site settings to be updated.
      */
     $input = apply_filters('rest_api_update_site_settings', $this->input());
     $jetpack_relatedposts_options = array();
     $sharing_options = array();
     $updated = array();
     foreach ($input as $key => $value) {
         if (!is_array($value)) {
             $value = trim($value);
         }
         $value = wp_unslash($value);
         switch ($key) {
             case 'default_ping_status':
             case 'default_comment_status':
                 // settings are stored as closed|open
                 $coerce_value = $value ? 'open' : 'closed';
                 if (update_option($key, $coerce_value)) {
                     $updated[$key] = $value;
                 }
                 break;
             case 'jetpack_protect_whitelist':
                 if (function_exists('jetpack_protect_save_whitelist')) {
                     $result = jetpack_protect_save_whitelist($value);
                     if (is_wp_error($result)) {
                         return $result;
                     }
                     $updated[$key] = jetpack_protect_format_whitelist();
                 }
                 break;
             case 'jetpack_sync_non_public_post_stati':
                 Jetpack_Options::update_option('sync_non_public_post_stati', $value);
                 break;
             case 'jetpack_relatedposts_enabled':
             case 'jetpack_relatedposts_show_thumbnails':
             case 'jetpack_relatedposts_show_headline':
                 if (!$this->jetpack_relatedposts_supported()) {
                     break;
                 }
                 if ('jetpack_relatedposts_enabled' === $key && method_exists('Jetpack', 'is_module_active') && $this->jetpack_relatedposts_supported()) {
                     $before_action = Jetpack::is_module_active('related-posts');
                     if ($value) {
                         Jetpack::activate_module('related-posts', false, false);
                     } else {
                         Jetpack::deactivate_module('related-posts');
                     }
                     $after_action = Jetpack::is_module_active('related-posts');
                     if ($after_action == $before_action) {
                         break;
                     }
                 }
                 $just_the_key = substr($key, 21);
                 $jetpack_relatedposts_options[$just_the_key] = $value;
                 break;
             case 'social_notifications_like':
             case 'social_notifications_reblog':
             case 'social_notifications_subscribe':
                 // settings are stored as on|off
                 $coerce_value = $value ? 'on' : 'off';
                 if (update_option($key, $coerce_value)) {
                     $updated[$key] = $value;
                 }
                 break;
             case 'wga':
                 if (!isset($value['code']) || !preg_match('/^$|^UA-[\\d-]+$/i', $value['code'])) {
                     return new WP_Error('invalid_code', 'Invalid UA ID');
                 }
                 $wga = get_option('wga', array());
                 $wga['code'] = $value['code'];
                 // maintain compatibility with wp-google-analytics
                 if (update_option('wga', $wga)) {
                     $updated[$key] = $value;
                 }
                 $enabled_or_disabled = $wga['code'] ? 'enabled' : 'disabled';
                 /** This action is documented in modules/widgets/social-media-icons.php */
                 do_action('jetpack_bump_stats_extras', 'google-analytics', $enabled_or_disabled);
                 $business_plugins = WPCOM_Business_Plugins::instance();
                 $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] = (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;
                 // Sharing options
             // Sharing options
             case 'sharing_button_style':
             case 'sharing_show':
             case 'sharing_open_links':
                 $sharing_options[preg_replace('/^sharing_/', '', $key)] = $value;
                 break;
             case 'sharing_label':
                 $sharing_options[$key] = $value;
                 break;
                 // Keyring token option
             // Keyring token option
             case 'eventbrite_api_token':
                 // These options can only be updated for sites hosted on WordPress.com
                 if (defined('IS_WPCOM') && IS_WPCOM) {
                     if (empty($value) || WPCOM_JSON_API::is_falsy($value)) {
                         if (delete_option($key)) {
                             $updated[$key] = null;
                         }
                     } else {
                         if (update_option($key, $value)) {
                             $updated[$key] = (int) $value;
                         }
                     }
                 }
                 break;
             case 'holidaysnow':
                 if (empty($value) || WPCOM_JSON_API::is_falsy($value)) {
                     if (function_exists('jetpack_holiday_snow_option_name') && delete_option(jetpack_holiday_snow_option_name())) {
                         $updated[$key] = false;
                     }
                 } else {
                     if (function_exists('jetpack_holiday_snow_option_name') && update_option(jetpack_holiday_snow_option_name(), 'letitsnow')) {
                         $updated[$key] = true;
                     }
                 }
                 break;
             case 'timezone_string':
                 // Map UTC+- timezones to gmt_offsets and set timezone_string to empty
                 // https://github.com/WordPress/WordPress/blob/4.4.2/wp-admin/options.php#L175
                 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
                 if (has_filter('site_settings_endpoint_update_' . $key)) {
                     /**
                      * Filter current site setting value to be updated.
                      *
                      * @module json-api
                      *
                      * @since 3.9.3
                      *
                      * @param mixed $response_item A single site setting value.
                      */
                     $value = apply_filters('site_settings_endpoint_update_' . $key, $value);
                     $updated[$key] = $value;
                     continue;
                 }
                 // no worries, we've already whitelisted and casted arguments above
                 if (update_option($key, $value)) {
                     $updated[$key] = $value;
                 }
         }
     }
     if (count($jetpack_relatedposts_options)) {
         // track new jetpack_relatedposts options against old
         $old_relatedposts_options = Jetpack_Options::get_option('relatedposts');
         if (Jetpack_Options::update_option('relatedposts', $jetpack_relatedposts_options)) {
             foreach ($jetpack_relatedposts_options as $key => $value) {
                 if ($value !== $old_relatedposts_options[$key]) {
                     $updated['jetpack_relatedposts_' . $key] = $value;
                 }
             }
         }
     }
     if (!empty($sharing_options) && class_exists('Sharing_Service')) {
         $ss = new Sharing_Service();
         // Merge current values with updated, since Sharing_Service expects
         // all values to be included when updating
         $current_sharing_options = $ss->get_global_options();
         foreach ($current_sharing_options as $key => $val) {
             if (!isset($sharing_options[$key])) {
                 $sharing_options[$key] = $val;
             }
         }
         $updated_social_options = $ss->set_global_options($sharing_options);
         if (isset($input['sharing_button_style'])) {
             $updated['sharing_button_style'] = (string) $updated_social_options['button_style'];
         }
         if (isset($input['sharing_label'])) {
             // Sharing_Service won't report label as updated if set to default
             $updated['sharing_label'] = (string) $sharing_options['sharing_label'];
         }
         if (isset($input['sharing_show'])) {
             $updated['sharing_show'] = (array) $updated_social_options['show'];
         }
         if (isset($input['sharing_open_links'])) {
             $updated['sharing_open_links'] = (string) $updated_social_options['open_links'];
         }
     }
     return array('updated' => $updated);
 }