Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 5 additions & 25 deletions src/wp-includes/capabilities.php
Original file line number Diff line number Diff line change
Expand Up @@ -1155,46 +1155,26 @@ function remove_role( $role ) {
* Retrieves a list of super admins.
*
* @since 3.0.0
* @since 7.2.0 Added the `$network_id` parameter.
*
* @global array $super_admins
*
* @param int|null $network_id Optional. ID of the network. Default is the current network.
* @return string[] List of super admin logins.
*/
function get_super_admins( $network_id = null ) {
function get_super_admins() {
global $super_admins;

// Falsy values (including 0) mean "unspecified", matching get_network_option()'s own fallback.
$is_current_network = ! $network_id || get_current_network_id() === (int) $network_id;

if ( $is_current_network && isset( $super_admins ) ) {
return $super_admins;
}

/*
* The 'admin' fallback exists for the current network only, where it reflects the
* install's original default super admin. A network whose `site_admins` option was
* never explicitly set has no default super admins - assuming 'admin' there would let
* any user with that login be treated as a super admin of a network they were never
* granted access to.
*/
$default = $is_current_network ? array( 'admin' ) : array();

return get_network_option( $network_id, 'site_admins', $default );
return $super_admins ?? get_site_option( 'site_admins', array( 'admin' ) );
}

/**
* Determines whether user is a site admin.
*
* @since 3.0.0
* @since 7.2.0 Added the `$network_id` parameter.
*
* @param int|false $user_id Optional. The ID of a user. Defaults to false, to check the current user.
* @param int|null $network_id Optional. ID of the network. Default is the current network.
* @param int|false $user_id Optional. The ID of a user. Defaults to false, to check the current user.
* @return bool Whether the user is a site admin.
*/
function is_super_admin( $user_id = false, $network_id = null ) {
function is_super_admin( $user_id = false ) {
if ( ! $user_id ) {
$user = wp_get_current_user();
} else {
Expand All @@ -1206,7 +1186,7 @@ function is_super_admin( $user_id = false, $network_id = null ) {
}

if ( is_multisite() ) {
$super_admins = get_super_admins( $network_id );
$super_admins = get_super_admins();
if ( is_array( $super_admins ) && in_array( $user->user_login, $super_admins, true ) ) {
return true;
}
Expand Down
134 changes: 31 additions & 103 deletions src/wp-includes/rest-api/endpoints/class-wp-rest-sites-controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,16 +133,6 @@ public function get_items_permissions_check( $request ) {
return $multisite_support;
}

foreach ( array( 'network', 'network_exclude' ) as $network_key ) {
if ( ! isset( $request[ $network_key ] ) ) {
continue;
}
$network_check = $this->check_network_ids( (array) $request[ $network_key ] );
if ( is_wp_error( $network_check ) ) {
return $network_check;
}
}

if ( $this->check_edit_permission() ) {
return true;
}
Expand Down Expand Up @@ -203,8 +193,6 @@ public function get_items( $request ) {
'include' => 'site__in',
'offset' => 'offset',
'order' => 'order',
'network' => 'network__in',
'network_exclude' => 'network__not_in',
'per_page' => 'number',
'path' => 'path__in',
'path_exclude' => 'path__not_in',
Expand All @@ -230,10 +218,8 @@ public function get_items( $request ) {
}
}

// Without an explicit network filter, limit the results to the current network.
if ( empty( $prepared_args['network__in'] ) ) {
$prepared_args['network__in'] = array( get_current_network_id() );
}
// Only sites on the current network are exposed.
$prepared_args['network__in'] = array( get_current_network_id() );

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

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

Expand Down Expand Up @@ -426,11 +412,8 @@ public function get_item_permissions_check( $request ) {
return $site;
}

if ( $site->network_id > 0 ) {
$network_check = $this->check_network_ids( (array) $site->network_id );
if ( is_wp_error( $network_check ) ) {
return $network_check;
}
if ( ! $this->site_in_network( $site ) ) {
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() ) );
}

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

/**
* Validates that the given network IDs exist and are accessible to the current user.
*
* A user can always access the current network. Access to any other
* network requires the user to be a super admin of that network.
* Checks whether a site belongs to the current network.
*
* @since 7.2.0
*
* @param int[] $network_ids Array of network IDs.
* @return true|WP_Error True if all network IDs exist and are accessible, WP_Error otherwise.
* @param WP_Site $site Site object.
* @return bool Whether the site is on the current network.
*/
protected function check_network_ids( array $network_ids ) {
$current_network_id = get_current_network_id();
$user_id = get_current_user_id();

_prime_network_caches( $network_ids );
foreach ( $network_ids as $network_id ) {
if ( ! get_network( $network_id ) ) {
return new WP_Error( 'rest_network_id_invalid', __( 'Invalid network ID.' ), array( 'status' => 400 ) );
}
}

if ( count( $network_ids ) === 1 && $current_network_id === $network_ids[0] ) {
return true;
}

foreach ( $network_ids as $network_id ) {
if ( (int) $network_id === $current_network_id ) {
continue;
}

if ( ! is_super_admin( $user_id, $network_id ) ) {
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() ) );
}
}
protected function site_in_network( WP_Site $site ) {
$network_id = get_current_network_id();

return true;
/**
* Filters whether a site is treated as belonging to the current network.
*
* Returning false blocks the site from being read, updated or deleted
* via the REST API.
*
* @since 7.2.0
*
* @param bool $in_network Whether the site belongs to the current network.
* @param WP_Site $site The site being checked.
* @param int $network_id The current network ID.
*/
return (bool) apply_filters( 'rest_site_in_network', $network_id === $site->network_id, $site, $network_id );
}

/**
Expand Down Expand Up @@ -519,14 +489,6 @@ public function create_item_permissions_check( $request ) {
return $multisite_support;
}

$network_id = isset( $request['network'] ) ? (int) $request['network'] : get_current_network_id();
if ( $network_id > 0 ) {
$network_check = $this->check_network_ids( (array) $network_id );
if ( is_wp_error( $network_check ) ) {
return $network_check;
}
}

if ( ! current_user_can( 'create_sites' ) ) {
return new WP_Error( 'rest_cannot_create', __( 'Sorry, you are not allowed to create sites.' ), array( 'status' => rest_authorization_required_code() ) );
}
Expand Down Expand Up @@ -652,12 +614,8 @@ public function update_item_permissions_check( $request ) {
return $site;
}

$network_id = isset( $request['network'] ) ? (int) $request['network'] : $site->network_id;
if ( $network_id > 0 ) {
$network_check = $this->check_network_ids( (array) $network_id );
if ( is_wp_error( $network_check ) ) {
return $network_check;
}
if ( ! $this->site_in_network( $site ) ) {
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() ) );
}

if ( ! $this->check_edit_permission() ) {
Expand Down Expand Up @@ -755,11 +713,8 @@ public function delete_item_permissions_check( $request ) {
return $site;
}

if ( $site->network_id > 0 ) {
$network_check = $this->check_network_ids( (array) $site->network_id );
if ( is_wp_error( $network_check ) ) {
return $network_check;
}
if ( ! $this->site_in_network( $site ) ) {
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() ) );
}

if ( ! $this->check_delete_permission( $site ) ) {
Expand Down Expand Up @@ -1060,13 +1015,6 @@ protected function prepare_item_for_database( $request ) {
}
}

if ( isset( $request['network'] ) ) {
if ( ! get_network( $request['network'] ) ) {
return new WP_Error( 'rest_network_id_invalid', __( 'Invalid network ID.' ), array( 'status' => 400 ) );
}
$prepared_site['network_id'] = (int) $request['network'];
}

if ( isset( $request['path'] ) ) {
$prepared_site['path'] = $request['path'];
}
Expand Down Expand Up @@ -1265,7 +1213,7 @@ protected function check_url_is_available( $prepared_site, $request ) {
$id = (int) $request['id'];
$domain = isset( $prepared_site['domain'] ) ? $prepared_site['domain'] : '';
$path = isset( $prepared_site['path'] ) ? $prepared_site['path'] : '/';
$network_id = isset( $prepared_site['network_id'] ) ? $prepared_site['network_id'] : get_current_network_id();
$network_id = get_current_network_id();

if ( ! empty( $id ) ) {
// Updating a site: fall back to the current values for anything the request left out.
Expand All @@ -1281,9 +1229,7 @@ protected function check_url_is_available( $prepared_site, $request ) {
if ( ! isset( $prepared_site['path'] ) ) {
$path = $current_site->path;
}
if ( ! isset( $prepared_site['network_id'] ) ) {
$network_id = (int) $current_site->network_id;
}
$network_id = (int) $current_site->network_id;
}

$existing_site_id = domain_exists( $domain, $path, $network_id );
Expand Down Expand Up @@ -1320,9 +1266,10 @@ public function get_item_schema() {
'readonly' => true,
),
'network' => array(
'description' => __( 'The site\'s network ID. Default is the current network ID.' ),
'description' => __( 'The site\'s network ID.' ),
'type' => 'integer',
'context' => array( 'view', 'edit', 'embed' ),
'readonly' => true,
),
'domain' => array(
'description' => __( 'Site domain.' ),
Expand Down Expand Up @@ -1546,7 +1493,6 @@ public function get_collection_params() {
'domain_length',
'path_length',
'site__in',
'network__in',
),
);
$query_params['user'] = array(
Expand Down Expand Up @@ -1600,24 +1546,6 @@ public function get_collection_params() {
'format' => 'date-time',
);

$query_params['network'] = array(
'default' => array(),
'description' => __( 'Limit result set to sites of specific network IDs.' ),
'type' => 'array',
'items' => array(
'type' => 'integer',
),
);

$query_params['network_exclude'] = array(
'default' => array(),
'description' => __( 'Ensure result set excludes specific network IDs.' ),
'type' => 'array',
'items' => array(
'type' => 'integer',
),
);

/**
* Filter collection parameters for the sites controller.
*
Expand Down
Loading