Skip to content

Commit 3abc57f

Browse files
authored
Merge pull request #11 from spacedmonkey/feature/40365-rest-sites-endpoint-no-network
REST API: Limit the sites endpoint to the current network
2 parents 944e506 + 94133a0 commit 3abc57f

5 files changed

Lines changed: 340 additions & 476 deletions

File tree

‎src/wp-includes/capabilities.php‎

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,46 +1155,26 @@ function remove_role( $role ) {
11551155
* Retrieves a list of super admins.
11561156
*
11571157
* @since 3.0.0
1158-
* @since 7.2.0 Added the `$network_id` parameter.
11591158
*
11601159
* @global array $super_admins
11611160
*
1162-
* @param int|null $network_id Optional. ID of the network. Default is the current network.
11631161
* @return string[] List of super admin logins.
11641162
*/
1165-
function get_super_admins( $network_id = null ) {
1163+
function get_super_admins() {
11661164
global $super_admins;
11671165

1168-
// Falsy values (including 0) mean "unspecified", matching get_network_option()'s own fallback.
1169-
$is_current_network = ! $network_id || get_current_network_id() === (int) $network_id;
1170-
1171-
if ( $is_current_network && isset( $super_admins ) ) {
1172-
return $super_admins;
1173-
}
1174-
1175-
/*
1176-
* The 'admin' fallback exists for the current network only, where it reflects the
1177-
* install's original default super admin. A network whose `site_admins` option was
1178-
* never explicitly set has no default super admins - assuming 'admin' there would let
1179-
* any user with that login be treated as a super admin of a network they were never
1180-
* granted access to.
1181-
*/
1182-
$default = $is_current_network ? array( 'admin' ) : array();
1183-
1184-
return get_network_option( $network_id, 'site_admins', $default );
1166+
return $super_admins ?? get_site_option( 'site_admins', array( 'admin' ) );
11851167
}
11861168

11871169
/**
11881170
* Determines whether user is a site admin.
11891171
*
11901172
* @since 3.0.0
1191-
* @since 7.2.0 Added the `$network_id` parameter.
11921173
*
1193-
* @param int|false $user_id Optional. The ID of a user. Defaults to false, to check the current user.
1194-
* @param int|null $network_id Optional. ID of the network. Default is the current network.
1174+
* @param int|false $user_id Optional. The ID of a user. Defaults to false, to check the current user.
11951175
* @return bool Whether the user is a site admin.
11961176
*/
1197-
function is_super_admin( $user_id = false, $network_id = null ) {
1177+
function is_super_admin( $user_id = false ) {
11981178
if ( ! $user_id ) {
11991179
$user = wp_get_current_user();
12001180
} else {
@@ -1206,7 +1186,7 @@ function is_super_admin( $user_id = false, $network_id = null ) {
12061186
}
12071187

12081188
if ( is_multisite() ) {
1209-
$super_admins = get_super_admins( $network_id );
1189+
$super_admins = get_super_admins();
12101190
if ( is_array( $super_admins ) && in_array( $user->user_login, $super_admins, true ) ) {
12111191
return true;
12121192
}

‎src/wp-includes/rest-api/endpoints/class-wp-rest-sites-controller.php‎

Lines changed: 31 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -133,16 +133,6 @@ public function get_items_permissions_check( $request ) {
133133
return $multisite_support;
134134
}
135135

136-
foreach ( array( 'network', 'network_exclude' ) as $network_key ) {
137-
if ( ! isset( $request[ $network_key ] ) ) {
138-
continue;
139-
}
140-
$network_check = $this->check_network_ids( (array) $request[ $network_key ] );
141-
if ( is_wp_error( $network_check ) ) {
142-
return $network_check;
143-
}
144-
}
145-
146136
if ( $this->check_edit_permission() ) {
147137
return true;
148138
}
@@ -203,8 +193,6 @@ public function get_items( $request ) {
203193
'include' => 'site__in',
204194
'offset' => 'offset',
205195
'order' => 'order',
206-
'network' => 'network__in',
207-
'network_exclude' => 'network__not_in',
208196
'per_page' => 'number',
209197
'path' => 'path__in',
210198
'path_exclude' => 'path__not_in',
@@ -230,10 +218,8 @@ public function get_items( $request ) {
230218
}
231219
}
232220

233-
// Without an explicit network filter, limit the results to the current network.
234-
if ( empty( $prepared_args['network__in'] ) ) {
235-
$prepared_args['network__in'] = array( get_current_network_id() );
236-
}
221+
// Only sites on the current network are exposed.
222+
$prepared_args['network__in'] = array( get_current_network_id() );
237223

238224
// WP_Site_Query tests the status columns with is_numeric(), and a boolean is not numeric.
239225
foreach ( array( 'public', 'archived', 'mature', 'spam', 'deleted' ) as $status_param ) {
@@ -260,7 +246,7 @@ public function get_items( $request ) {
260246
$orderby = $request['orderby'];
261247

262248
// Ordering by an ID list needs a list to order by.
263-
if ( in_array( $orderby, array( 'site__in', 'network__in' ), true ) && empty( $prepared_args[ $orderby ] ) ) {
249+
if ( 'site__in' === $orderby && empty( $prepared_args['site__in'] ) ) {
264250
$orderby = 'id';
265251
}
266252

@@ -426,11 +412,8 @@ public function get_item_permissions_check( $request ) {
426412
return $site;
427413
}
428414

429-
if ( $site->network_id > 0 ) {
430-
$network_check = $this->check_network_ids( (array) $site->network_id );
431-
if ( is_wp_error( $network_check ) ) {
432-
return $network_check;
433-
}
415+
if ( ! $this->site_in_network( $site ) ) {
416+
return new WP_Error( 'rest_unable_read_from_network', __( 'Sorry, you are not allowed to view sites on another network.' ), array( 'status' => rest_authorization_required_code() ) );
434417
}
435418

436419
$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
@@ -447,42 +430,29 @@ public function get_item_permissions_check( $request ) {
447430
}
448431

449432
/**
450-
* Validates that the given network IDs exist and are accessible to the current user.
451-
*
452-
* A user can always access the current network. Access to any other
453-
* network requires the user to be a super admin of that network.
433+
* Checks whether a site belongs to the current network.
454434
*
455435
* @since 7.2.0
456436
*
457-
* @param int[] $network_ids Array of network IDs.
458-
* @return true|WP_Error True if all network IDs exist and are accessible, WP_Error otherwise.
437+
* @param WP_Site $site Site object.
438+
* @return bool Whether the site is on the current network.
459439
*/
460-
protected function check_network_ids( array $network_ids ) {
461-
$current_network_id = get_current_network_id();
462-
$user_id = get_current_user_id();
463-
464-
_prime_network_caches( $network_ids );
465-
foreach ( $network_ids as $network_id ) {
466-
if ( ! get_network( $network_id ) ) {
467-
return new WP_Error( 'rest_network_id_invalid', __( 'Invalid network ID.' ), array( 'status' => 400 ) );
468-
}
469-
}
470-
471-
if ( count( $network_ids ) === 1 && $current_network_id === $network_ids[0] ) {
472-
return true;
473-
}
474-
475-
foreach ( $network_ids as $network_id ) {
476-
if ( (int) $network_id === $current_network_id ) {
477-
continue;
478-
}
479-
480-
if ( ! is_super_admin( $user_id, $network_id ) ) {
481-
return new WP_Error( 'rest_cannot_view_network', __( 'Sorry, you are not allowed to access sites on this network.' ), array( 'status' => rest_authorization_required_code() ) );
482-
}
483-
}
440+
protected function site_in_network( WP_Site $site ) {
441+
$network_id = get_current_network_id();
484442

485-
return true;
443+
/**
444+
* Filters whether a site is treated as belonging to the current network.
445+
*
446+
* Returning false blocks the site from being read, updated or deleted
447+
* via the REST API.
448+
*
449+
* @since 7.2.0
450+
*
451+
* @param bool $in_network Whether the site belongs to the current network.
452+
* @param WP_Site $site The site being checked.
453+
* @param int $network_id The current network ID.
454+
*/
455+
return (bool) apply_filters( 'rest_site_in_network', $network_id === $site->network_id, $site, $network_id );
486456
}
487457

488458
/**
@@ -519,14 +489,6 @@ public function create_item_permissions_check( $request ) {
519489
return $multisite_support;
520490
}
521491

522-
$network_id = isset( $request['network'] ) ? (int) $request['network'] : get_current_network_id();
523-
if ( $network_id > 0 ) {
524-
$network_check = $this->check_network_ids( (array) $network_id );
525-
if ( is_wp_error( $network_check ) ) {
526-
return $network_check;
527-
}
528-
}
529-
530492
if ( ! current_user_can( 'create_sites' ) ) {
531493
return new WP_Error( 'rest_cannot_create', __( 'Sorry, you are not allowed to create sites.' ), array( 'status' => rest_authorization_required_code() ) );
532494
}
@@ -652,12 +614,8 @@ public function update_item_permissions_check( $request ) {
652614
return $site;
653615
}
654616

655-
$network_id = isset( $request['network'] ) ? (int) $request['network'] : $site->network_id;
656-
if ( $network_id > 0 ) {
657-
$network_check = $this->check_network_ids( (array) $network_id );
658-
if ( is_wp_error( $network_check ) ) {
659-
return $network_check;
660-
}
617+
if ( ! $this->site_in_network( $site ) ) {
618+
return new WP_Error( 'rest_unable_update_from_network', __( 'Sorry, you are not allowed to edit sites on another network.' ), array( 'status' => rest_authorization_required_code() ) );
661619
}
662620

663621
if ( ! $this->check_edit_permission() ) {
@@ -755,11 +713,8 @@ public function delete_item_permissions_check( $request ) {
755713
return $site;
756714
}
757715

758-
if ( $site->network_id > 0 ) {
759-
$network_check = $this->check_network_ids( (array) $site->network_id );
760-
if ( is_wp_error( $network_check ) ) {
761-
return $network_check;
762-
}
716+
if ( ! $this->site_in_network( $site ) ) {
717+
return new WP_Error( 'rest_unable_delete_from_network', __( 'Sorry, you are not allowed to delete sites on another network.' ), array( 'status' => rest_authorization_required_code() ) );
763718
}
764719

765720
if ( ! $this->check_delete_permission( $site ) ) {
@@ -1060,13 +1015,6 @@ protected function prepare_item_for_database( $request ) {
10601015
}
10611016
}
10621017

1063-
if ( isset( $request['network'] ) ) {
1064-
if ( ! get_network( $request['network'] ) ) {
1065-
return new WP_Error( 'rest_network_id_invalid', __( 'Invalid network ID.' ), array( 'status' => 400 ) );
1066-
}
1067-
$prepared_site['network_id'] = (int) $request['network'];
1068-
}
1069-
10701018
if ( isset( $request['path'] ) ) {
10711019
$prepared_site['path'] = $request['path'];
10721020
}
@@ -1265,7 +1213,7 @@ protected function check_url_is_available( $prepared_site, $request ) {
12651213
$id = (int) $request['id'];
12661214
$domain = isset( $prepared_site['domain'] ) ? $prepared_site['domain'] : '';
12671215
$path = isset( $prepared_site['path'] ) ? $prepared_site['path'] : '/';
1268-
$network_id = isset( $prepared_site['network_id'] ) ? $prepared_site['network_id'] : get_current_network_id();
1216+
$network_id = get_current_network_id();
12691217

12701218
if ( ! empty( $id ) ) {
12711219
// Updating a site: fall back to the current values for anything the request left out.
@@ -1281,9 +1229,7 @@ protected function check_url_is_available( $prepared_site, $request ) {
12811229
if ( ! isset( $prepared_site['path'] ) ) {
12821230
$path = $current_site->path;
12831231
}
1284-
if ( ! isset( $prepared_site['network_id'] ) ) {
1285-
$network_id = (int) $current_site->network_id;
1286-
}
1232+
$network_id = (int) $current_site->network_id;
12871233
}
12881234

12891235
$existing_site_id = domain_exists( $domain, $path, $network_id );
@@ -1320,9 +1266,10 @@ public function get_item_schema() {
13201266
'readonly' => true,
13211267
),
13221268
'network' => array(
1323-
'description' => __( 'The site\'s network ID. Default is the current network ID.' ),
1269+
'description' => __( 'The site\'s network ID.' ),
13241270
'type' => 'integer',
13251271
'context' => array( 'view', 'edit', 'embed' ),
1272+
'readonly' => true,
13261273
),
13271274
'domain' => array(
13281275
'description' => __( 'Site domain.' ),
@@ -1546,7 +1493,6 @@ public function get_collection_params() {
15461493
'domain_length',
15471494
'path_length',
15481495
'site__in',
1549-
'network__in',
15501496
),
15511497
);
15521498
$query_params['user'] = array(
@@ -1600,24 +1546,6 @@ public function get_collection_params() {
16001546
'format' => 'date-time',
16011547
);
16021548

1603-
$query_params['network'] = array(
1604-
'default' => array(),
1605-
'description' => __( 'Limit result set to sites of specific network IDs.' ),
1606-
'type' => 'array',
1607-
'items' => array(
1608-
'type' => 'integer',
1609-
),
1610-
);
1611-
1612-
$query_params['network_exclude'] = array(
1613-
'default' => array(),
1614-
'description' => __( 'Ensure result set excludes specific network IDs.' ),
1615-
'type' => 'array',
1616-
'items' => array(
1617-
'type' => 'integer',
1618-
),
1619-
);
1620-
16211549
/**
16221550
* Filter collection parameters for the sites controller.
16231551
*

0 commit comments

Comments
 (0)