Skip to content
48 changes: 43 additions & 5 deletions includes/Core/Authentication/Has_Multiple_Admins.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class Has_Multiple_Admins {
/**
* The option_name for this transient.
*/
const OPTION = 'googlesitekit_has_multiple_admins';
const OPTION = 'googlesitekit_number_of_administrators';

/**
* Transients instance.
Expand Down Expand Up @@ -70,8 +70,44 @@ public function register() {
* @return boolean TRUE if the site kit has multiple admins, otherwise FALSE.
*/
public function get() {
$admins_count = $this->transients->get( self::OPTION );
if ( false === $admins_count ) {
$number_of_admins = $this->transients->get( self::OPTION );

// If we have a cached number of admins, use it rather than doing
// database queries to check on the number of admins.
if ( ! empty( $number_of_admins ) ) {
return $number_of_admins > 1;
}

if ( is_multisite() ) {
$super_admins = get_super_admins();
// If there are multiple super admins, we definitely have multiple admins.
if ( count( $super_admins ) > 1 ) {
$admins_count = count( $super_admins );
// There's no need to check local admins in this case.
} else {
// If there is 0 or 1 super admin, we need to check local admins.
// We exclude the super admin from the local check to avoid double counting
// if they are also added as a local administrator.
$exclude_users = array();
if ( ! empty( $super_admins ) ) {
$super_admin = get_user_by( 'login', $super_admins[0] );
if ( $super_admin ) {
$exclude_users[] = $super_admin->ID;
}
}

$user_query_args = array(
'number' => 1,
'role__in' => array( 'Administrator' ),
'count_total' => true,
'exclude' => $exclude_users, // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude -- We're excluding existing super admins from the result and caching the results of this slow query. This is a legitimate use case of the 'exclude' param.
);

$user_query = new WP_User_Query( $user_query_args );
// Add 1 if there is a super admin, plus any other local admins found.
$admins_count = ( ! empty( $super_admins ) ? 1 : 0 ) + $user_query->get_total();
}
} else {
$user_query_args = array(
'number' => 1,
'role__in' => array( 'Administrator' ),
Expand All @@ -80,10 +116,12 @@ public function get() {

$user_query = new WP_User_Query( $user_query_args );
$admins_count = $user_query->get_total();

$this->transients->set( self::OPTION, $admins_count, WEEK_IN_SECONDS );
}

// Set the number of admins transient for 1 week.
$this->transients->set( self::OPTION, $admins_count, WEEK_IN_SECONDS );

// Return whether we have multiple admins.
return $admins_count > 1;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,4 +147,51 @@ public function test_get__on_add_remove_user_role() {
$this->assertTrue( $has_multiple_admins->get(), 'Should return true when there are multiple admin users' );
$this->assertEquals( 3, $this->transients->get( Has_Multiple_Admins::OPTION ), 'Transient should be updated to three admins' );
}

public function test_get__multisite_super_admins() {
if ( ! is_multisite() ) {
$this->markTestSkipped( 'This test only runs on multisite.' );
}

// Create a super admin user.
$super_admin_id = $this->factory()->user->create( array( 'role' => 'editor' ) );
grant_super_admin( $super_admin_id );
$regular_admin_id = $this->factory()->user->create( array( 'role' => 'administrator' ) );

$has_multiple_admins = new Has_Multiple_Admins( $this->transients );
$has_multiple_admins->register();

// Should return TRUE since we have a super-admin and regular admin.
$this->assertTrue( $has_multiple_admins->get(), 'Should return true when there is one admin and one super-admin' );

// Verify we have two admin users; one normal admin and another super
// admin.
$this->assertEquals( 2, $this->transients->get( Has_Multiple_Admins::OPTION ), 'Transient should reflect two admins' );
}

public function test_get__multisite_many_super_admins() {
if ( ! is_multisite() ) {
$this->markTestSkipped( 'This test only runs on multisite.' );
}

// Create several super admin users.
$super_admin_id = $this->factory()->user->create( array( 'role' => 'editor' ) );
grant_super_admin( $super_admin_id );
$regular_admin_id = $this->factory()->user->create( array( 'role' => 'administrator' ) );
// Create a second super-admin; this causes a different code path to
// be taken in `Has_Multiple_Admins::get()`.
$second_super_admin_id = $this->factory()->user->create( array( 'role' => 'editor' ) );
grant_super_admin( $second_super_admin_id );

$has_multiple_admins = new Has_Multiple_Admins( $this->transients );
$has_multiple_admins->register();

// Check that we have multiple admins.
$this->assertTrue( $has_multiple_admins->get(), 'Should return true when there are two super-admin users' );

// Verify the transient is updated and reflects the admin count,
// including super admins.
// (One regular admin + two super admins = three admins.)
$this->assertEquals( 3, $this->transients->get( Has_Multiple_Admins::OPTION ), 'Transient should be updated to three admins' );
}
}
Loading