Make WordPress Core

Ticket #40365: 40365.diff

File 40365.diff, 31.7 KB (added by spacedmonkey, 9 years ago)
  • src/wp-includes/rest-api/endpoints/class-wp-rest-sites-controller.php

     
     1<?php
     2/**
     3 * REST API: WP_REST_Sites_Controller class
     4 *
     5 * @package WordPress
     6 * @subpackage REST_API
     7 * @since 4.9.0
     8 */
     9
     10/**
     11 * Core controller used to access sites via the REST API.
     12 *
     13 * @since 4.9.0
     14 *
     15 * @see WP_REST_Controller
     16 */
     17class WP_REST_Sites_Controller extends WP_REST_Controller {
     18
     19        /**
     20         * Instance of a site meta fields object.
     21         *
     22         * @since 4.9.0
     23         * @var WP_REST_Site_Meta_Fields
     24         */
     25        protected $meta;
     26
     27        /**
     28         * Constructor.
     29         *
     30         * @since 4.9.0
     31         */
     32        public function __construct() {
     33                $this->namespace = 'wp/v2';
     34                $this->rest_base = 'sites';
     35
     36                $this->meta = new WP_REST_Site_Meta_Fields();
     37        }
     38
     39        /**
     40         * Registers the routes for the objects of the controller.
     41         *
     42         * @since 4.9.0
     43         */
     44        public function register_routes() {
     45
     46                register_rest_route( $this->namespace, '/' . $this->rest_base, array(
     47                        array(
     48                                'methods'   => WP_REST_Server::READABLE,
     49                                'callback'  => array( $this, 'get_items' ),
     50                                'permission_callback' => array( $this, 'get_items_permissions_check' ),
     51                                'args'      => $this->get_collection_params(),
     52                        ),
     53                        array(
     54                                'methods'  => WP_REST_Server::CREATABLE,
     55                                'callback' => array( $this, 'create_item' ),
     56                                'permission_callback' => array( $this, 'create_item_permissions_check' ),
     57                                'args'     => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
     58                        ),
     59                        'schema' => array( $this, 'get_public_item_schema' ),
     60                ) );
     61
     62                register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array(
     63                        'args' => array(
     64                                'id' => array(
     65                                        'description' => __( 'Unique identifier for the object.' ),
     66                                        'type'        => 'integer',
     67                                ),
     68                        ),
     69                        array(
     70                                'methods'  => WP_REST_Server::READABLE,
     71                                'callback' => array( $this, 'get_item' ),
     72                                'permission_callback' => array( $this, 'get_item_permissions_check' ),
     73                                'args'     => array(
     74                                        'context'          => $this->get_context_param( array( 'default' => 'view' ) ),
     75                                        'password' => array(
     76                                                'description' => __( 'The password for the parent post of the site (if the post is password protected).' ),
     77                                                'type'        => 'string',
     78                                        ),
     79                                ),
     80                        ),
     81                        array(
     82                                'methods'  => WP_REST_Server::EDITABLE,
     83                                'callback' => array( $this, 'update_item' ),
     84                                'permission_callback' => array( $this, 'update_item_permissions_check' ),
     85                                'args'     => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
     86                        ),
     87                        array(
     88                                'methods'  => WP_REST_Server::DELETABLE,
     89                                'callback' => array( $this, 'delete_item' ),
     90                                'permission_callback' => array( $this, 'delete_item_permissions_check' ),
     91                                'args'     => array(
     92                                        'force'    => array(
     93                                                'type'        => 'boolean',
     94                                                'default'     => false,
     95                                                'description' => __( 'Whether to bypass trash and force deletion.' ),
     96                                        ),
     97                                        'password' => array(
     98                                                'description' => __( 'The password for the parent post of the site (if the post is password protected).' ),
     99                                                'type'        => 'string',
     100                                        ),
     101                                ),
     102                        ),
     103                        'schema' => array( $this, 'get_public_item_schema' ),
     104                ) );
     105        }
     106
     107        /**
     108         * Checks if a given request has access to read sites.
     109         *
     110         * @since 4.9.0
     111         *
     112         * @param WP_REST_Request $request Full details about the request.
     113         * @return WP_Error|bool True if the request has read access, error object otherwise.
     114         */
     115        public function get_items_permissions_check( $request ) {
     116
     117                if ( ! empty( $request['context'] ) && 'edit' === $request['context'] && ! current_user_can( 'manage_sites' ) ) {
     118                        return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit sites.' ), array( 'status' => rest_authorization_required_code() ) );
     119                }
     120               
     121
     122                return true;
     123        }
     124
     125        /**
     126         * Retrieves a list of site items.
     127         *
     128         * @since 4.9.0
     129         *
     130         * @param WP_REST_Request $request Full details about the request.
     131         * @return WP_Error|WP_REST_Response Response object on success, or error object on failure.
     132         */
     133        public function get_items( $request ) {
     134
     135                // Retrieve the list of registered collection query parameters.
     136                $registered = $this->get_collection_params();
     137
     138                /*
     139                 * This array defines mappings between public API query parameters whose
     140                 * values are accepted as-passed, and their internal WP_Query parameter
     141                 * name equivalents (some are the same). Only values which are also
     142                 * present in $registered will be set.
     143                 */
     144                $parameter_mappings = array(
     145                        'domain'          => 'domain__in',
     146                        'domain_exclude'  => 'domain__not_in',
     147                        'exclude'         => 'site__not_in',
     148                        'include'         => 'site__in',
     149                        'offset'          => 'offset',
     150                        'order'           => 'order',
     151                        'network'         => 'network__in',
     152                        'network_exclude' => 'network__not_in',
     153                        'per_page'        => 'number',
     154                        'path'            => 'path__in',
     155                        'path_exclude'    => 'path__not_in',
     156                        'search'          => 'search',
     157                        'public'          => 'public',
     158                        'archived'        => 'archived',
     159                        'mature'          => 'mature',
     160                        'spam'            => 'spam',
     161                        'deleted'         => 'deleted',
     162                        'lang_id'         => 'lang__in',
     163                        'lang_id_exclude' => 'lang__not_in',
     164                );
     165
     166                $prepared_args = array();
     167
     168                /*
     169                 * For each known parameter which is both registered and present in the request,
     170                 * set the parameter's value on the query $prepared_args.
     171                 */
     172                foreach ( $parameter_mappings as $api_param => $wp_param ) {
     173                        if ( isset( $registered[ $api_param ], $request[ $api_param ] ) ) {
     174                                $prepared_args[ $wp_param ] = $request[ $api_param ];
     175                        }
     176                }
     177
     178               
     179                // Ensure certain parameter values default to empty strings.
     180                foreach (
     181                        array(
     182                                'search',
     183                                'domain',
     184                                'domain_exclude',
     185                                'lang_id',
     186                                'lang_id_exclude',
     187                                'path',
     188                                'path_exclude'
     189                        ) as $param
     190                ) {
     191                        if ( ! isset( $prepared_args[ $param ] ) ) {
     192                                $prepared_args[ $param ] = '';
     193                        }
     194                }
     195
     196                if ( isset( $registered['orderby'] ) ) {
     197                        $prepared_args['orderby'] =  $request['orderby'] ;
     198                }
     199
     200                $prepared_args['no_found_rows'] = false;
     201
     202                $prepared_args['date_query'] = array();
     203
     204                // Set before into date query. Date query must be specified as an array of an array.
     205                if ( isset( $registered['before'], $request['before'] ) ) {
     206                        $prepared_args['date_query'][0]['before'] = $request['before'];
     207                }
     208
     209                // Set after into date query. Date query must be specified as an array of an array.
     210                if ( isset( $registered['after'], $request['after'] ) ) {
     211                        $prepared_args['date_query'][0]['after'] = $request['after'];
     212                }
     213
     214                if ( isset( $registered['page'] ) && empty( $request['offset'] ) ) {
     215                        $prepared_args['offset'] = $prepared_args['number'] * ( absint( $request['page'] ) - 1 );
     216                }
     217
     218                /**
     219                 * Filters arguments, before passing to WP_Site_Query, when querying sites via the REST API.
     220                 *
     221                 * @since 4.9.0
     222                 *
     223                 * @link https://developer.wordpress.org/reference/classes/wp_site_query/
     224                 *
     225                 * @param array           $prepared_args Array of arguments for WP_Site_Query.
     226                 * @param WP_REST_Request $request       The current request.
     227                 */
     228                $prepared_args = apply_filters( 'rest_site_query', $prepared_args, $request );
     229
     230                $query = new WP_Site_Query;
     231                $query_result = $query->query( $prepared_args );
     232
     233                $sites = array();
     234
     235                foreach ( $query_result as $site ) {
     236                        if ( ! $this->check_read_permission( $site, $request ) ) {
     237                                continue;
     238                        }
     239
     240                        $data = $this->prepare_item_for_response( $site, $request );
     241                        $sites[] = $this->prepare_response_for_collection( $data );
     242                }
     243
     244                $total_sites = (int) $query->found_sites;
     245                $max_pages      = (int) $query->max_num_pages;
     246
     247                if ( $total_sites < 1 ) {
     248                        // Out-of-bounds, run the query again without LIMIT for total count.
     249                        unset( $prepared_args['number'], $prepared_args['offset'] );
     250
     251                        $query = new WP_Site_Query;
     252                        $prepared_args['count'] = true;
     253
     254                        $total_sites = $query->query( $prepared_args );
     255                        $max_pages = ceil( $total_sites / $request['per_page'] );
     256                }
     257
     258                $response = rest_ensure_response( $sites );
     259                $response->header( 'X-WP-Total', $total_sites );
     260                $response->header( 'X-WP-TotalPages', $max_pages );
     261
     262                $base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ) );
     263
     264                if ( $request['page'] > 1 ) {
     265                        $prev_page = $request['page'] - 1;
     266
     267                        if ( $prev_page > $max_pages ) {
     268                                $prev_page = $max_pages;
     269                        }
     270
     271                        $prev_link = add_query_arg( 'page', $prev_page, $base );
     272                        $response->link_header( 'prev', $prev_link );
     273                }
     274
     275                if ( $max_pages > $request['page'] ) {
     276                        $next_page = $request['page'] + 1;
     277                        $next_link = add_query_arg( 'page', $next_page, $base );
     278
     279                        $response->link_header( 'next', $next_link );
     280                }
     281
     282                return $response;
     283        }
     284
     285        /**
     286         * Get the site, if the ID is valid.
     287         *
     288         * @since 4.9.0
     289         *
     290         * @param int $id Supplied ID.
     291         * @return WP_Site|WP_Error Site object if ID is valid, WP_Error otherwise.
     292         */
     293        protected function get_site( $id ) {
     294                $error = new WP_Error( 'rest_site_invalid_id', __( 'Invalid site ID.' ), array( 'status' => 404 ) );
     295                if ( (int) $id <= 0 ) {
     296                        return $error;
     297                }
     298
     299                $id = (int) $id;
     300                $site = get_site( $id );
     301                if ( empty( $site ) ) {
     302                        return $error;
     303                }
     304
     305                return $site;
     306        }
     307
     308        /**
     309         * Checks if a given request has access to read the site.
     310         *
     311         * @since 4.9.0
     312         *
     313         * @param WP_REST_Request $request Full details about the request.
     314         * @return WP_Error|bool True if the request has read access for the item, error object otherwise.
     315         */
     316        public function get_item_permissions_check( $request ) {
     317                $site = $this->get_site( $request['id'] );
     318                if ( is_wp_error( $site ) ) {
     319                        return $site;
     320                }
     321
     322                if ( ! empty( $request['context'] ) && 'edit' === $request['context'] && ! current_user_can( 'manage_sites' ) ) {
     323                        return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit sites.' ), array( 'status' => rest_authorization_required_code() ) );
     324                }
     325
     326                return true;
     327        }
     328
     329        /**
     330         * Retrieves a site.
     331         *
     332         * @since 4.9.0
     333         *
     334         * @param WP_REST_Request $request Full details about the request.
     335         * @return WP_Error|WP_REST_Response Response object on success, or error object on failure.
     336         */
     337        public function get_item( $request ) {
     338                $site = $this->get_site( $request['id'] );
     339                if ( is_wp_error( $site ) ) {
     340                        return $site;
     341                }
     342
     343                $data = $this->prepare_item_for_response( $site, $request );
     344                $response = rest_ensure_response( $data );
     345
     346                return $response;
     347        }
     348
     349        /**
     350         * Checks if a given request has access to create a site.
     351         *
     352         * @since 4.9.0
     353         *
     354         * @param WP_REST_Request $request Full details about the request.
     355         * @return WP_Error|bool True if the request has access to create items, error object otherwise.
     356         */
     357        public function create_item_permissions_check( $request ) {
     358                if ( 0 === get_current_user_id() ) {
     359                        return false;
     360                }
     361
     362                return current_user_can( 'create_sites' );
     363        }
     364
     365        /**
     366         * Creates a site.
     367         *
     368         * @since 4.9.0
     369         *
     370         * @param WP_REST_Request $request Full details about the request.
     371         * @return WP_Error|WP_REST_Response Response object on success, or error object on failure.
     372         */
     373        public function create_item( $request ) {
     374
     375                if ( ! empty( $request['id'] ) ) {
     376                        return new WP_Error( 'rest_site_exists', __( 'Cannot create existing site.' ), array( 'status' => 400 ) );
     377                }
     378
     379                $prepared_site = $this->prepare_item_for_database( $request );
     380                if ( is_wp_error( $prepared_site ) ) {
     381                        return $prepared_site;
     382                }
     383
     384                /*
     385                 * Do not allow a site to be created with missing or empty
     386                 * domain
     387                 */
     388
     389                if ( empty( $prepared_site['domain'] ) ) {
     390                        return new WP_Error( 'rest_domain_invalid', __( 'Invalid domain' ), array( 'status' => 400 ) );
     391                }
     392
     393
     394                // Set user data if the user's logged in.
     395                if ( is_user_logged_in() &&  empty( $prepared_site['user_id'] ) ) {
     396                        $user = wp_get_current_user();
     397                        $prepared_site['user_id'] = $user->ID;
     398                }
     399
     400                /**
     401                 * Filters a site before it is inserted via the REST API.
     402                 *
     403                 * Allows modification of the site right before it is inserted via wpmu_create_blog().
     404                 * Returning a WP_Error value from the filter will shortcircuit insertion and allow
     405                 * skipping further processing.
     406                 *
     407                 * @since 4.9.0
     408                 * @since 4.8.0 $prepared_site can now be a WP_Error to shortcircuit insertion.
     409                 *
     410                 * @param array|WP_Error  $prepared_site The prepared site data for wpmu_create_blog().
     411                 * @param WP_REST_Request $request          Request used to insert the site.
     412                 */
     413                $prepared_site = apply_filters( 'rest_pre_insert_site', $prepared_site, $request );
     414                if ( is_wp_error( $prepared_site ) ) {
     415                        return $prepared_site;
     416                }
     417
     418                $site_id = wpmu_create_blog( $prepared_site['domain'], $prepared_site['path'], $prepared_site['title'], $prepared_site['user_id'], $prepared_site['fields'], $prepared_site['network_id'] );
     419
     420                if ( is_wp_error( $site_id ) ) {
     421                        return $site_id;
     422                }
     423               
     424                if ( ! $site_id ) {
     425                        return new WP_Error( 'rest_site_failed_create', __( 'Creating site failed.' ), array( 'status' => 500 ) );
     426                }
     427               
     428                $site = get_site( $site_id );
     429
     430                /**
     431                 * Fires after a site is created or updated via the REST API.
     432                 *
     433                 * @since 4.9.0
     434                 *
     435                 * @param WP_Site      $site  Inserted or updated site object.
     436                 * @param WP_REST_Request $request  Request object.
     437                 * @param bool            $creating True when creating a site, false
     438                 *                                  when updating.
     439                 */
     440                do_action( 'rest_insert_site', $site, $request, true );
     441
     442                $schema = $this->get_item_schema();
     443
     444                if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) {
     445                        $meta_update = $this->meta->update_value( $request['meta'], $site_id );
     446
     447                        if ( is_wp_error( $meta_update ) ) {
     448                                return $meta_update;
     449                        }
     450                }
     451
     452                $fields_update = $this->update_additional_fields_for_object( $site, $request );
     453
     454                if ( is_wp_error( $fields_update ) ) {
     455                        return $fields_update;
     456                }
     457
     458                $context = current_user_can( 'manage_sites' ) ? 'edit' : 'view';
     459
     460                $request->set_param( 'context', $context );
     461
     462                $response = $this->prepare_item_for_response( $site, $request );
     463                $response = rest_ensure_response( $response );
     464
     465                $response->set_status( 201 );
     466                $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $site_id ) ) );
     467
     468
     469                return $response;
     470        }
     471
     472        /**
     473         * Checks if a given REST request has access to update a site.
     474         *
     475         * @since 4.9.0
     476         *
     477         * @param WP_REST_Request $request Full details about the request.
     478         * @return WP_Error|bool True if the request has access to update the item, error object otherwise.
     479         */
     480        public function update_item_permissions_check( $request ) {
     481                $site = $this->get_site( $request['id'] );
     482                if ( is_wp_error( $site ) ) {
     483                        return $site;
     484                }
     485
     486                if ( ! $this->check_edit_permission( $site ) ) {
     487                        return new WP_Error( 'rest_cannot_edit', __( 'Sorry, you are not allowed to edit this site.' ), array( 'status' => rest_authorization_required_code() ) );
     488                }
     489
     490                return true;
     491        }
     492
     493        /**
     494         * Updates a site.
     495         *
     496         * @since 4.9.0
     497         *
     498         * @param WP_REST_Request $request Full details about the request.
     499         * @return WP_Error|WP_REST_Response Response object on success, or error object on failure.
     500         */
     501        public function update_item( $request ) {
     502                $site = $this->get_site( $request['id'] );
     503                if ( is_wp_error( $site ) ) {
     504                        return $site;
     505                }
     506
     507                $id = $site->blog_id;
     508
     509
     510                $prepared_args = $this->prepare_item_for_database( $request );
     511
     512                if ( is_wp_error( $prepared_args ) ) {
     513                        return $prepared_args;
     514                }
     515
     516                if ( ! empty( $prepared_args['network'] ) ) {
     517                        if ( ! get_network( $prepared_args['network'] ) ) {
     518                                return new WP_Error( 'rest_network_id_invalid', __( 'Invalid network ID.' ), array( 'status' => 400 ) );
     519                        }
     520                }
     521                if ( ! empty( $prepared_args['fields'] ) ) {
     522                        $meta_fields = array( 'public', 'archived', 'mature', 'spam', 'deleted', 'lang_id' );
     523                        foreach ( $meta_fields as $meta_field ) {
     524                                if ( isset( $prepared_args['fields'][ $meta_field ] ) ) {
     525                                        $prepared_args[ $meta_field ] = $prepared_args['fields'][ $meta_field ];
     526                                }
     527                        }
     528                        unset( $prepared_args['fields'] );
     529                }
     530
     531                if ( ! empty( $prepared_args ) ) {
     532                        if ( is_wp_error( $prepared_args ) ) {
     533                                return $prepared_args;
     534                        }
     535
     536                        if ( isset( $prepared_args['domain'] ) && empty( $prepared_args['domain'] ) ) {
     537                                return new WP_Error( 'rest_domain_invalid', __( 'Invalid domain.' ), array( 'status' => 400 ) );
     538                        }
     539
     540                        update_blog_details( $id, wp_slash( (array) $prepared_args ) );
     541
     542
     543                }
     544
     545                $site = get_site( $id );
     546
     547                /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-sites-controller.php */
     548                do_action( 'rest_insert_site', $site, $request, false );
     549
     550                $schema = $this->get_item_schema();
     551
     552                if ( ! empty( $schema['properties']['meta'] ) && isset( $request['meta'] ) ) {
     553                        $meta_update = $this->meta->update_value( $request['meta'], $id );
     554
     555                        if ( is_wp_error( $meta_update ) ) {
     556                                return $meta_update;
     557                        }
     558                }
     559
     560                $fields_update = $this->update_additional_fields_for_object( $site, $request );
     561
     562                if ( is_wp_error( $fields_update ) ) {
     563                        return $fields_update;
     564                }
     565
     566                $request->set_param( 'context', 'edit' );
     567
     568                $response = $this->prepare_item_for_response( $site, $request );
     569
     570                return rest_ensure_response( $response );
     571        }
     572
     573        /**
     574         * Checks if a given request has access to delete a site.
     575         *
     576         * @since 4.9.0
     577         *
     578         * @param WP_REST_Request $request Full details about the request.
     579         * @return WP_Error|bool True if the request has access to delete the item, error object otherwise.
     580         */
     581        public function delete_item_permissions_check( $request ) {
     582                $site = $this->get_site( $request['id'] );
     583                if ( is_wp_error( $site ) ) {
     584                        return $site;
     585                }
     586
     587                if ( 0 === (int) get_current_user_id() ) {
     588                        return false;
     589                }
     590
     591                if ( ! current_user_can( 'delete_sites' ) ) {
     592                        return new WP_Error( 'rest_cannot_delete', __( 'Sorry, you are not allowed to delete this site.' ), array( 'status' => rest_authorization_required_code() ) );
     593                }
     594
     595                return true;
     596        }
     597
     598        /**
     599         * Deletes a site.
     600         *
     601         * @since 4.9.0
     602         *
     603         * @param WP_REST_Request $request Full details about the request.
     604         * @return WP_Error|WP_REST_Response Response object on success, or error object on failure.
     605         */
     606        public function delete_item( $request ) {
     607                $site = $this->get_site( $request['id'] );
     608                if ( is_wp_error( $site ) ) {
     609                        return $site;
     610                }
     611
     612                $force = isset( $request['force'] ) ? (bool) $request['force'] : false;
     613
     614                $request->set_param( 'context', 'edit' );
     615
     616
     617                $previous = $this->prepare_item_for_response( $site, $request );
     618                wpmu_delete_blog( $site->blog_id, $force );
     619                $result   = $this->get_site( $site->blog_id );
     620                $response = new WP_REST_Response();
     621                $response->set_data( array( 'deleted' => true, 'previous' => $previous->get_data() ) );
     622
     623
     624                if ( $result ) {
     625                        return new WP_Error( 'rest_cannot_delete', __( 'The site cannot be deleted.' ), array( 'status' => 500 ) );
     626                }
     627
     628                /**
     629                 * Fires after a site is deleted via the REST API.
     630                 *
     631                 * @since 4.9.0
     632                 *
     633                 * @param WP_Site $site The deleted site data.
     634                 * @param WP_REST_Response $response The response returned from the API.
     635                 * @param WP_REST_Request $request The request sent to the API.
     636                 */
     637                do_action( 'rest_delete_site', $site, $response, $request );
     638
     639                return $response;
     640        }
     641
     642        /**
     643         * Prepares a single site output for response.
     644         *
     645         * @since 4.9.0
     646         *
     647         * @param WP_Site      $site Site object.
     648         * @param WP_REST_Request $request Request object.
     649         * @return WP_REST_Response Response object.
     650         */
     651        public function prepare_item_for_response( $site, $request ) {
     652                $data = array(
     653                        'id'           => (int) $site->blog_id,
     654                        'network'      => (int) $site->site_id,
     655                        'domain'       => $site->domain,
     656                        'path'         => $site->path,
     657                        'registered'   => $site->registered,
     658                        'last_updated' => $site->last_updated,
     659                        'public'       => (int) $site->public,
     660                        'archived'     => (int) $site->archived,
     661                        'mature'       => (int) $site->mature,
     662                        'spam'         => (int) $site->spam,
     663                        'deleted'      => (int) $site->deleted,
     664                        'lang_id'      => (int) $site->lang_id,
     665                );
     666
     667                $schema = $this->get_item_schema();
     668
     669                if ( ! empty( $schema['properties']['meta'] ) ) {
     670                        $data['meta'] = $this->meta->get_value( $site->blog_id, $request );
     671                }
     672
     673                $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
     674                $data    = $this->add_additional_fields_to_object( $data, $request );
     675                $data    = $this->filter_response_by_context( $data, $context );
     676
     677                // Wrap the data in a response object.
     678                $response = rest_ensure_response( $data );
     679
     680                /**
     681                 * Filters a site returned from the API.
     682                 *
     683                 * Allows modification of the site right before it is returned.
     684                 *
     685                 * @since 4.9.0
     686                 *
     687                 * @param WP_REST_Response  $response The response object.
     688                 * @param WP_Site        $site  The original site object.
     689                 * @param WP_REST_Request   $request  Request used to generate the response.
     690                 */
     691                return apply_filters( 'rest_prepare_site', $response, $site, $request );
     692        }
     693
     694        /**
     695         * Prepares a single site to be inserted into the database.
     696         *
     697         * @since 4.9.0
     698         *
     699         * @param WP_REST_Request $request Request object.
     700         * @return array|WP_Error Prepared site, otherwise WP_Error object.
     701         */
     702        protected function prepare_item_for_database( $request ) {
     703                $prepared_site = array();
     704
     705                $meta_fields = array( 'public', 'archived', 'mature', 'spam', 'deleted', 'lang_id' );
     706                foreach ( $meta_fields as $meta_field ) {
     707                        $prepared_site['fields'][ $meta_field ] = $request[ $meta_field ];
     708                }
     709
     710                $prepared_comment['network'] = 1;
     711                if ( isset( $request['network'] ) ) {
     712                        $prepared_site['network_id'] = (int) $request['network'];
     713                }
     714
     715                if ( isset( $request['user_id'] ) ) {
     716                        $prepared_site['user_id'] = (int) $request['user_id'];
     717                }
     718
     719                if ( empty( $request['path'] ) ) {
     720                        $prepared_site['path'] = '/';
     721                }
     722
     723                if ( isset( $request['domain'] ) ) {
     724                        $prepared_comment['domain'] = $request['domain'];
     725                }
     726
     727                /**
     728                 * Filters a site after it is prepared for the database.
     729                 *
     730                 * Allows modification of the site right after it is prepared for the database.
     731                 *
     732                 * @since 4.9.0
     733                 *
     734                 * @param array           $prepared_site The prepared site data for `wpmu_create_blog`.
     735                 * @param WP_REST_Request $request          The current request.
     736                 */
     737                return apply_filters( 'rest_preprocess_site', $prepared_site, $request );
     738        }
     739
     740        /**
     741         * Retrieves the site's schema, conforming to JSON Schema.
     742         *
     743         * @since 4.9.0
     744         *
     745         * @return array
     746         */
     747        public function get_item_schema() {
     748                $schema = array(
     749                        '$schema'    => 'http://json-schema.org/schema#',
     750                        'title'      => 'site',
     751                        'type'       => 'object',
     752                        'properties' => array(
     753                                'id'       => array(
     754                                        'description' => __( 'Unique identifier for the object.' ),
     755                                        'type'        => 'integer',
     756                                        'context'     => array( 'view', 'edit', 'embed' ),
     757                                        'readonly'    => true,
     758                                ),
     759                                'network'       => array(
     760                                        'description' => __( '' ),
     761                                        'type'        => 'integer',
     762                                        'context'     => array( 'view', 'edit', 'embed' ),
     763                                ),
     764                                'domain'   => array(
     765                                        'description' => __( '' ),
     766                                        'type'        => 'string',
     767                                        'context'     => array( 'view', 'edit', 'embed' ),
     768                                ),
     769                                'path'     => array(
     770                                        'description' => __( '' ),
     771                                        'type'        => 'string',
     772                                        'context'     => array( 'view', 'edit', 'embed' ),
     773                                ),
     774                                'registered'     => array(
     775                                        'description' => __( '' ),
     776                                        'type'        => 'string',
     777                                        'format'      => 'date-time',
     778                                        'context'     => array( 'view', 'edit', 'embed' ),
     779                                ),
     780                                'last_updated'     => array(
     781                                        'description' => __( '' ),
     782                                        'type'        => 'string',
     783                                        'format'      => 'date-time',
     784                                        'context'     => array( 'view', 'edit', 'embed' ),
     785                                ),
     786                                'public'   => array(
     787                                        'context'     => array( 'view', 'edit', 'embed' ),
     788                                        'description' => __( '' ),
     789                                        'type'        => 'integer',
     790                                ),
     791                                'archived' => array(
     792                                        'context'     => array( 'view', 'edit', 'embed' ),
     793                                        'description' => __( '' ),
     794                                        'type'        => 'integer',
     795                                ),
     796                                'mature' => array(
     797                                        'context'     => array( 'view', 'edit', 'embed' ),
     798                                        'description' => __( '' ),
     799                                        'type'        => 'integer',
     800                                ),
     801                                'spam' => array(
     802                                        'context'     => array( 'view', 'edit', 'embed' ),
     803                                        'description' => __( '' ),
     804                                        'type'        => 'integer',
     805                                ),
     806                                'deleted' => array(
     807                                        'context'     => array( 'view', 'edit', 'embed' ),
     808                                        'description' => __( '' ),
     809                                        'type'        => 'integer',
     810                                ),
     811                                'lang_id' => array(
     812                                        'context'     => array( 'view', 'edit', 'embed' ),
     813                                        'description' => __( '' ),
     814                                        'type'        => 'integer',
     815                                ),
     816                               
     817                        ),
     818                );
     819
     820
     821                $schema['properties']['meta'] = $this->meta->get_field_schema();
     822
     823                return $this->add_additional_fields_schema( $schema );
     824        }
     825
     826        /**
     827         * Retrieves the query params for collections.
     828         *
     829         * @since 4.9.0
     830         *
     831         * @return array Sites collection parameters.
     832         */
     833        public function get_collection_params() {
     834                $query_params = parent::get_collection_params();
     835
     836                $query_params['context']['default'] = 'view';
     837
     838
     839                $query_params['domain'] = array(
     840                        'description' => __( 'Limit result set to sites assigned to specific domain. ' ),
     841                        'type'        => 'array',
     842                        'items'       => array(
     843                                'type' => 'string',
     844                        ),
     845                );
     846
     847                $query_params['domain_exclude'] = array(
     848                        'description' => __( 'Ensure result set excludes sites assigned to specific domain. ' ),
     849                        'type'        => 'array',
     850                        'items'       => array(
     851                                'type' => 'string',
     852                        ),
     853                );
     854
     855                $query_params['path'] = array(
     856                        'description' => __( 'Limit result set to sites assigned to specific path. ' ),
     857                        'type'        => 'array',
     858                        'items'       => array(
     859                                'type' => 'string',
     860                        ),
     861                );
     862
     863                $query_params['path_exclude'] = array(
     864                        'description' => __( 'Ensure result set excludes sites assigned to specific path. ' ),
     865                        'type'        => 'array',
     866                        'items'       => array(
     867                                'type' => 'string',
     868                        ),
     869                );
     870
     871                $query_params['exclude'] = array(
     872                        'description' => __( 'Ensure result set excludes specific IDs.' ),
     873                        'type'        => 'array',
     874                        'items'       => array(
     875                                'type' => 'integer',
     876                        ),
     877                        'default'     => array(),
     878                );
     879
     880                $query_params['include'] = array(
     881                        'description' => __( 'Limit result set to specific IDs.' ),
     882                        'type'        => 'array',
     883                        'items'       => array(
     884                                'type' => 'integer',
     885                        ),
     886                        'default'     => array(),
     887                );
     888
     889                $query_params['offset'] = array(
     890                        'description' => __( 'Offset the result set by a specific number of items.' ),
     891                        'type'        => 'integer',
     892                );
     893
     894                $query_params['order'] = array(
     895                        'description' => __( 'Order sort attribute ascending or descending.' ),
     896                        'type'        => 'string',
     897                        'default'     => 'desc',
     898                        'enum'        => array(
     899                                'asc',
     900                                'desc',
     901                        ),
     902                );
     903
     904                $query_params['orderby'] = array(
     905                        'description' => __( 'Sort collection by object attribute.' ),
     906                        'type'        => 'string',
     907                        'default'     => 'id',
     908                        'enum'        => array(
     909                                'id',
     910                                'domain',
     911                                'path',
     912                                'network_id',
     913                                'last_updated',
     914                                'registered',
     915                                'domain_length',
     916                                'path_length',
     917                                'site__in',
     918                                'network__in'
     919                        ),
     920                );
     921                $query_params['network'] = array(
     922                        'default'     => array(),
     923                        'description' => __( 'Limit result set to sites of specific network IDs.' ),
     924                        'type'        => 'array',
     925                        'items'       => array(
     926                                'type' => 'integer',
     927                        ),
     928                );
     929
     930                $query_params['network_exclude'] = array(
     931                        'default'     => array(),
     932                        'description' => __( 'Ensure result set excludes specific network IDs.' ),
     933                        'type'        => 'array',
     934                        'items'       => array(
     935                                'type' => 'integer',
     936                        ),
     937                );
     938
     939
     940               
     941       
     942                /**
     943                 * Filter collection parameters for the sites controller.
     944                 *
     945                 * This filter registers the collection parameter, but does not map the
     946                 * collection parameter to an internal WP_Site_Query parameter. Use the
     947                 * `rest_site_query` filter to set WP_Site_Query parameters.
     948                 *
     949                 * @since 4.9.0
     950                 *
     951                 * @param array $query_params JSON Schema-formatted collection parameters.
     952                 */
     953                return apply_filters( 'rest_site_collection_params', $query_params );
     954        }
     955       
     956        /**
     957         * Checks if the site can be read.
     958         *
     959         * @since 4.9.0
     960         *
     961         * @param WP_Site      $site Site object.
     962         * @param WP_REST_Request $request Request data to check.
     963         * @return bool Whether the site can be read.
     964         */
     965        protected function check_read_permission( $site, $request ) {
     966
     967                if ( 0 === get_current_user_id() ) {
     968                        return false;
     969                }
     970
     971                return current_user_can( 'manage_sites' );
     972        }
     973
     974        /**
     975         * Checks if a site can be edited or deleted.
     976         *
     977         * @since 4.9.0
     978         *
     979         * @param object $site Site object.
     980         * @return bool Whether the site can be edited or deleted.
     981         */
     982        protected function check_edit_permission( $site ) {
     983                if ( 0 === (int) get_current_user_id() ) {
     984                        return false;
     985                }
     986
     987                return current_user_can( 'manage_sites' );
     988        }
     989
     990}
  • src/wp-includes/rest-api/fields/class-wp-rest-site-meta-fields.php

    Property changes on: src/wp-includes/rest-api/endpoints/class-wp-rest-sites-controller.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
     1<?php
     2/**
     3 * REST API: WP_REST_Site_Meta_Fields class
     4 *
     5 * @package WordPress
     6 * @subpackage REST_API
     7 * @since 4.7.0
     8 */
     9
     10/**
     11 * Core class to manage site meta via the REST API.
     12 *
     13 * @since 4.7.0
     14 *
     15 * @see WP_REST_Meta_Fields
     16 */
     17class WP_REST_Site_Meta_Fields extends WP_REST_Meta_Fields {
     18
     19        /**
     20         * Retrieves the object type for site meta.
     21         *
     22         * @since 4.7.0
     23         *
     24         * @return string The meta type.
     25         */
     26        protected function get_meta_type() {
     27                return 'blog';
     28        }
     29
     30        /**
     31         * Retrieves the type for register_rest_field() in the context of site.
     32         *
     33         * @since 4.7.0
     34         *
     35         * @return string The REST field type.
     36         */
     37        public function get_rest_field_type() {
     38                return 'blog';
     39        }
     40}
  • src/wp-includes/rest-api.php

    Property changes on: src/wp-includes/rest-api/fields/class-wp-rest-site-meta-fields.php
    ___________________________________________________________________
    Added: svn:executable
    ## -0,0 +1 ##
    +*
    \ No newline at end of property
     
    232232        // Settings.
    233233        $controller = new WP_REST_Settings_Controller;
    234234        $controller->register_routes();
     235
     236        if ( is_multisite() ) {
     237                // Sites.
     238                $controller = new WP_REST_Sites_Controller;
     239                $controller->register_routes();
     240        }
    235241}
    236242
    237243/**
  • src/wp-settings.php

     
    240240require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-term-meta-fields.php' );
    241241require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-user-meta-fields.php' );
    242242
     243if ( is_multisite() ) {
     244        require( ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-sites-controller.php' );
     245        require( ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-site-meta-fields.php' );
     246}
     247
    243248$GLOBALS['wp_embed'] = new WP_Embed();
    244249
    245250// Load multisite-specific files.