コード例 #1
0
	static function init( $method = null, $url = null, $post_body = null ) {
		if ( !self::$self ) {
			$class = function_exists( 'get_called_class' ) ? get_called_class() : __CLASS__;
			self::$self = new $class( $method, $url, $post_body );
		}
		return self::$self;
	}
コード例 #2
0
 function callback($path = '', $blog_id = 0)
 {
     global $wpdb;
     if ('mine' === $blog_id) {
         $api = WPCOM_JSON_API::init();
         if (!$api->token_details || empty($api->token_details['blog_id'])) {
             return new WP_Error('authorization_required', 'An active access token must be used to query information about the current blog.', 403);
         }
         $blog_id = $api->token_details['blog_id'];
     }
     $blog_id = $this->api->switch_to_blog_and_validate_user($this->api->get_blog_id($blog_id));
     if (is_wp_error($blog_id)) {
         return $blog_id;
     }
     $response = $this->build_current_site_response();
     do_action('wpcom_json_api_objects', 'sites');
     return $response;
 }
コード例 #3
0
 function callback($path = '', $blog_id = 0)
 {
     if ('mine' === $blog_id) {
         $api = WPCOM_JSON_API::init();
         if (!$api->token_details || empty($api->token_details['blog_id'])) {
             return new WP_Error('authorization_required', 'An active access token must be used to query information about the current blog.', 403);
         }
         $blog_id = $api->token_details['blog_id'];
     }
     $blog_id = $this->api->switch_to_blog_and_validate_user($this->api->get_blog_id($blog_id));
     if (is_wp_error($blog_id)) {
         return $blog_id;
     }
     // TODO: enable this when we can do so without being interfered with by
     // other endpoints that might be wrapping this one.
     // Uncomment and see failing test: test_jetpack_site_should_have_true_jetpack_property_via_site_meta
     // $this->filter_fields_and_options();
     $response = $this->build_current_site_response();
     /** This action is documented in json-endpoints/class.wpcom-json-api-site-settings-endpoint.php */
     do_action('wpcom_json_api_objects', 'sites');
     return $response;
 }
 function write_post($path, $blog_id, $post_id)
 {
     $new = $this->api->ends_with($path, '/new');
     $args = $this->query_args();
     // unhook publicize, it's hooked again later -- without this, skipping services is impossible
     if (defined('IS_WPCOM') && IS_WPCOM) {
         remove_action('save_post', array($GLOBALS['publicize_ui']->publicize, 'async_publicize_post'), 100, 2);
         add_action('rest_api_inserted_post', array($GLOBALS['publicize_ui']->publicize, 'async_publicize_post'));
     }
     if ($new) {
         $input = $this->input(true);
         if ('revision' === $input['type']) {
             if (!isset($input['parent'])) {
                 return new WP_Error('invalid_input', 'Invalid request input', 400);
             }
             $input['status'] = 'inherit';
             // force inherit for revision type
             $input['slug'] = $input['parent'] . '-autosave-v1';
         } elseif (!isset($input['title']) && !isset($input['content']) && !isset($input['excerpt'])) {
             return new WP_Error('invalid_input', 'Invalid request input', 400);
         }
         // default to post
         if (empty($input['type'])) {
             $input['type'] = 'post';
         }
         $post_type = get_post_type_object($input['type']);
         if (!$this->is_post_type_allowed($input['type'])) {
             return new WP_Error('unknown_post_type', 'Unknown post type', 404);
         }
         if (!empty($input['author'])) {
             $author_id = parent::parse_and_set_author($input['author'], $input['type']);
             unset($input['author']);
             if (is_wp_error($author_id)) {
                 return $author_id;
             }
         }
         if ('publish' === $input['status']) {
             if (!current_user_can($post_type->cap->publish_posts)) {
                 if (current_user_can($post_type->cap->edit_posts)) {
                     $input['status'] = 'pending';
                 } else {
                     return new WP_Error('unauthorized', 'User cannot publish posts', 403);
                 }
             }
         } else {
             if (!current_user_can($post_type->cap->edit_posts)) {
                 return new WP_Error('unauthorized', 'User cannot edit posts', 403);
             }
         }
     } else {
         $input = $this->input(false);
         if (!is_array($input) || !$input) {
             return new WP_Error('invalid_input', 'Invalid request input', 400);
         }
         $post = get_post($post_id);
         $_post_type = !empty($input['type']) ? $input['type'] : $post->post_type;
         $post_type = get_post_type_object($_post_type);
         if (!$post || is_wp_error($post)) {
             return new WP_Error('unknown_post', 'Unknown post', 404);
         }
         if (!current_user_can('edit_post', $post->ID)) {
             return new WP_Error('unauthorized', 'User cannot edit post', 403);
         }
         if (!empty($input['author'])) {
             $author_id = parent::parse_and_set_author($input['author'], $_post_type);
             unset($input['author']);
             if (is_wp_error($author_id)) {
                 return $author_id;
             }
         }
         if ('publish' === $input['status'] && 'publish' !== $post->post_status && !current_user_can('publish_post', $post->ID)) {
             $input['status'] = 'pending';
         }
         $last_status = $post->post_status;
         $new_status = $input['status'];
     }
     // Fix for https://iorequests.wordpress.com/2014/08/13/scheduled-posts-made-in-the/
     // See: https://a8c.slack.com/archives/io/p1408047082000273
     // If date was set, $this->input will set date_gmt, date still needs to be adjusted for the blog's offset
     if (isset($input['date_gmt'])) {
         $gmt_offset = get_option('gmt_offset');
         $time_with_offset = strtotime($input['date_gmt']) + $gmt_offset * HOUR_IN_SECONDS;
         $input['date'] = date('Y-m-d H:i:s', $time_with_offset);
     }
     if (!empty($author_id) && get_current_user_id() != $author_id) {
         if (!current_user_can($post_type->cap->edit_others_posts)) {
             return new WP_Error('unauthorized', "User is not allowed to publish others' posts.", 403);
         } elseif (!user_can($author_id, $post_type->cap->edit_posts)) {
             return new WP_Error('unauthorized', 'Assigned author cannot publish post.', 403);
         }
     }
     if (!is_post_type_hierarchical($post_type->name) && 'revision' !== $post_type->name) {
         unset($input['parent']);
     }
     /* add taxonomies by name */
     $tax_input = array();
     foreach (array('categories' => 'category', 'tags' => 'post_tag') as $key => $taxonomy) {
         if (!isset($input[$key])) {
             continue;
         }
         $tax_input[$taxonomy] = array();
         $is_hierarchical = is_taxonomy_hierarchical($taxonomy);
         if (is_array($input[$key])) {
             $terms = $input[$key];
         } else {
             $terms = explode(',', $input[$key]);
         }
         foreach ($terms as $term) {
             /**
              * We assume these are names, not IDs, even if they are numeric.
              * Note: A category named "0" will not work right.
              * https://core.trac.wordpress.org/ticket/9059
              */
             $term_info = get_term_by('name', $term, $taxonomy, ARRAY_A);
             if (!$term_info) {
                 // only add a new tag/cat if the user has access to
                 $tax = get_taxonomy($taxonomy);
                 if (!current_user_can($tax->cap->edit_terms)) {
                     continue;
                 }
                 $term_info = wp_insert_term($term, $taxonomy);
             }
             if (!is_wp_error($term_info)) {
                 if ($is_hierarchical) {
                     // Categories must be added by ID
                     $tax_input[$taxonomy][] = (int) $term_info['term_id'];
                 } else {
                     // Tags must be added by name
                     $tax_input[$taxonomy][] = $term;
                 }
             }
         }
     }
     /* add taxonomies by ID */
     foreach (array('categories_by_id' => 'category', 'tags_by_id' => 'post_tag') as $key => $taxonomy) {
         if (!isset($input[$key])) {
             continue;
         }
         // combine with any previous selections
         if (!is_array($tax_input[$taxonomy])) {
             $tax_input[$taxonomy] = array();
         }
         $is_hierarchical = is_taxonomy_hierarchical($taxonomy);
         if (is_array($input[$key])) {
             $terms = $input[$key];
         } else {
             $terms = explode(',', $input[$key]);
         }
         foreach ($terms as $term) {
             if (!ctype_digit($term)) {
                 // skip anything that doesn't look like an ID
                 continue;
             }
             $term = (int) $term;
             $term_info = get_term_by('id', $term, $taxonomy, ARRAY_A);
             if ($term_info && !is_wp_error($term_info)) {
                 if ($is_hierarchical) {
                     // Categories must be added by ID
                     $tax_input[$taxonomy][] = $term;
                 } else {
                     // Tags must be added by name
                     $tax_input[$taxonomy][] = $term_info['name'];
                 }
             }
         }
     }
     if ((isset($input['categories']) || isset($input['categories_by_id'])) && empty($tax_input['category']) && 'revision' !== $post_type->name) {
         $tax_input['category'][] = get_option('default_category');
     }
     unset($input['tags'], $input['categories'], $input['tags_by_id'], $input['categories_by_id']);
     $insert = array();
     if (!empty($input['slug'])) {
         $insert['post_name'] = $input['slug'];
         unset($input['slug']);
     }
     if (isset($input['discussion'])) {
         $discussion = (array) $input['discussion'];
         foreach (array('comment', 'ping') as $discussion_type) {
             $discussion_open = sprintf('%ss_open', $discussion_type);
             $discussion_status = sprintf('%s_status', $discussion_type);
             if (isset($discussion[$discussion_open])) {
                 $is_open = WPCOM_JSON_API::is_truthy($discussion[$discussion_open]);
                 $discussion[$discussion_status] = $is_open ? 'open' : 'closed';
             }
             if (in_array($discussion[$discussion_status], array('open', 'closed'))) {
                 $insert[$discussion_status] = $discussion[$discussion_status];
             }
         }
     }
     unset($input['discussion']);
     if (isset($input['menu_order'])) {
         $insert['menu_order'] = $input['menu_order'];
         unset($input['menu_order']);
     }
     if (isset($input['publicize'])) {
         $publicize = $input['publicize'];
         unset($input['publicize']);
     }
     if (isset($input['publicize_message'])) {
         $publicize_custom_message = $input['publicize_message'];
         unset($input['publicize_message']);
     }
     if (isset($input['featured_image'])) {
         $featured_image = trim($input['featured_image']);
         $delete_featured_image = empty($featured_image);
         unset($input['featured_image']);
     }
     if (isset($input['metadata'])) {
         $metadata = $input['metadata'];
         unset($input['metadata']);
     }
     if (isset($input['likes_enabled'])) {
         $likes = $input['likes_enabled'];
         unset($input['likes_enabled']);
     }
     if (isset($input['sharing_enabled'])) {
         $sharing = $input['sharing_enabled'];
         unset($input['sharing_enabled']);
     }
     if (isset($input['sticky'])) {
         $sticky = $input['sticky'];
         unset($input['sticky']);
     }
     foreach ($input as $key => $value) {
         $insert["post_{$key}"] = $value;
     }
     if (!empty($author_id)) {
         $insert['post_author'] = absint($author_id);
     }
     if (!empty($tax_input)) {
         $insert['tax_input'] = $tax_input;
     }
     $has_media = !empty($input['media']) ? count($input['media']) : false;
     $has_media_by_url = !empty($input['media_urls']) ? count($input['media_urls']) : false;
     if ($new) {
         if (false === strpos($input['content'], '[gallery') && ($has_media || $has_media_by_url)) {
             switch ($has_media + $has_media_by_url) {
                 case 0:
                     // No images - do nothing.
                     break;
                 case 1:
                     // 1 image - make it big
                     $insert['post_content'] = $input['content'] = "[gallery size=full columns=1]\n\n" . $input['content'];
                     break;
                 default:
                     // Several images - 3 column gallery
                     $insert['post_content'] = $input['content'] = "[gallery]\n\n" . $input['content'];
                     break;
             }
         }
         $post_id = wp_insert_post(add_magic_quotes($insert), true);
     } else {
         $insert['ID'] = $post->ID;
         // wp_update_post ignores date unless edit_date is set
         // See: http://codex.wordpress.org/Function_Reference/wp_update_post#Scheduling_posts
         // See: https://core.trac.wordpress.org/browser/tags/3.9.2/src/wp-includes/post.php#L3302
         if (isset($input['date_gmt']) || isset($input['date'])) {
             $insert['edit_date'] = true;
         }
         $post_id = wp_update_post((object) $insert);
     }
     if (!$post_id || is_wp_error($post_id)) {
         return $post_id;
     }
     // make sure this post actually exists and is not an error of some kind (ie, trying to load media in the posts endpoint)
     $post_check = $this->get_post_by('ID', $post_id, $args['context']);
     if (is_wp_error($post_check)) {
         return $post_check;
     }
     if ($has_media || $has_media_by_url) {
         $media_files = !empty($input['media']) ? $input['media'] : array();
         $media_urls = !empty($input['media_urls']) ? $input['media_urls'] : array();
         $media_attrs = !empty($input['media_attrs']) ? $input['media_attrs'] : array();
         $force_parent_id = $post_id;
         $media_results = $this->handle_media_creation_v1_1($media_files, $media_urls, $media_attrs, $force_parent_id);
     }
     // set page template for this post..
     if (isset($input['page_template']) && 'page' == $post_type->name) {
         $page_template = $input['page_template'];
         $page_templates = wp_get_theme()->get_page_templates(get_post($post_id));
         if (empty($page_template) || 'default' == $page_template || isset($page_templates[$page_template])) {
             update_post_meta($post_id, '_wp_page_template', $page_template);
         }
     }
     // Set like status for the post
     $sitewide_likes_enabled = (bool) apply_filters('wpl_is_enabled_sitewide', !get_option('disabled_likes'));
     if ($new) {
         if ($sitewide_likes_enabled) {
             if (false === $likes) {
                 update_post_meta($post_id, 'switch_like_status', 1);
             } else {
                 delete_post_meta($post_id, 'switch_like_status');
             }
         } else {
             if ($likes) {
                 update_post_meta($post_id, 'switch_like_status', 1);
             } else {
                 delete_post_meta($post_id, 'switch_like_status');
             }
         }
     } else {
         if (isset($likes)) {
             if ($sitewide_likes_enabled) {
                 if (false === $likes) {
                     update_post_meta($post_id, 'switch_like_status', 1);
                 } else {
                     delete_post_meta($post_id, 'switch_like_status');
                 }
             } else {
                 if (true === $likes) {
                     update_post_meta($post_id, 'switch_like_status', 1);
                 } else {
                     delete_post_meta($post_id, 'switch_like_status');
                 }
             }
         }
     }
     // Set sharing status of the post
     if ($new) {
         $sharing_enabled = isset($sharing) ? (bool) $sharing : true;
         if (false === $sharing_enabled) {
             update_post_meta($post_id, 'sharing_disabled', 1);
         }
     } else {
         if (isset($sharing) && true === $sharing) {
             delete_post_meta($post_id, 'sharing_disabled');
         } else {
             if (isset($sharing) && false == $sharing) {
                 update_post_meta($post_id, 'sharing_disabled', 1);
             }
         }
     }
     if (true === $sticky) {
         stick_post($post_id);
     } else {
         unstick_post($post_id);
     }
     // WPCOM Specific (Jetpack's will get bumped elsewhere
     // Tracks how many posts are published and sets meta so we can track some other cool stats (like likes & comments on posts published)
     if ($new && 'publish' == $input['status'] || !$new && isset($last_status) && 'publish' != $last_status && isset($new_status) && 'publish' == $new_status) {
         if (function_exists('bump_stats_extras')) {
             bump_stats_extras('api-insights-posts', $this->api->token_details['client_id']);
             update_post_meta($post_id, '_rest_api_published', 1);
             update_post_meta($post_id, '_rest_api_client_id', $this->api->token_details['client_id']);
         }
     }
     // We ask the user/dev to pass Publicize services he/she wants activated for the post, but Publicize expects us
     // to instead flag the ones we don't want to be skipped. proceed with said logic.
     // any posts coming from Path (client ID 25952) should also not publicize
     if ($publicize === false || isset($this->api->token_details['client_id']) && 25952 == $this->api->token_details['client_id']) {
         // No publicize at all, skip all by ID
         foreach ($GLOBALS['publicize_ui']->publicize->get_services('all') as $name => $service) {
             delete_post_meta($post_id, $GLOBALS['publicize_ui']->publicize->POST_SKIP . $name);
             $service_connections = $GLOBALS['publicize_ui']->publicize->get_connections($name);
             if (!$service_connections) {
                 continue;
             }
             foreach ($service_connections as $service_connection) {
                 update_post_meta($post_id, $GLOBALS['publicize_ui']->publicize->POST_SKIP . $service_connection->unique_id, 1);
             }
         }
     } else {
         if (is_array($publicize) && count($publicize) > 0) {
             foreach ($GLOBALS['publicize_ui']->publicize->get_services('all') as $name => $service) {
                 /*
                  * We support both indexed and associative arrays:
                  * * indexed are to pass entire services
                  * * associative are to pass specific connections per service
                  *
                  * We do support mixed arrays: mixed integer and string keys (see 3rd example below).
                  *
                  * EG: array( 'twitter', 'facebook') will only publicize to those, ignoring the other available services
                  * 		Form data: publicize[]=twitter&publicize[]=facebook
                  * EG: array( 'twitter' => '(int) $pub_conn_id_0, (int) $pub_conn_id_3', 'facebook' => (int) $pub_conn_id_7 ) will publicize to two Twitter accounts, and one Facebook connection, of potentially many.
                  * 		Form data: publicize[twitter]=$pub_conn_id_0,$pub_conn_id_3&publicize[facebook]=$pub_conn_id_7
                  * EG: array( 'twitter', 'facebook' => '(int) $pub_conn_id_0, (int) $pub_conn_id_3' ) will publicize to all available Twitter accounts, but only 2 of potentially many Facebook connections
                  * 		Form data: publicize[]=twitter&publicize[facebook]=$pub_conn_id_0,$pub_conn_id_3
                  */
                 // Delete any stale SKIP value for the service by name. We'll add it back by ID.
                 delete_post_meta($post_id, $GLOBALS['publicize_ui']->publicize->POST_SKIP . $name);
                 // Get the user's connections
                 $service_connections = $GLOBALS['publicize_ui']->publicize->get_connections($name);
                 // if the user doesn't have any connections for this service, move on
                 if (!$service_connections) {
                     continue;
                 }
                 if (!in_array($name, $publicize) && !array_key_exists($name, $publicize)) {
                     // Skip the whole service by adding each connection ID
                     foreach ($service_connections as $service_connection) {
                         update_post_meta($post_id, $GLOBALS['publicize_ui']->publicize->POST_SKIP . $service_connection->unique_id, 1);
                     }
                 } else {
                     if (!empty($publicize[$name])) {
                         // Seems we're being asked to only push to [a] specific connection[s].
                         // Explode the list on commas, which will also support a single passed ID
                         $requested_connections = explode(',', preg_replace('/[\\s]*/', '', $publicize[$name]));
                         // Flag the connections we can't match with the requested list to be skipped.
                         foreach ($service_connections as $service_connection) {
                             if (!in_array($service_connection->meta['connection_data']->id, $requested_connections)) {
                                 update_post_meta($post_id, $GLOBALS['publicize_ui']->publicize->POST_SKIP . $service_connection->unique_id, 1);
                             } else {
                                 delete_post_meta($post_id, $GLOBALS['publicize_ui']->publicize->POST_SKIP . $service_connection->unique_id);
                             }
                         }
                     } else {
                         // delete all SKIP values; it's okay to publish to all connected IDs for this service
                         foreach ($service_connections as $service_connection) {
                             delete_post_meta($post_id, $GLOBALS['publicize_ui']->publicize->POST_SKIP . $service_connection->unique_id);
                         }
                     }
                 }
             }
         }
     }
     if (!empty($publicize_custom_message)) {
         update_post_meta($post_id, $GLOBALS['publicize_ui']->publicize->POST_MESS, trim($publicize_custom_message));
     }
     set_post_format($post_id, $insert['post_format']);
     if (isset($featured_image)) {
         parent::parse_and_set_featured_image($post_id, $delete_featured_image, $featured_image);
     }
     if (!empty($metadata)) {
         foreach ((array) $metadata as $meta) {
             $meta = (object) $meta;
             $existing_meta_item = new stdClass();
             if (empty($meta->operation)) {
                 $meta->operation = 'update';
             }
             if (!empty($meta->value)) {
                 if ('true' == $meta->value) {
                     $meta->value = true;
                 }
                 if ('false' == $meta->value) {
                     $meta->value = false;
                 }
             }
             if (!empty($meta->id)) {
                 $meta->id = absint($meta->id);
                 $existing_meta_item = get_metadata_by_mid('post', $meta->id);
             }
             $unslashed_meta_key = wp_unslash($meta->key);
             // should match what the final key will be
             $meta->key = wp_slash($meta->key);
             $unslashed_existing_meta_key = wp_unslash($existing_meta_item->meta_key);
             $existing_meta_item->meta_key = wp_slash($existing_meta_item->meta_key);
             // make sure that the meta id passed matches the existing meta key
             if (!empty($meta->id) && !empty($meta->key)) {
                 $meta_by_id = get_metadata_by_mid('post', $meta->id);
                 if ($meta_by_id->meta_key !== $meta->key) {
                     continue;
                     // skip this meta
                 }
             }
             switch ($meta->operation) {
                 case 'delete':
                     if (!empty($meta->id) && !empty($existing_meta_item->meta_key) && current_user_can('delete_post_meta', $post_id, $unslashed_existing_meta_key)) {
                         delete_metadata_by_mid('post', $meta->id);
                     } elseif (!empty($meta->key) && !empty($meta->previous_value) && current_user_can('delete_post_meta', $post_id, $unslashed_meta_key)) {
                         delete_post_meta($post_id, $meta->key, $meta->previous_value);
                     } elseif (!empty($meta->key) && current_user_can('delete_post_meta', $post_id, $unslashed_meta_key)) {
                         delete_post_meta($post_id, $meta->key);
                     }
                     break;
                 case 'add':
                     if (!empty($meta->id) || !empty($meta->previous_value)) {
                         continue;
                     } elseif (!empty($meta->key) && !empty($meta->value) && current_user_can('add_post_meta', $post_id, $unslashed_meta_key) || $this->is_metadata_public($meta->key)) {
                         add_post_meta($post_id, $meta->key, $meta->value);
                     }
                     break;
                 case 'update':
                     if (!isset($meta->value)) {
                         continue;
                     } elseif (!empty($meta->id) && !empty($existing_meta_item->meta_key) && (current_user_can('edit_post_meta', $post_id, $unslashed_existing_meta_key) || $this->is_metadata_public($meta->key))) {
                         update_metadata_by_mid('post', $meta->id, $meta->value);
                     } elseif (!empty($meta->key) && !empty($meta->previous_value) && (current_user_can('edit_post_meta', $post_id, $unslashed_meta_key) || $this->is_metadata_public($meta->key))) {
                         update_post_meta($post_id, $meta->key, $meta->value, $meta->previous_value);
                     } elseif (!empty($meta->key) && (current_user_can('edit_post_meta', $post_id, $unslashed_meta_key) || $this->is_metadata_public($meta->key))) {
                         update_post_meta($post_id, $meta->key, $meta->value);
                     }
                     break;
             }
         }
     }
     do_action('rest_api_inserted_post', $post_id, $insert, $new);
     $return = $this->get_post_by('ID', $post_id, $args['context']);
     if (!$return || is_wp_error($return)) {
         return $return;
     }
     if (isset($input['type']) && 'revision' === $input['type']) {
         $return['preview_nonce'] = wp_create_nonce('post_preview_' . $input['parent']);
     }
     // workaround for sticky test occasionally failing, maybe a race condition with stick_post() above
     $return['sticky'] = true === $sticky;
     if (!empty($media_results['errors'])) {
         $return['media_errors'] = $media_results['errors'];
     }
     do_action('wpcom_json_api_objects', 'posts');
     return $return;
 }
 /**
  * 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);
 }
コード例 #6
0
 protected function __construct()
 {
     $this->api = WPCOM_JSON_API::init();
 }
コード例 #7
0
 function json_api($args = array())
 {
     $json_api_args = $args[0];
     $verify_api_user_args = $args[1];
     $method = (string) $json_api_args[0];
     $url = (string) $json_api_args[1];
     $post_body = is_null($json_api_args[2]) ? null : (string) $json_api_args[2];
     $my_id = (int) $json_api_args[3];
     $user_details = (array) $json_api_args[4];
     if (!$verify_api_user_args) {
         $user_id = 0;
     } elseif ('internal' === $verify_api_user_args[0]) {
         $user_id = (int) $verify_api_user_args[1];
         if ($user_id) {
             $user = get_user_by('id', $user_id);
             if (!$user || is_wp_error($user)) {
                 return false;
             }
         }
     } else {
         $user_id = call_user_func(array($this, 'test_api_user_code'), $verify_api_user_args);
         if (!$user_id) {
             return false;
         }
     }
     /* debugging
     		error_log( "-- begin json api via jetpack debugging -- " );
     		error_log( "METHOD: $method" );
     		error_log( "URL: $url" );
     		error_log( "POST BODY: $post_body" );
     		error_log( "MY JETPACK ID: $my_id" );
     		error_log( "VERIFY_ARGS: " . print_r( $verify_api_user_args, 1 ) );
     		error_log( "VERIFIED USER_ID: " . (int) $user_id );
     		error_log( "-- end json api via jetpack debugging -- " );
     		*/
     $old_user = wp_get_current_user();
     wp_set_current_user($user_id);
     $token = Jetpack_Data::get_access_token(get_current_user_id());
     if (!$token || is_wp_error($token)) {
         return false;
     }
     define('REST_API_REQUEST', true);
     define('WPCOM_JSON_API__BASE', 'public-api.wordpress.com/rest/v1');
     // needed?
     require_once ABSPATH . 'wp-admin/includes/admin.php';
     require_once dirname(__FILE__) . '/class.json-api.php';
     $api = WPCOM_JSON_API::init($method, $url, $post_body);
     $api->token_details['user'] = $user_details;
     require_once dirname(__FILE__) . '/class.json-api-endpoints.php';
     $display_errors = ini_set('display_errors', 0);
     ob_start();
     $content_type = $api->serve(false);
     $output = ob_get_clean();
     ini_set('display_errors', $display_errors);
     $nonce = wp_generate_password(10, false);
     $hmac = hash_hmac('md5', $nonce . $output, $token->secret);
     wp_set_current_user(isset($old_user->ID) ? $old_user->ID : 0);
     return array((string) $output, (string) $nonce, (string) $hmac);
 }
コード例 #8
0
 /**
  * Casts $value according to $type.
  * Handles fallbacks for certain values of $type when $value is not that $type
  * Currently, only handles fallback between string <-> array (two way), from string -> false (one way), and from object -> false (one way)
  *
  * Handles "child types" - array:URL, object:category
  * array:URL means an array of URLs
  * object:category means a hash of categories
  *
  * Handles object typing - object>post means an object of type post
  */
 function cast_and_filter_item(&$return, $type, $key, $value, $types = array(), $for_output = false)
 {
     if (is_string($type)) {
         $type = compact('type');
     }
     switch ($type['type']) {
         case 'false':
             $return[$key] = false;
             break;
         case 'url':
             $return[$key] = (string) esc_url_raw($value);
             break;
         case 'string':
             // Fallback string -> array
             if (is_array($value)) {
                 if (!empty($types[0])) {
                     $next_type = array_shift($types);
                     return $this->cast_and_filter_item($return, $next_type, $key, $value, $types, $for_output);
                 }
             }
             // Fallback string -> false
             if (!is_string($value)) {
                 if (!empty($types[0]) && 'false' === $types[0]['type']) {
                     $next_type = array_shift($types);
                     return $this->cast_and_filter_item($return, $next_type, $key, $value, $types, $for_output);
                 }
             }
             $return[$key] = (string) $value;
             break;
         case 'html':
             $return[$key] = (string) $value;
             break;
         case 'safehtml':
             $return[$key] = wp_kses((string) $value, wp_kses_allowed_html());
             break;
         case 'media':
             if (is_array($value)) {
                 if (isset($value['name'])) {
                     // It's a $_FILES array
                     // Reformat into array of $_FILES items
                     $files = array();
                     foreach ($value['name'] as $k => $v) {
                         $files[$k] = array();
                         foreach (array_keys($value) as $file_key) {
                             $files[$k][$file_key] = $value[$file_key][$k];
                         }
                     }
                     $return[$key] = $files;
                 }
                 break;
             } else {
                 // no break - treat as 'array'
             }
             // nobreak
         // nobreak
         case 'array':
             // Fallback array -> string
             if (is_string($value)) {
                 if (!empty($types[0])) {
                     $next_type = array_shift($types);
                     return $this->cast_and_filter_item($return, $next_type, $key, $value, $types, $for_output);
                 }
             }
             if (isset($type['children'])) {
                 $children = array();
                 foreach ((array) $value as $k => $child) {
                     $this->cast_and_filter_item($children, $type['children'], $k, $child, array(), $for_output);
                 }
                 $return[$key] = (array) $children;
                 break;
             }
             $return[$key] = (array) $value;
             break;
         case 'iso 8601 datetime':
         case 'datetime':
             // (string)s
             $dates = $this->parse_date((string) $value);
             if ($for_output) {
                 $return[$key] = $this->format_date($dates[1], $dates[0]);
             } else {
                 list($return[$key], $return["{$key}_gmt"]) = $dates;
             }
             break;
         case 'float':
             $return[$key] = (double) $value;
             break;
         case 'int':
         case 'integer':
             $return[$key] = (int) $value;
             break;
         case 'bool':
         case 'boolean':
             $return[$key] = (bool) WPCOM_JSON_API::is_truthy($value);
             break;
         case 'object':
             // Fallback object -> false
             if (is_scalar($value) || is_null($value)) {
                 if (!empty($types[0]) && 'false' === $types[0]['type']) {
                     return $this->cast_and_filter_item($return, 'false', $key, $value, $types, $for_output);
                 }
             }
             if (isset($type['children'])) {
                 $children = array();
                 foreach ((array) $value as $k => $child) {
                     $this->cast_and_filter_item($children, $type['children'], $k, $child, array(), $for_output);
                 }
                 $return[$key] = (object) $children;
                 break;
             }
             if (isset($type['subtype'])) {
                 return $this->cast_and_filter_item($return, $type['subtype'], $key, $value, $types, $for_output);
             }
             $return[$key] = (object) $value;
             break;
         case 'post':
             $return[$key] = (object) $this->cast_and_filter($value, $this->post_object_format, false, $for_output);
             break;
         case 'comment':
             $return[$key] = (object) $this->cast_and_filter($value, $this->comment_object_format, false, $for_output);
             break;
         case 'tag':
         case 'category':
             $docs = array('ID' => '(int)', 'name' => '(string)', 'slug' => '(string)', 'description' => '(HTML)', 'post_count' => '(int)', 'meta' => '(object)');
             if ('category' === $type['type']) {
                 $docs['parent'] = '(int)';
             }
             $return[$key] = (object) $this->cast_and_filter($value, $docs, false, $for_output);
             break;
         case 'post_reference':
         case 'comment_reference':
             $docs = array('ID' => '(int)', 'type' => '(string)', 'title' => '(string)', 'link' => '(URL)');
             $return[$key] = (object) $this->cast_and_filter($value, $docs, false, $for_output);
             break;
         case 'geo':
             $docs = array('latitude' => '(float)', 'longitude' => '(float)', 'address' => '(string)');
             $return[$key] = (object) $this->cast_and_filter($value, $docs, false, $for_output);
             break;
         case 'author':
             $docs = array('ID' => '(int)', 'user_login' => '(string)', 'email' => '(string|false)', 'name' => '(string)', 'URL' => '(URL)', 'avatar_URL' => '(URL)', 'profile_URL' => '(URL)');
             $return[$key] = (object) $this->cast_and_filter($value, $docs, false, $for_output);
             break;
         case 'attachment':
             $docs = array('ID' => '(int)', 'URL' => '(URL)', 'guid' => '(string)', 'mime_type' => '(string)', 'width' => '(int)', 'height' => '(int)', 'duration' => '(int)');
             $return[$key] = (object) $this->cast_and_filter($value, apply_filters('wpcom_json_api_attachment_cast_and_filter', $docs), false, $for_output);
             break;
         case 'metadata':
             $docs = array('id' => '(int)', 'key' => '(string)', 'value' => '(string|false|float|int|array|object)', 'previous_value' => '(string)', 'operation' => '(string)');
             $return[$key] = (object) $this->cast_and_filter($value, apply_filters('wpcom_json_api_attachment_cast_and_filter', $docs), false, $for_output);
             break;
         case 'plugin':
             $docs = array('id' => '(string)   The plugin\'s ID', 'active' => '(boolean)  The plugin status.', 'update' => '(object)   The plugin update info.', 'name' => '(string)   The name of the plugin.', 'plugin_url' => '(url)      Link to the plugin\'s web site.', 'version' => '(string)   The plugin version number.', 'description' => '(safehtml) Description of what the plugin does and/or notes from the author', 'author' => '(string)   The plugin author\'s name', 'author_url' => '(url)      The plugin author web site address', 'network' => '(boolean)  Whether the plugin can only be activated network wide.', 'autoupdate' => '(boolean)  Whether the plugin is automatically updated', 'log' => '(array)    An array of log strings telling how the plugin was modified');
             $return[$key] = (object) $this->cast_and_filter($value, apply_filters('wpcom_json_api_plugin_cast_and_filter', $docs), false, $for_output);
             break;
         case 'jetpackmodule':
             $docs = array('id' => '(string)   The module\'s ID', 'active' => '(boolean)  The module\'s status.', 'name' => '(string)   The module\'s name.', 'description' => '(safehtml) The module\'s description.', 'sort' => '(int)      The module\'s display order.', 'introduced' => '(string)   The Jetpack version when the module was introduced.', 'changed' => '(string)   The Jetpack version when the module was changed.', 'free' => '(boolean)  The module\'s Free or Paid status.', 'module_tags' => '(array)    The module\'s tags.');
             $return[$key] = (object) $this->cast_and_filter($value, apply_filters('wpcom_json_api_plugin_cast_and_filter', $docs), false, $for_output);
             break;
         default:
             trigger_error("Unknown API casting type {$type['type']}", E_USER_WARNING);
     }
 }
コード例 #9
0
 function callback($path = '', $blog_id = 0)
 {
     global $wpdb;
     if ('mine' === $blog_id) {
         $api = WPCOM_JSON_API::init();
         if (!$api->token_details || empty($api->token_details['blog_id'])) {
             return new WP_Error('authorization_required', 'An active access token must be used to query information about the current blog.', 403);
         }
         $blog_id = $api->token_details['blog_id'];
     }
     $blog_id = $this->api->switch_to_blog_and_validate_user($this->api->get_blog_id($blog_id));
     if (is_wp_error($blog_id)) {
         return $blog_id;
     }
     $is_user_logged_in = is_user_logged_in();
     $response = array();
     foreach (array_keys($this->response_format) as $key) {
         switch ($key) {
             case 'ID':
                 $response[$key] = (int) $this->api->get_blog_id_for_output();
                 break;
             case 'name':
                 $response[$key] = (string) get_bloginfo('name');
                 break;
             case 'description':
                 $response[$key] = (string) get_bloginfo('description');
                 break;
             case 'URL':
                 $response[$key] = (string) home_url();
                 break;
             case 'jetpack':
                 if ($is_user_logged_in) {
                     $response[$key] = false;
                 }
                 // magic
                 break;
             case 'post_count':
                 if ($is_user_logged_in) {
                     $response[$key] = (int) $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_status = 'publish'");
                 }
                 break;
             case 'lang':
                 if ($is_user_logged_in) {
                     $response[$key] = (string) get_bloginfo('language');
                 }
                 break;
             case 'meta':
                 $response[$key] = (object) array('links' => (object) array('self' => (string) $this->get_site_link($this->api->get_blog_id_for_output()), 'help' => (string) $this->get_site_link($this->api->get_blog_id_for_output(), 'help'), 'posts' => (string) $this->get_site_link($this->api->get_blog_id_for_output(), 'posts/'), 'comments' => (string) $this->get_site_link($this->api->get_blog_id_for_output(), 'comments/')));
                 break;
         }
     }
     do_action('wpcom_json_api_objects', 'sites');
     return $response;
 }
コード例 #10
0
 /**
  * Casts $value according to $type.
  * Handles fallbacks for certain values of $type when $value is not that $type
  * Currently, only handles fallback between string <-> array (two way), from string -> false (one way), and from object -> false (one way),
  * and string -> object (one way)
  *
  * Handles "child types" - array:URL, object:category
  * array:URL means an array of URLs
  * object:category means a hash of categories
  *
  * Handles object typing - object>post means an object of type post
  */
 function cast_and_filter_item(&$return, $type, $key, $value, $types = array(), $for_output = false)
 {
     if (is_string($type)) {
         $type = compact('type');
     }
     switch ($type['type']) {
         case 'false':
             $return[$key] = false;
             break;
         case 'url':
             $return[$key] = (string) esc_url_raw($value);
             break;
         case 'string':
             // Fallback string -> array, or for string -> object
             if (is_array($value) || is_object($value)) {
                 if (!empty($types[0])) {
                     $next_type = array_shift($types);
                     return $this->cast_and_filter_item($return, $next_type, $key, $value, $types, $for_output);
                 }
             }
             // Fallback string -> false
             if (!is_string($value)) {
                 if (!empty($types[0]) && 'false' === $types[0]['type']) {
                     $next_type = array_shift($types);
                     return $this->cast_and_filter_item($return, $next_type, $key, $value, $types, $for_output);
                 }
             }
             $return[$key] = (string) $value;
             break;
         case 'html':
             $return[$key] = (string) $value;
             break;
         case 'safehtml':
             $return[$key] = wp_kses((string) $value, wp_kses_allowed_html());
             break;
         case 'media':
             if (is_array($value)) {
                 if (isset($value['name']) && is_array($value['name'])) {
                     // It's a $_FILES array
                     // Reformat into array of $_FILES items
                     $files = array();
                     foreach ($value['name'] as $k => $v) {
                         $files[$k] = array();
                         foreach (array_keys($value) as $file_key) {
                             $files[$k][$file_key] = $value[$file_key][$k];
                         }
                     }
                     $return[$key] = $files;
                     break;
                 }
             } else {
                 // no break - treat as 'array'
             }
             // nobreak
         // nobreak
         case 'array':
             // Fallback array -> string
             if (is_string($value)) {
                 if (!empty($types[0])) {
                     $next_type = array_shift($types);
                     return $this->cast_and_filter_item($return, $next_type, $key, $value, $types, $for_output);
                 }
             }
             if (isset($type['children'])) {
                 $children = array();
                 foreach ((array) $value as $k => $child) {
                     $this->cast_and_filter_item($children, $type['children'], $k, $child, array(), $for_output);
                 }
                 $return[$key] = (array) $children;
                 break;
             }
             $return[$key] = (array) $value;
             break;
         case 'iso 8601 datetime':
         case 'datetime':
             // (string)s
             $dates = $this->parse_date((string) $value);
             if ($for_output) {
                 $return[$key] = $this->format_date($dates[1], $dates[0]);
             } else {
                 list($return[$key], $return["{$key}_gmt"]) = $dates;
             }
             break;
         case 'float':
             $return[$key] = (double) $value;
             break;
         case 'int':
         case 'integer':
             $return[$key] = (int) $value;
             break;
         case 'bool':
         case 'boolean':
             $return[$key] = (bool) WPCOM_JSON_API::is_truthy($value);
             break;
         case 'object':
             // Fallback object -> false
             if (is_scalar($value) || is_null($value)) {
                 if (!empty($types[0]) && 'false' === $types[0]['type']) {
                     return $this->cast_and_filter_item($return, 'false', $key, $value, $types, $for_output);
                 }
             }
             if (isset($type['children'])) {
                 $children = array();
                 foreach ((array) $value as $k => $child) {
                     $this->cast_and_filter_item($children, $type['children'], $k, $child, array(), $for_output);
                 }
                 $return[$key] = (object) $children;
                 break;
             }
             if (isset($type['subtype'])) {
                 return $this->cast_and_filter_item($return, $type['subtype'], $key, $value, $types, $for_output);
             }
             $return[$key] = (object) $value;
             break;
         case 'post':
             $return[$key] = (object) $this->cast_and_filter($value, $this->post_object_format, false, $for_output);
             break;
         case 'comment':
             $return[$key] = (object) $this->cast_and_filter($value, $this->comment_object_format, false, $for_output);
             break;
         case 'tag':
         case 'category':
             $docs = array('ID' => '(int)', 'name' => '(string)', 'slug' => '(string)', 'description' => '(HTML)', 'post_count' => '(int)', 'meta' => '(object)');
             if ('category' === $type['type']) {
                 $docs['parent'] = '(int)';
             }
             $return[$key] = (object) $this->cast_and_filter($value, $docs, false, $for_output);
             break;
         case 'post_reference':
         case 'comment_reference':
             $docs = array('ID' => '(int)', 'type' => '(string)', 'title' => '(string)', 'link' => '(URL)');
             $return[$key] = (object) $this->cast_and_filter($value, $docs, false, $for_output);
             break;
         case 'geo':
             $docs = array('latitude' => '(float)', 'longitude' => '(float)', 'address' => '(string)');
             $return[$key] = (object) $this->cast_and_filter($value, $docs, false, $for_output);
             break;
         case 'author':
             $docs = array('ID' => '(int)', 'user_login' => '(string)', 'login' => '(string)', 'email' => '(string|false)', 'name' => '(string)', 'first_name' => '(string)', 'last_name' => '(string)', 'nice_name' => '(string)', 'URL' => '(URL)', 'avatar_URL' => '(URL)', 'profile_URL' => '(URL)', 'is_super_admin' => '(bool)', 'roles' => '(array:string)');
             $return[$key] = (object) $this->cast_and_filter($value, $docs, false, $for_output);
             break;
         case 'role':
             $docs = array('name' => '(string)', 'display_name' => '(string)', 'capabilities' => '(object:boolean)');
             $return[$key] = (object) $this->cast_and_filter($value, $docs, false, $for_output);
             break;
         case 'attachment':
             $docs = array('ID' => '(int)', 'URL' => '(URL)', 'guid' => '(string)', 'mime_type' => '(string)', 'width' => '(int)', 'height' => '(int)', 'duration' => '(int)');
             $return[$key] = (object) $this->cast_and_filter($value, apply_filters('wpcom_json_api_attachment_cast_and_filter', $docs), false, $for_output);
             break;
         case 'metadata':
             $docs = array('id' => '(int)', 'key' => '(string)', 'value' => '(string|false|float|int|array|object)', 'previous_value' => '(string)', 'operation' => '(string)');
             $return[$key] = (object) $this->cast_and_filter($value, apply_filters('wpcom_json_api_attachment_cast_and_filter', $docs), false, $for_output);
             break;
         case 'plugin':
             $docs = array('id' => '(safehtml) The plugin\'s ID', 'slug' => '(safehtml) The plugin\'s Slug', 'active' => '(boolean)  The plugin status.', 'update' => '(object)   The plugin update info.', 'name' => '(safehtml) The name of the plugin.', 'plugin_url' => '(url)      Link to the plugin\'s web site.', 'version' => '(safehtml) The plugin version number.', 'description' => '(safehtml) Description of what the plugin does and/or notes from the author', 'author' => '(safehtml) The plugin author\'s name', 'author_url' => '(url)      The plugin author web site address', 'network' => '(boolean)  Whether the plugin can only be activated network wide.', 'autoupdate' => '(boolean)  Whether the plugin is auto updated', 'log' => '(array:safehtml) An array of update log strings.');
             $return[$key] = (object) $this->cast_and_filter($value, apply_filters('wpcom_json_api_plugin_cast_and_filter', $docs), false, $for_output);
             break;
         case 'jetpackmodule':
             $docs = array('id' => '(string)   The module\'s ID', 'active' => '(boolean)  The module\'s status.', 'name' => '(string)   The module\'s name.', 'description' => '(safehtml) The module\'s description.', 'sort' => '(int)      The module\'s display order.', 'introduced' => '(string)   The Jetpack version when the module was introduced.', 'changed' => '(string)   The Jetpack version when the module was changed.', 'free' => '(boolean)  The module\'s Free or Paid status.', 'module_tags' => '(array)    The module\'s tags.');
             $return[$key] = (object) $this->cast_and_filter($value, apply_filters('wpcom_json_api_plugin_cast_and_filter', $docs), false, $for_output);
             break;
         case 'sharing_button':
             $docs = array('ID' => '(string)', 'name' => '(string)', 'URL' => '(string)', 'icon' => '(string)', 'enabled' => '(bool)', 'visibility' => '(string)');
             $return[$key] = (array) $this->cast_and_filter($value, $docs, false, $for_output);
             break;
         case 'sharing_button_service':
             $docs = array('ID' => '(string) The service identifier', 'name' => '(string) The service name', 'class_name' => '(string) Class name for custom style sharing button elements', 'genericon' => '(string) The Genericon unicode character for the custom style sharing button icon', 'preview_smart' => '(string) An HTML snippet of a rendered sharing button smart preview', 'preview_smart_js' => '(string) An HTML snippet of the page-wide initialization scripts used for rendering the sharing button smart preview');
             $return[$key] = (array) $this->cast_and_filter($value, $docs, false, $for_output);
             break;
         case 'taxonomy':
             $docs = array('name' => '(string) The taxonomy slug', 'label' => '(string) The taxonomy human-readable name', 'labels' => '(object) Mapping of labels for the taxonomy', 'description' => '(string) The taxonomy description', 'hierarchical' => '(bool) Whether the taxonomy is hierarchical', 'public' => '(bool) Whether the taxonomy is public', 'capabilities' => '(object) Mapping of current user capabilities for the taxonomy');
             $return[$key] = (array) $this->cast_and_filter($value, $docs, false, $for_output);
             break;
         default:
             $method_name = $type['type'] . '_docs';
             if (method_exists(WPCOM_JSON_API_Jetpack_Overrides, $method_name)) {
                 $docs = WPCOM_JSON_API_Jetpack_Overrides::$method_name();
             }
             if (!empty($docs)) {
                 $return[$key] = (object) $this->cast_and_filter($value, apply_filters('wpcom_json_api_plugin_cast_and_filter', $docs), false, $for_output);
             } else {
                 trigger_error("Unknown API casting type {$type['type']}", E_USER_WARNING);
             }
     }
 }
 function json_api($args = array())
 {
     $json_api_args = $args[0];
     $verify_api_user_args = $args[1];
     $method = (string) $json_api_args[0];
     $url = (string) $json_api_args[1];
     $post_body = is_null($json_api_args[2]) ? null : (string) $json_api_args[2];
     $user_details = (array) $json_api_args[4];
     $locale = (string) $json_api_args[5];
     if (!$verify_api_user_args) {
         $user_id = 0;
     } elseif ('internal' === $verify_api_user_args[0]) {
         $user_id = (int) $verify_api_user_args[1];
         if ($user_id) {
             $user = get_user_by('id', $user_id);
             if (!$user || is_wp_error($user)) {
                 return false;
             }
         }
     } else {
         $user_id = call_user_func(array($this, 'test_api_user_code'), $verify_api_user_args);
         if (!$user_id) {
             return false;
         }
     }
     /* debugging
     		error_log( "-- begin json api via jetpack debugging -- " );
     		error_log( "METHOD: $method" );
     		error_log( "URL: $url" );
     		error_log( "POST BODY: $post_body" );
     		error_log( "VERIFY_ARGS: " . print_r( $verify_api_user_args, 1 ) );
     		error_log( "VERIFIED USER_ID: " . (int) $user_id );
     		error_log( "-- end json api via jetpack debugging -- " );
     		*/
     if ('en' !== $locale) {
         // .org mo files are named slightly different from .com, and all we have is this the locale -- try to guess them.
         $new_locale = $locale;
         if (strpos($locale, '-') !== false) {
             $pieces = explode('-', $locale);
             $new_locale = $locale_pieces[0];
             $new_locale .= !empty($locale_pieces[1]) ? '_' . strtoupper($locale_pieces[1]) : '';
         } else {
             // .com might pass 'fr' because thats what our language files are named as, where core seems
             // to do fr_FR - so try that if we don't think we can load the file.
             if (!file_exists(WP_LANG_DIR . '/' . $locale . '.mo')) {
                 $new_locale = $locale . '_' . strtoupper($locale);
             }
         }
         if (file_exists(WP_LANG_DIR . '/' . $new_locale . '.mo')) {
             unload_textdomain('default');
             load_textdomain('default', WP_LANG_DIR . '/' . $new_locale . '.mo');
         }
     }
     $old_user = wp_get_current_user();
     wp_set_current_user($user_id);
     $token = Jetpack_Data::get_access_token(get_current_user_id());
     if (!$token || is_wp_error($token)) {
         return false;
     }
     define('REST_API_REQUEST', true);
     define('WPCOM_JSON_API__BASE', 'public-api.wordpress.com/rest/v1');
     // needed?
     require_once ABSPATH . 'wp-admin/includes/admin.php';
     require_once JETPACK__PLUGIN_DIR . 'class.json-api.php';
     $api = WPCOM_JSON_API::init($method, $url, $post_body);
     $api->token_details['user'] = $user_details;
     require_once JETPACK__PLUGIN_DIR . 'class.json-api-endpoints.php';
     $display_errors = ini_set('display_errors', 0);
     ob_start();
     $content_type = $api->serve(false);
     $output = ob_get_clean();
     ini_set('display_errors', $display_errors);
     $nonce = wp_generate_password(10, false);
     $hmac = hash_hmac('md5', $nonce . $output, $token->secret);
     wp_set_current_user(isset($old_user->ID) ? $old_user->ID : 0);
     return array((string) $output, (string) $nonce, (string) $hmac);
 }
コード例 #12
0
 /**
  * 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);
 }