Make WordPress Core

Changeset 41225


Ignore:
Timestamp:
08/03/2017 09:40:02 PM (7 years ago)
Author:
flixos90
Message:

Multisite: Introduce a can_add_user_to_blog filter to prevent adding a user to a site.

Under certain circumstances, it can be necessary that a user should not be added to a site, beyond the restrictions that WordPress core applies. With the new can_add_user_to_blog filter, plugin developers can run custom checks and return an error in case of a failure, that will prevent the user from being added.

The user-facing parts and the REST API route that interact with add_user_to_blog() have been adjusted accordingly to provide appropriate error feedback when a user could not be added to a site. Furthermore, two existing error feedback messages in the site admin's "New User" screen have been adjusted to properly show inside an error notice instead of a success notice.

Props jmdodd.
Fixes #41101.

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/network/site-users.php

    r41065 r41225  
    6767                    $update = 'err_new_dup';
    6868                } else {
    69                     add_user_to_blog( $id, $user_id, $_POST['new_role'] );
    70                     $update = 'newuser';
    71                     /**
    72                       * Fires after a user has been created via the network site-users.php page.
    73                       *
    74                       * @since 4.4.0
    75                       *
    76                       * @param int $user_id ID of the newly created user.
    77                       */
    78                     do_action( 'network_site_users_created_user', $user_id );
     69                    $result = add_user_to_blog( $id, $user_id, $_POST['new_role'] );
     70
     71                    if ( is_wp_error( $result ) ) {
     72                        $update = 'err_add_fail';
     73                    } else {
     74                        $update = 'newuser';
     75                        /**
     76                          * Fires after a user has been created via the network site-users.php page.
     77                          *
     78                          * @since 4.4.0
     79                          *
     80                          * @param int $user_id ID of the newly created user.
     81                          */
     82                        do_action( 'network_site_users_created_user', $user_id );
     83                    }
    7984                }
    8085            }
     
    8893                $user = get_user_by( 'login', $newuser );
    8994                if ( $user && $user->exists() ) {
    90                     if ( ! is_user_member_of_blog( $user->ID, $id ) )
    91                         add_user_to_blog( $id, $user->ID, $_POST['new_role'] );
    92                     else
     95                    if ( ! is_user_member_of_blog( $user->ID, $id ) ) {
     96                        $result = add_user_to_blog( $id, $user->ID, $_POST['new_role'] );
     97
     98                        if ( is_wp_error( $result ) ) {
     99                            $update = 'err_add_fail';
     100                        }
     101                    } else {
    93102                        $update = 'err_add_member';
     103                    }
    94104                } else {
    95105                    $update = 'err_add_notfound';
     
    224234        echo '<div id="message" class="error notice is-dismissible"><p>' . __( 'User is already a member of this site.' ) . '</p></div>';
    225235        break;
     236    case 'err_add_fail':
     237        echo '<div id="message" class="error notice is-dismissible"><p>' . __( 'User could not be added to this site.' ) . '</p></div>';
     238        break;
    226239    case 'err_add_notfound':
    227240        echo '<div id="message" class="error notice is-dismissible"><p>' . __( 'Enter the username of an existing user.' ) . '</p></div>';
  • trunk/src/wp-admin/user-new.php

    r41122 r41225  
    6868    } else {
    6969        if ( isset( $_POST[ 'noconfirmation' ] ) && current_user_can( 'manage_network_users' ) ) {
    70             add_existing_user_to_blog( array( 'user_id' => $user_id, 'role' => $_REQUEST[ 'role' ] ) );
    71             $redirect = add_query_arg( array( 'update' => 'addnoconfirmation' , 'user_id' => $user_id ), 'user-new.php' );
     70            $result = add_existing_user_to_blog( array( 'user_id' => $user_id, 'role' => $_REQUEST[ 'role' ] ) );
     71
     72            if ( ! is_wp_error( $result ) ) {
     73                $redirect = add_query_arg( array( 'update' => 'addnoconfirmation', 'user_id' => $user_id ), 'user-new.php' );
     74            } else {
     75                $redirect = add_query_arg( array( 'update' => 'could_not_add' ), 'user-new.php' );
     76            }
    7277        } else {
    7378            $newuser_key = substr( md5( $user_id ), 0, 5 );
     
    158163                if ( is_wp_error( $new_user ) ) {
    159164                    $redirect = add_query_arg( array( 'update' => 'addnoconfirmation' ), 'user-new.php' );
     165                } elseif ( ! is_user_member_of_blog( $new_user['user_id'] ) ) {
     166                    $redirect = add_query_arg( array( 'update' => 'created_could_not_add' ), 'user-new.php' );
    160167                } else {
    161168                    $redirect = add_query_arg( array( 'update' => 'addnoconfirmation', 'user_id' => $new_user['user_id'] ), 'user-new.php' );
     
    262269                $messages[] = __('That user is already a member of this site.');
    263270                break;
     271            case "could_not_add":
     272                $add_user_errors = new WP_Error( 'could_not_add', __( 'That user could not be added to this site.' ) );
     273                break;
     274            case "created_could_not_add":
     275                $add_user_errors = new WP_Error( 'created_could_not_add', __( 'User has been created, but could not be added to this site.' ) );
     276                break;
    264277            case "does_not_exist":
    265                 $messages[] = __('The requested user does not exist.');
     278                $add_user_errors = new WP_Error( 'does_not_exist', __( 'The requested user does not exist.' ) );
    266279                break;
    267280            case "enter_email":
    268                 $messages[] = __('Please enter a valid email address.');
     281                $add_user_errors = new WP_Error( 'enter_email', __( 'Please enter a valid email address.' ) );
    269282                break;
    270283        }
  • trunk/src/wp-includes/ms-functions.php

    r41200 r41225  
    6060    } else {
    6161        //TODO Review this call to add_user_to_blog too - to get here the user must have a role on this blog?
    62         add_user_to_blog( $first_blog->userblog_id, $user_id, 'subscriber' );
    63         update_user_meta( $user_id, 'primary_blog', $first_blog->userblog_id );
    64         $primary = $first_blog;
     62        $result = add_user_to_blog( $first_blog->userblog_id, $user_id, 'subscriber' );
     63
     64        if ( ! is_wp_error( $result ) ) {
     65            update_user_meta( $user_id, 'primary_blog', $first_blog->userblog_id );
     66            $primary = $first_blog;
     67        }
    6568    }
    6669
     
    159162        restore_current_blog();
    160163        return new WP_Error( 'user_does_not_exist', __( 'The requested user does not exist.' ) );
     164    }
     165
     166    /**
     167     * Filters whether a user should be added to a site.
     168     *
     169     * @since 4.9.0
     170     *
     171     * @param bool|WP_Error $retval  True if the user should be added to the site, false
     172     *                               or error object otherwise.
     173     * @param int           $user_id User ID.
     174     * @param string        $role    User role.
     175     * @param int           $blog_id Site ID.
     176     */
     177    $can_add_user = apply_filters( 'can_add_user_to_blog', true, $user_id, $role, $blog_id );
     178
     179    if ( true !== $can_add_user ) {
     180        restore_current_blog();
     181
     182        if ( is_wp_error( $can_add_user ) ) {
     183            return $can_add_user;
     184        }
     185
     186        return new WP_Error( 'user_cannot_be_added', __( 'User cannot be added to this site.' ) );
    161187    }
    162188
     
    20822108        $blog_id = get_current_blog_id();
    20832109        $result = add_user_to_blog( $blog_id, $details[ 'user_id' ], $details[ 'role' ] );
    2084         /**
    2085          * Fires immediately after an existing user is added to a site.
    2086          *
    2087          * @since MU (3.0.0)
    2088          *
    2089          * @param int   $user_id User ID.
    2090          * @param mixed $result  True on success or a WP_Error object if the user doesn't exist.
    2091          */
    2092         do_action( 'added_existing_user', $details['user_id'], $result );
     2110
     2111        if ( ! is_wp_error( $result ) ) {
     2112            /**
     2113             * Fires immediately after an existing user is added to a site.
     2114             *
     2115             * @since MU (3.0.0)
     2116             *
     2117             * @param int   $user_id User ID.
     2118             * @param mixed $result  True on success or a WP_Error object if the user doesn't exist.
     2119             */
     2120            do_action( 'added_existing_user', $details['user_id'], $result );
     2121        }
     2122
    20932123        return $result;
    20942124    }
     
    21122142        $blog_id = $meta[ 'add_to_blog' ];
    21132143        $role = $meta[ 'new_role' ];
    2114         remove_user_from_blog($user_id, get_network()->site_id); // remove user from main blog.
    2115         add_user_to_blog( $blog_id, $user_id, $role );
    2116         update_user_meta( $user_id, 'primary_blog', $blog_id );
     2144        remove_user_from_blog( $user_id, get_network()->site_id ); // remove user from main blog.
     2145
     2146        $result = add_user_to_blog( $blog_id, $user_id, $role );
     2147
     2148        if ( ! is_wp_error( $result ) ) {
     2149            update_user_meta( $user_id, 'primary_blog', $blog_id );
     2150        }
    21172151    }
    21182152}
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php

    r41162 r41225  
    493493            }
    494494
    495             add_user_to_blog( get_site()->id, $user_id, '' );
     495            $result= add_user_to_blog( get_site()->id, $user_id, '' );
     496            if ( is_wp_error( $result ) ) {
     497                return $result;
     498            }
    496499        } else {
    497500            $user_id = wp_insert_user( wp_slash( (array) $user ) );
  • trunk/tests/phpunit/tests/rest-api/rest-users-controller.php

    r41011 r41225  
    10191019
    10201020        $this->assertFalse( $user_is_member );
     1021    }
     1022
     1023    /**
     1024     * @ticket 41101
     1025     * @group ms-required
     1026     */
     1027    public function test_create_new_network_user_with_add_user_to_blog_failure() {
     1028        $this->allow_user_to_manage_multisite();
     1029
     1030        $params = array(
     1031            'username' => 'testuser123',
     1032            'password' => 'testpassword',
     1033            'email'    => 'test@example.com',
     1034            'name'     => 'Test User 123',
     1035            'roles'    => array( 'editor' ),
     1036        );
     1037
     1038        add_filter( 'can_add_user_to_blog', '__return_false' );
     1039
     1040        $request = new WP_REST_Request( 'POST', '/wp/v2/users' );
     1041        $request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
     1042        $request->set_body_params( $params );
     1043        $response = $this->server->dispatch( $request );
     1044        $this->assertErrorResponse( 'user_cannot_be_added', $response );
    10211045    }
    10221046
  • trunk/tests/phpunit/tests/user/multisite.php

    r41171 r41225  
    396396
    397397        $this->assertWPError( $result );
     398    }
     399
     400    /**
     401     * @ticket 41101
     402     */
     403    public function test_should_fail_can_add_user_to_blog_filter() {
     404        $site_id = self::factory()->blog->create();
     405        $user_id = self::factory()->user->create();
     406
     407        add_filter( 'can_add_user_to_blog', '__return_false' );
     408        $result = add_user_to_blog( $site_id, $user_id, 'subscriber' );
     409
     410        $this->assertWPError( $result );
     411    }
     412
     413    /**
     414     * @ticket 41101
     415     */
     416    public function test_should_succeed_can_add_user_to_blog_filter() {
     417        $site_id = self::factory()->blog->create();
     418        $user_id = self::factory()->user->create();
     419
     420        add_filter( 'can_add_user_to_blog', '__return_true' );
     421        $result = add_user_to_blog( $site_id, $user_id, 'subscriber' );
     422
     423        $this->assertTrue( $result );
    398424    }
    399425
Note: See TracChangeset for help on using the changeset viewer.