Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
19 changes: 17 additions & 2 deletions src/wp-includes/user.php
Original file line number Diff line number Diff line change
Expand Up @@ -1152,6 +1152,7 @@ function get_blogs_of_user( $user_id, $all = false ) {
* Finds out whether a user is a member of a given blog.
*
* @since MU (3.0.0)
* @since 7.1.0 Introduced the `is_user_member_of_blog` filter.
*
* @global wpdb $wpdb WordPress database abstraction object.
*
Expand Down Expand Up @@ -1201,9 +1202,23 @@ function is_user_member_of_blog( $user_id = 0, $blog_id = 0 ) {
} else {
$capabilities_key = $wpdb->base_prefix . $blog_id . '_capabilities';
}
$has_cap = get_user_meta( $user_id, $capabilities_key, true );
$has_cap = get_user_meta( $user_id, $capabilities_key, true );
$is_member = is_array( $has_cap );

return is_array( $has_cap );
/**
* Filters whether a user is a member of a given blog.
*
* This filter only runs when the user and blog have both been resolved
* to valid records on a multisite install; it is not invoked for logged-out
* requests, unknown users, or archived/spammed/deleted sites.
*
* @since 7.1.0
*
* @param bool $is_member Whether the user is a member of the blog.
* @param int $user_id The user ID being checked.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we needs to add Defaults to the current user. for better doc for param?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is that something we do on other filter doc blocks? When something is passed explicitly to a filter, it feels like defaults shouldn't be mentioned..

* @param int $blog_id The blog ID being checked.
*/
return (bool) apply_filters( 'is_user_member_of_blog', $is_member, $user_id, $blog_id );
}

/**
Expand Down
67 changes: 67 additions & 0 deletions tests/phpunit/tests/user/multisite.php
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,73 @@ public function test_is_user_member_of_blog() {
wp_set_current_user( $old_current );
}

/**
* Ensures the `is_user_member_of_blog` filter can override the return value
* and receives the resolved user ID and blog ID.
*
* @ticket 65096
*
* @covers ::is_user_member_of_blog
*/
public function test_is_user_member_of_blog_filter() {
$user_id = self::factory()->user->create();
$blog_id = self::factory()->blog->create();

// Sanity check: the user is not a member of the blog by default.
$this->assertFalse( is_user_member_of_blog( $user_id, $blog_id ) );

$filter_args = array();
$filter = function ( $is_member, $filtered_user_id, $filtered_blog_id ) use ( &$filter_args ) {
$filter_args[] = array( $is_member, $filtered_user_id, $filtered_blog_id );
return true;
};

add_filter( 'is_user_member_of_blog', $filter, 10, 3 );
$result = is_user_member_of_blog( $user_id, $blog_id );
remove_filter( 'is_user_member_of_blog', $filter, 10 );

$this->assertTrue( $result, 'Filter should be able to force a truthy return value.' );
$this->assertCount( 1, $filter_args, 'Filter should run exactly once per call on a valid multisite blog.' );
$this->assertSame( array( false, $user_id, $blog_id ), $filter_args[0], 'Filter should receive the computed membership, user ID, and blog ID.' );
}

/**
* Ensures the `is_user_member_of_blog` filter is not invoked for requests
* that short-circuit before the membership is computed.
*
* @ticket 65096
*
* @covers ::is_user_member_of_blog
*/
public function test_is_user_member_of_blog_filter_not_called_for_invalid_input() {
$filter_calls = 0;
$filter = function ( $is_member ) use ( &$filter_calls ) {
++$filter_calls;
return $is_member;
};

add_filter( 'is_user_member_of_blog', $filter );

// No current user, and no user ID provided.
$old_current = get_current_user_id();
wp_set_current_user( 0 );
$this->assertFalse( is_user_member_of_blog() );

// Unknown user ID.
$this->assertFalse( is_user_member_of_blog( PHP_INT_MAX ) );

// Known user, but an archived/deleted/spam site short-circuits.
$user_id = self::factory()->user->create();
$blog_id = self::factory()->blog->create();
update_blog_details( $blog_id, array( 'archived' => 1 ) );
$this->assertFalse( is_user_member_of_blog( $user_id, $blog_id ) );

wp_set_current_user( $old_current );
remove_filter( 'is_user_member_of_blog', $filter );

$this->assertSame( 0, $filter_calls, 'Filter should not run when the function short-circuits before computing membership.' );
}

/**
* @ticket 23192
*/
Expand Down
Loading