fetcher = new UserFetcher(); } /** * Lists users. * * Display WordPress users based on all arguments supported by * [WP_User_Query()](https://developer.wordpress.org/reference/classes/wp_user_query/prepare_query/). * * ## OPTIONS * * [--role=] * : Only display users with a certain role. * * [--=] * : Control output by one or more arguments of WP_User_Query(). * * [--network] * : List all users in the network for multisite. * * [--field=] * : Prints the value of a single field for each user. * * [--fields=] * : Limit the output to specific object fields. * * [--format=] * : Render output in a particular format. * --- * default: table * options: * - table * - csv * - ids * - json * - count * - yaml * --- * * ## AVAILABLE FIELDS * * These fields will be displayed by default for each user: * * * ID * * user_login * * display_name * * user_email * * user_registered * * roles * * These fields are optionally available: * * * user_pass * * user_nicename * * user_url * * user_activation_key * * user_status * * spam * * deleted * * caps * * cap_key * * allcaps * * filter * * url * * ## EXAMPLES * * # List user IDs * $ wp user list --field=ID * 1 * * # List users with administrator role * $ wp user list --role=administrator --format=csv * ID,user_login,display_name,user_email,user_registered,roles * 1,supervisor,supervisor,supervisor@gmail.com,"2016-06-03 04:37:00",administrator * * # List users with only given fields * $ wp user list --fields=display_name,user_email --format=json * [{"display_name":"supervisor","user_email":"supervisor@gmail.com"}] * * # List users ordered by the 'last_activity' meta value. * $ wp user list --meta_key=last_activity --orderby=meta_value_num * * @subcommand list */ public function list_( $args, $assoc_args ) { if ( Utils\get_flag_value( $assoc_args, 'network' ) ) { if ( ! is_multisite() ) { WP_CLI::error( 'This is not a multisite installation.' ); } $assoc_args['blog_id'] = 0; if ( isset( $assoc_args['fields'] ) ) { $fields = explode( ',', $assoc_args['fields'] ); $assoc_args['fields'] = array_diff( $fields, [ 'roles' ] ); } else { $assoc_args['fields'] = array_diff( $this->obj_fields, [ 'roles' ] ); } } $formatter = $this->get_formatter( $assoc_args ); if ( in_array( $formatter->format, [ 'ids', 'count' ], true ) ) { $assoc_args['fields'] = 'ids'; } else { $assoc_args['fields'] = 'all_with_meta'; } $assoc_args['count_total'] = false; $assoc_args = self::process_csv_arguments_to_arrays( $assoc_args ); if ( ! empty( $assoc_args['role'] ) && 'none' === $assoc_args['role'] ) { $norole_user_ids = wp_get_users_with_no_role(); if ( ! empty( $norole_user_ids ) ) { $assoc_args['include'] = $norole_user_ids; unset( $assoc_args['role'] ); } } $users = get_users( $assoc_args ); if ( 'ids' === $formatter->format ) { echo implode( ' ', $users ); } elseif ( 'count' === $formatter->format ) { $formatter->display_items( $users ); } else { $iterator = Utils\iterator_map( $users, function ( $user ) { if ( ! is_object( $user ) ) { return $user; } $user->roles = implode( ',', $user->roles ); $user->url = get_author_posts_url( $user->ID, $user->user_nicename ); return $user; } ); $formatter->display_items( $iterator ); } } /** * Gets details about a user. * * ## OPTIONS * * * : User ID, user email, or user login. * * [--field=] * : Instead of returning the whole user, returns the value of a single field. * * [--fields=] * : Get a specific subset of the user's fields. * * [--format=] * : Render output in a particular format. * --- * default: table * options: * - table * - csv * - json * - yaml * --- * * ## EXAMPLES * * # Get user * $ wp user get 12 --field=login * supervisor * * # Get user and export to JSON file * $ wp user get bob --format=json > bob.json */ public function get( $args, $assoc_args ) { $user = $this->fetcher->get_check( $args[0] ); $user_data = $user->to_array(); $user_data['roles'] = implode( ', ', $user->roles ); $formatter = $this->get_formatter( $assoc_args ); $formatter->display_item( $user_data ); } /** * Deletes one or more users from the current site. * * On multisite, `wp user delete` only removes the user from the current * site. Include `--network` to also remove the user from the database, but * make sure to reassign their posts prior to deleting the user. * * ## OPTIONS * * ... * : The user login, user email, or user ID of the user(s) to delete. * * [--network] * : On multisite, delete the user from the entire network. * * [--reassign=] * : User ID to reassign the posts to. * * [--yes] * : Answer yes to any confirmation prompts. * * ## EXAMPLES * * # Delete user 123 and reassign posts to user 567 * $ wp user delete 123 --reassign=567 * Success: Removed user 123 from http://example.com. * * # Delete all contributors and reassign their posts to user 2 * $ wp user delete $(wp user list --role=contributor --field=ID) --reassign=2 * Success: Removed user 813 from http://example.com. * Success: Removed user 578 from http://example.com. * * # Delete all contributors in batches of 100 (avoid error: argument list too long: wp) * $ wp user delete $(wp user list --role=contributor --field=ID | head -n 100) */ public function delete( $args, $assoc_args ) { $network = Utils\get_flag_value( $assoc_args, 'network' ) && is_multisite(); $reassign = Utils\get_flag_value( $assoc_args, 'reassign' ); if ( $network && $reassign ) { WP_CLI::error( 'Reassigning content to a different user is not supported on multisite.' ); } $is_reassign_valid = ( $reassign && false === get_userdata( $reassign ) ) ? false : true; if ( ! $reassign ) { WP_CLI::confirm( '--reassign parameter not passed. All associated posts will be deleted. Proceed?', $assoc_args ); } elseif ( ! $is_reassign_valid ) { WP_CLI::confirm( '--reassign parameter is invalid. All associated posts will be deleted. Proceed?', $assoc_args ); } $users = $this->fetcher->get_many( $args ); parent::_delete( $users, $assoc_args, function ( $user ) use ( $network, $reassign ) { $user_id = $user->ID; if ( $network ) { $result = wpmu_delete_user( $user_id ); $message = "Deleted user {$user_id}."; } elseif ( is_multisite() && empty( $user->roles ) ) { $message = "No roles found for user {$user_id} on " . home_url() . ', no users deleted.'; return [ 'error', $message ]; } else { $result = wp_delete_user( $user_id, $reassign ); $message = "Removed user {$user_id} from " . home_url() . '.'; } if ( ! $result ) { $message = "Failed deleting user {$user_id}."; if ( is_multisite() && is_super_admin( $user_id ) ) { $message .= ' The user is a super admin.'; } return [ 'error', $message ]; } return [ 'success', $message ]; } ); } /** * Creates a new user. * * ## OPTIONS * * * : The login of the user to create. * * * : The email address of the user to create. * * [--role=] * : The role of the user to create. Default: default role. Possible values * include 'administrator', 'editor', 'author', 'contributor', 'subscriber'. * * [--user_pass=] * : The user password. Default: randomly generated. * * [--user_registered=] * : The date the user registered. Default: current date. * * [--display_name=] * : The display name. * * [--user_nicename=] * : A string that contains a URL-friendly name for the user. The default is the user's username. * * [--user_url=] * : A string containing the user's URL for the user's web site. * * [--nickname=] * : The user's nickname, defaults to the user's username. * * [--first_name=] * : The user's first name. * * [--last_name=] * : The user's last name. * * [--description=] * : A string containing content about the user. * * [--rich_editing=] * : A string for whether to enable the rich editor or not. False if not empty. * * [--send-email] * : Send an email to the user with their new account details. * * [--porcelain] * : Output just the new user id. * * ## EXAMPLES * * # Create user * $ wp user create bob bob@example.com --role=author * Success: Created user 3. * Password: k9**&I4vNH(& * * # Create user without showing password upon success * $ wp user create ann ann@example.com --porcelain * 4 */ public function create( $args, $assoc_args ) { $user = new stdClass(); list( $user->user_login, $user->user_email ) = $args; $assoc_args = wp_slash( $assoc_args ); if ( username_exists( $user->user_login ) ) { WP_CLI::error( "The '{$user->user_login}' username is already registered." ); } if ( ! is_email( $user->user_email ) ) { WP_CLI::error( "The '{$user->user_email}' email address is invalid." ); } $user->user_registered = Utils\get_flag_value( $assoc_args, 'user_registered', current_time( 'mysql', true ) ); $user->display_name = Utils\get_flag_value( $assoc_args, 'display_name', false ); $user->nickname = Utils\get_flag_value( $assoc_args, 'nickname', false ); $user->first_name = Utils\get_flag_value( $assoc_args, 'first_name', false ); $user->last_name = Utils\get_flag_value( $assoc_args, 'last_name', false ); $user->description = Utils\get_flag_value( $assoc_args, 'description', false ); $user->user_url = Utils\get_flag_value( $assoc_args, 'user_url', false ); if ( isset( $assoc_args['user_pass'] ) ) { $user->user_pass = $assoc_args['user_pass']; } else { $user->user_pass = wp_generate_password( 24 ); $generated_pass = true; } $user->role = Utils\get_flag_value( $assoc_args, 'role', get_option( 'default_role' ) ); self::validate_role( $user->role ); if ( ! Utils\get_flag_value( $assoc_args, 'send-email' ) ) { add_filter( 'send_password_change_email', '__return_false' ); add_filter( 'send_email_change_email', '__return_false' ); } if ( is_multisite() ) { $result = wpmu_validate_user_signup( $user->user_login, $user->user_email ); if ( is_wp_error( $result['errors'] ) && ! empty( $result['errors']->errors ) ) { WP_CLI::error( $result['errors'] ); } $user_id = wpmu_create_user( $user->user_login, $user->user_pass, $user->user_email ); if ( ! $user_id ) { WP_CLI::error( 'Unknown error creating new user.' ); } $user->ID = $user_id; $user_id = wp_update_user( $user ); if ( is_wp_error( $user_id ) ) { WP_CLI::error( $user_id ); } } else { $user_id = wp_insert_user( $user ); } if ( ! $user_id || is_wp_error( $user_id ) ) { if ( ! $user_id ) { $user_id = 'Unknown error creating new user.'; } WP_CLI::error( $user_id ); } elseif ( false === $user->role ) { delete_user_option( $user_id, 'capabilities' ); delete_user_option( $user_id, 'user_level' ); } if ( Utils\get_flag_value( $assoc_args, 'send-email' ) ) { self::wp_new_user_notification( $user_id, $user->user_pass ); } if ( Utils\get_flag_value( $assoc_args, 'porcelain' ) ) { WP_CLI::line( $user_id ); } else { WP_CLI::success( "Created user {$user_id}." ); if ( isset( $generated_pass ) ) { WP_CLI::line( "Password: {$user->user_pass}" ); } } } /** * Updates an existing user. * * ## OPTIONS * * ... * : The user login, user email or user ID of the user(s) to update. * * [--user_pass=] * : A string that contains the plain text password for the user. * * [--user_nicename=] * : A string that contains a URL-friendly name for the user. The default is the user's username. * * [--user_url=] * : A string containing the user's URL for the user's web site. * * [--user_email=] * : A string containing the user's email address. * * [--display_name=] * : A string that will be shown on the site. Defaults to user's username. * * [--nickname=] * : The user's nickname, defaults to the user's username. * * [--first_name=] * : The user's first name. * * [--last_name=] * : The user's last name. * * [--description=] * : A string containing content about the user. * * [--rich_editing=] * : A string for whether to enable the rich editor or not. False if not empty. * * [--user_registered=] * : The date the user registered. * * [--role=] * : A string used to set the user's role. * * --= * : One or more fields to update. For accepted fields, see wp_update_user(). * * [--skip-email] * : Don't send an email notification to the user. * * ## EXAMPLES * * # Update user * $ wp user update 123 --display_name=Mary --user_pass=marypass * Success: Updated user 123. */ public function update( $args, $assoc_args ) { if ( isset( $assoc_args['user_login'] ) ) { WP_CLI::warning( "User logins can't be changed." ); unset( $assoc_args['user_login'] ); } if ( isset( $assoc_args['role'] ) ) { self::validate_role( $assoc_args['role'], true ); } $user_ids = []; foreach ( $this->fetcher->get_many( $args ) as $user ) { $user_ids[] = $user->ID; } $skip_email = Utils\get_flag_value( $assoc_args, 'skip-email' ); if ( $skip_email ) { add_filter( 'send_email_change_email', '__return_false' ); add_filter( 'send_password_change_email', '__return_false' ); } $assoc_args = wp_slash( $assoc_args ); parent::_update( $user_ids, $assoc_args, 'wp_update_user' ); if ( $skip_email ) { remove_filter( 'send_email_change_email', '__return_false' ); remove_filter( 'send_password_change_email', '__return_false' ); } } /** * Generates some users. * * Creates a specified number of new users with dummy data. * * ## OPTIONS * * [--count=] * : How many users to generate? * --- * default: 100 * --- * * [--role=] * : The role of the generated users. Default: default role from WP * * [--format=] * : Render output in a particular format. * --- * default: progress * options: * - progress * - ids * --- * * ## EXAMPLES * * # Add meta to every generated users. * $ wp user generate --format=ids --count=3 | xargs -d ' ' -I % wp user meta add % foo bar * Success: Added custom field. * Success: Added custom field. * Success: Added custom field. */ public function generate( $args, $assoc_args ) { global $blog_id; $defaults = [ 'count' => 100, 'role' => get_option( 'default_role' ), ]; $assoc_args = array_merge( $defaults, $assoc_args ); $role = $assoc_args['role']; if ( ! empty( $role ) ) { self::validate_role( $role ); } $user_count = count_users(); $total = $user_count['total_users']; $limit = $assoc_args['count'] + $total; $format = Utils\get_flag_value( $assoc_args, 'format', 'progress' ); $notify = false; if ( 'progress' === $format ) { $notify = Utils\make_progress_bar( 'Generating users', $assoc_args['count'] ); } for ( $index = $total; $index < $limit; $index++ ) { $login = "user_{$blog_id}_{$index}"; $name = "User {$index}"; $user_id = wp_insert_user( [ 'user_login' => $login, 'user_pass' => $login, 'nickname' => $name, 'display_name' => $name, 'role' => $role, ] ); if ( false === $role ) { delete_user_option( $user_id, 'capabilities' ); delete_user_option( $user_id, 'user_level' ); } if ( 'progress' === $format ) { $notify->tick(); } elseif ( 'ids' === $format ) { echo $user_id; if ( $index < $limit - 1 ) { echo ' '; } } } if ( 'progress' === $format ) { $notify->finish(); } } /** * Verifies whether a user exists. * * Displays a success message if the user does exist. * * ## OPTIONS * * * : The ID of the user to check. * * ## EXAMPLES * * # The user exists. * $ wp user exists 1337 * Success: User with ID 1337 exists. * $ echo $? * 0 * * # The user does not exist. * $ wp user exists 10000 * $ echo $? * 1 */ public function exists( $args ) { if ( $this->fetcher->get( $args[0] ) ) { WP_CLI::success( "User with ID {$args[0]} exists." ); } else { WP_CLI::halt( 1 ); } } /** * Sets the user role. * * ## OPTIONS * * * : User ID, user email, or user login. * * [] * : Make the user have the specified role. If not passed, the default role is * used. * * ## EXAMPLES * * $ wp user set-role 12 author * Success: Added johndoe (12) to http://example.com as author. * * @subcommand set-role */ public function set_role( $args, $assoc_args ) { $user = $this->fetcher->get_check( $args[0] ); $role = Utils\get_flag_value( $args, 1, get_option( 'default_role' ) ); self::validate_role( $role ); // Multisite if ( function_exists( 'add_user_to_blog' ) ) { add_user_to_blog( get_current_blog_id(), $user->ID, $role ); } else { $user->set_role( $role ); } WP_CLI::success( "Added {$user->user_login} ({$user->ID}) to " . site_url() . " as {$role}." ); } /** * Adds a role for a user. * * ## OPTIONS * * * : User ID, user email, or user login. * * [...] * : Add the specified role(s) to the user. * * ## EXAMPLES * * $ wp user add-role 12 author * Success: Added 'author' role for johndoe (12). * * $ wp user add-role 12 author editor * Success: Added 'author', 'editor' roles for johndoe (12). * * @subcommand add-role */ public function add_role( $args, $assoc_args ) { $user = $this->fetcher->get_check( $args[0] ); $roles = $args; array_shift( $roles ); if ( empty( $roles ) ) { WP_CLI::error( 'Please specify at least one role to add.' ); } foreach ( $roles as $role ) { self::validate_role( $role ); } foreach ( $roles as $role ) { $user->add_role( $role ); } $message = implode( "', '", $roles ); $label = count( $roles ) > 1 ? 'roles' : 'role'; WP_CLI::success( "Added '{$message}' {$label} for {$user->user_login} ({$user->ID})." ); } /** * Removes a user's role. * * ## OPTIONS * * * : User ID, user email, or user login. * * [...] * : Remove the specified role(s) from the user. * * ## EXAMPLES * * $ wp user remove-role 12 author * Success: Removed 'author' role for johndoe (12). * * $ wp user remove-role 12 author editor * Success: Removed 'author', 'editor' roles for johndoe (12). * * @subcommand remove-role */ public function remove_role( $args, $assoc_args ) { $user = $this->fetcher->get_check( $args[0] ); if ( isset( $args[1] ) ) { $roles = $args; array_shift( $roles ); foreach ( $roles as $role ) { self::validate_role( $role ); } foreach ( $roles as $role ) { $user->remove_role( $role ); } $message = implode( "', '", $roles ); $label = count( $roles ) > 1 ? 'roles' : 'role'; WP_CLI::success( "Removed '{$message}' {$label} from {$user->user_login} ({$user->ID})." ); } else { // Multisite if ( function_exists( 'remove_user_from_blog' ) ) { remove_user_from_blog( $user->ID, get_current_blog_id() ); } else { $user->remove_all_caps(); } WP_CLI::success( "Removed {$user->user_login} ({$user->ID}) from " . site_url() . '.' ); } } /** * Adds a capability to a user. * * ## OPTIONS * * * : User ID, user email, or user login. * * * : The capability to add. * * ## EXAMPLES * * # Add a capability for a user * $ wp user add-cap john create_premium_item * Success: Added 'create_premium_item' capability for john (16). * * # Add a capability for a user * $ wp user add-cap 15 edit_product * Success: Added 'edit_product' capability for johndoe (15). * * @subcommand add-cap */ public function add_cap( $args, $assoc_args ) { $user = $this->fetcher->get_check( $args[0] ); if ( $user ) { $cap = $args[1]; $user->add_cap( $cap ); WP_CLI::success( "Added '{$cap}' capability for {$user->user_login} ({$user->ID})." ); } } /** * Removes a user's capability. * * ## OPTIONS * * * : User ID, user email, or user login. * * * : The capability to be removed. * * ## EXAMPLES * * $ wp user remove-cap 11 publish_newsletters * Success: Removed 'publish_newsletters' cap for supervisor (11). * * $ wp user remove-cap 11 publish_posts * Error: The 'publish_posts' cap for supervisor (11) is inherited from a role. * * $ wp user remove-cap 11 nonexistent_cap * Error: No such 'nonexistent_cap' cap for supervisor (11). * * @subcommand remove-cap */ public function remove_cap( $args, $assoc_args ) { $user = $this->fetcher->get_check( $args[0] ); if ( $user ) { $cap = $args[1]; if ( ! isset( $user->caps[ $cap ] ) ) { if ( isset( $user->allcaps[ $cap ] ) ) { WP_CLI::error( "The '{$cap}' cap for {$user->user_login} ({$user->ID}) is inherited from a role." ); } WP_CLI::error( "No such '{$cap}' cap for {$user->user_login} ({$user->ID})." ); } $user->remove_cap( $cap ); WP_CLI::success( "Removed '{$cap}' cap for {$user->user_login} ({$user->ID})." ); } } /** * Lists all capabilities for a user. * * ## OPTIONS * * * : User ID, user email, or login. * * [--format=] * : Render output in a particular format. * --- * default: list * options: * - list * - table * - csv * - json * - count * - yaml * --- * * [--origin=] * : Render output in a particular format. * --- * default: all * options: * - all * - user * - role * --- * * [--exclude-role-names] * : Exclude capabilities that match role names from output. * * ## EXAMPLES * * $ wp user list-caps 21 * edit_product * create_premium_item * * @subcommand list-caps */ public function list_caps( $args, $assoc_args ) { $user = $this->fetcher->get_check( $args[0] ); $exclude_role_names = Utils\get_flag_value( $assoc_args, 'exclude-role-names' ); $active_user_cap_list = []; $user_roles = $user->roles; switch ( $assoc_args['origin'] ) { case 'all': $user->get_role_caps(); $user_caps_list = $user->allcaps; foreach ( $user_caps_list as $capability => $active ) { if ( $exclude_role_names && in_array( $capability, $user_roles, true ) ) { continue; } if ( $active ) { $active_user_cap_list[] = $capability; } } break; case 'user': // Get the user's capabilities $user_capabilities = get_user_meta( $user->ID, 'wp_capabilities', true ); // Loop through each capability and only return the non-inherited ones foreach ( $user_capabilities as $capability => $active ) { if ( true === $active && ! in_array( $capability, $user_roles, true ) ) { $active_user_cap_list[] = $capability; } } break; case 'role': // Get the user's capabilities $user_capabilities = get_user_meta( $user->ID, 'wp_capabilities', true ); // Loop through each capability and only return the inherited ones (including the role name) foreach ( $user->get_role_caps() as $capability => $active ) { if ( true === $active && ! isset( $user_capabilities[ $capability ] ) ) { $active_user_cap_list[] = $capability; } if ( true === $active && ! $exclude_role_names && in_array( $capability, $user_roles, true ) ) { $active_user_cap_list[] = $capability; } } break; } if ( 'list' === $assoc_args['format'] ) { foreach ( $active_user_cap_list as $cap ) { WP_CLI::line( $cap ); } } else { $output_caps = []; foreach ( $active_user_cap_list as $cap ) { $output_cap = new stdClass(); $output_cap->name = $cap; $output_caps[] = $output_cap; } $formatter = new Formatter( $assoc_args, $this->cap_fields ); $formatter->display_items( $output_caps ); } } /** * Imports users from a CSV file. * * If the user already exists (matching the email address or login), then * the user is updated unless the `--skip-update` flag is used. * * ## OPTIONS * * * : The local or remote CSV file of users to import. If '-', then reads from STDIN. * * [--send-email] * : Send an email to new users with their account details. * * [--skip-update] * : Don't update users that already exist. * * ## EXAMPLES * * # Import users from local CSV file * $ wp user import-csv /path/to/users.csv * Success: bobjones created. * Success: newuser1 created. * Success: existinguser created. * * # Import users from remote CSV file * $ wp user import-csv http://example.com/users.csv * * Sample users.csv file: * * user_login,user_email,display_name,role * bobjones,bobjones@example.com,Bob Jones,contributor * newuser1,newuser1@example.com,New User,author * existinguser,existinguser@example.com,Existing User,administrator * * @subcommand import-csv */ public function import_csv( $args, $assoc_args ) { $blog_users = get_users(); $filename = $args[0]; if ( 0 === stripos( $filename, 'http://' ) || 0 === stripos( $filename, 'https://' ) ) { $response = wp_remote_head( $filename ); $response_code = (string) wp_remote_retrieve_response_code( $response ); if ( in_array( (int) $response_code[0], [ 4, 5 ], true ) ) { WP_CLI::error( "Couldn't access remote CSV file (HTTP {$response_code} response)." ); } } elseif ( '-' === $filename ) { if ( ! Utils\has_stdin() ) { WP_CLI::error( 'Unable to read content from STDIN.' ); } } elseif ( ! file_exists( $filename ) ) { WP_CLI::error( "Missing file: {$filename}" ); } // Don't send core's emails during the creation / update process add_filter( 'send_password_change_email', '__return_false' ); add_filter( 'send_email_change_email', '__return_false' ); if ( '-' === $filename ) { $file_object = new NoRewindIterator( new SplFileObject( 'php://stdin' ) ); $file_object->setFlags( SplFileObject::READ_CSV ); $csv_data = []; $indexes = []; foreach ( $file_object as $line ) { if ( empty( $line[0] ) ) { continue; } if ( empty( $indexes ) ) { $indexes = $line; continue; } foreach ( $indexes as $n => $key ) { $data[ $key ] = $line[ $n ]; } $csv_data[] = $data; } } else { $csv_data = new CsvIterator( $filename ); } foreach ( $csv_data as $new_user ) { $defaults = [ 'role' => get_option( 'default_role' ), 'user_pass' => wp_generate_password( 24 ), 'user_registered' => current_time( 'mysql', true ), 'display_name' => false, ]; $new_user = array_merge( $defaults, $new_user ); $secondary_roles = []; if ( ! empty( $new_user['roles'] ) ) { $roles = array_map( 'trim', explode( ',', $new_user['roles'] ) ); $invalid_role = false; foreach ( $roles as $role ) { if ( null === get_role( $role ) ) { WP_CLI::warning( "{$new_user['user_login']} has an invalid role." ); $invalid_role = true; break; } } if ( $invalid_role ) { continue; } $new_user['role'] = array_shift( $roles ); $secondary_roles = $roles; } elseif ( 'none' === $new_user['role'] ) { $new_user['role'] = false; } elseif ( null === get_role( $new_user['role'] ) ) { WP_CLI::warning( "{$new_user['user_login']} has an invalid role." ); continue; } // User already exists and we just need to add them to the site if they aren't already there $existing_user = get_user_by( 'email', $new_user['user_email'] ); if ( ! $existing_user ) { $existing_user = get_user_by( 'login', $new_user['user_login'] ); } if ( $existing_user && Utils\get_flag_value( $assoc_args, 'skip-update' ) ) { WP_CLI::log( "{$existing_user->user_login} exists and has been skipped." ); continue; } if ( $existing_user ) { $new_user['ID'] = $existing_user->ID; $user_id = wp_update_user( $new_user ); if ( ! in_array( $existing_user->user_login, wp_list_pluck( $blog_users, 'user_login' ), true ) && is_multisite() && $new_user['role'] ) { add_user_to_blog( get_current_blog_id(), $existing_user->ID, $new_user['role'] ); WP_CLI::log( "{$existing_user->user_login} added as {$new_user['role']}." ); } // Create the user } else { unset( $new_user['ID'] ); // Unset else it will just return the ID if ( is_multisite() ) { $result = wpmu_validate_user_signup( $new_user['user_login'], $new_user['user_email'] ); if ( is_wp_error( $result['errors'] ) && ! empty( $result['errors']->errors ) ) { WP_CLI::warning( $result['errors'] ); continue; } $user_id = wpmu_create_user( $new_user['user_login'], $new_user['user_pass'], $new_user['user_email'] ); if ( ! $user_id ) { WP_CLI::warning( 'Unknown error creating new user.' ); continue; } $new_user['ID'] = $user_id; $user_id = wp_update_user( $new_user ); if ( is_wp_error( $user_id ) ) { WP_CLI::warning( $user_id ); continue; } } else { $user_id = wp_insert_user( $new_user ); } if ( Utils\get_flag_value( $assoc_args, 'send-email' ) ) { self::wp_new_user_notification( $user_id, $new_user['user_pass'] ); } } if ( is_wp_error( $user_id ) ) { WP_CLI::warning( $user_id ); continue; } if ( false === $new_user['role'] ) { delete_user_option( $user_id, 'capabilities' ); delete_user_option( $user_id, 'user_level' ); } $user = get_user_by( 'id', $user_id ); foreach ( $secondary_roles as $secondary_role ) { $user->add_role( $secondary_role ); } if ( ! empty( $existing_user ) ) { WP_CLI::success( $new_user['user_login'] . ' updated.' ); } else { WP_CLI::success( $new_user['user_login'] . ' created.' ); } } } /** * Resets the password for one or more users. * * ## OPTIONS * * ... * : one or more user logins or IDs. * * [--skip-email] * : Don't send an email notification to the affected user(s). * * [--show-password] * : Show the new password(s). * * [--porcelain] * : Output only the new password(s). * * ## EXAMPLES * * # Reset the password for two users and send them the change email. * $ wp user reset-password admin editor * Reset password for admin. * Reset password for editor. * Success: Passwords reset for 2 users. * * # Reset and display the password. * $ wp user reset-password editor --show-password * Reset password for editor. * Password: N6hAau0fXZMN#rLCIirdEGOh * Success: Password reset for 1 user. * * # Reset the password for one user, displaying only the new password, and not sending the change email. * $ wp user reset-password admin --skip-email --porcelain * yV6BP*!d70wg * * # Reset password for all users. * $ wp user reset-password $(wp user list --format=ids) * Reset password for admin. * Reset password for editor. * Reset password for subscriber. * Success: Passwords reset for 3 users. * * # Reset password for all users with a particular role. * $ wp user reset-password $(wp user list --format=ids --role=administrator) * Reset password for admin. * Success: Password reset for 1 user. * * @subcommand reset-password */ public function reset_password( $args, $assoc_args ) { $porcelain = Utils\get_flag_value( $assoc_args, 'porcelain' ); $skip_email = Utils\get_flag_value( $assoc_args, 'skip-email' ); $show_new_pass = Utils\get_flag_value( $assoc_args, 'show-password' ); if ( $skip_email ) { add_filter( 'send_password_change_email', '__return_false' ); } $fetcher = new UserFetcher(); $users = $fetcher->get_many( $args ); foreach ( $users as $user ) { $new_pass = wp_generate_password( 24 ); wp_update_user( [ 'ID' => $user->ID, 'user_pass' => $new_pass, ] ); if ( $porcelain ) { WP_CLI::line( "$new_pass" ); } else { WP_CLI::log( "Reset password for {$user->user_login}." ); if ( $show_new_pass ) { WP_CLI::line( "Password: $new_pass" ); } } } $reset_user_count = count( $users ); if ( ! $porcelain ) { if ( 1 === $reset_user_count ) { WP_CLI::success( "Password reset for {$reset_user_count} user." ); } elseif ( $reset_user_count > 1 ) { WP_CLI::success( "Passwords reset for {$reset_user_count} users." ); } else { WP_CLI::error( 'No user found to reset password.' ); } } } /** * Checks whether the role is valid * * @param $role string * @param $warn_user_only bool */ private static function validate_role( $role, $warn_user_only = false ) { if ( ! empty( $role ) && null === get_role( $role ) ) { if ( $warn_user_only ) { WP_CLI::warning( "Role doesn't exist: {$role}" ); } else { WP_CLI::error( "Role doesn't exist: {$role}" ); } } } /** * Accommodates three different behaviors for wp_new_user_notification() * - 4.3.1 and above: expect second argument to be deprecated * - 4.3: Second argument was repurposed as $notify * - Below 4.3: Send the password in the notification * * @param string $user_id * @param string $password */ public static function wp_new_user_notification( $user_id, $password ) { if ( Utils\wp_version_compare( '4.3.1', '>=' ) ) { wp_new_user_notification( $user_id, null, 'both' ); } elseif ( Utils\wp_version_compare( '4.3', '>=' ) ) { // phpcs:ignore WordPress.WP.DeprecatedParameters.Wp_new_user_notificationParam2Found -- Only called in valid conditions. wp_new_user_notification( $user_id, 'both' ); } else { // phpcs:ignore WordPress.WP.DeprecatedParameters.Wp_new_user_notificationParam2Found -- Only called in valid conditions. wp_new_user_notification( $user_id, $password ); } } /** * Marks one or more users as spam on multisite. * * ## OPTIONS * * ... * : The user login, user email, or user ID of the user(s) to mark as spam. * * ## EXAMPLES * * # Mark user as spam. * $ wp user spam 123 * User 123 marked as spam. * Success: Spammed 1 of 1 users. */ public function spam( $args ) { $this->update_msuser_status( $args, 'spam', '1' ); } /** * Removes one or more users from spam on multisite. * * ## OPTIONS * * ... * : The user login, user email, or user ID of the user(s) to remove from spam. * * ## EXAMPLES * * # Remove user from spam. * $ wp user unspam 123 * User 123 removed from spam. * Success: Unspamed 1 of 1 users. */ public function unspam( $args ) { $this->update_msuser_status( $args, 'spam', '0' ); } /** * Common command for updating user data. */ private function update_msuser_status( $user_ids, $pref, $value ) { // If site is not multisite, then stop execution. if ( ! is_multisite() ) { WP_CLI::error( 'This is not a multisite installation.' ); } if ( 'spam' === $pref ) { $action = (int) $value ? 'marked as spam' : 'removed from spam'; $verb = (int) $value ? 'spam' : 'unspam'; } $successes = 0; $errors = 0; $users = $this->fetcher->get_many( $user_ids ); if ( count( $users ) < count( $user_ids ) ) { $errors = count( $user_ids ) - count( $users ); } foreach ( $users as $user ) { $user_id = $user->ID; // Super admin should not be marked as spam. if ( is_super_admin( $user->ID ) ) { WP_CLI::warning( "User cannot be modified. The user {$user->ID} is a network administrator." ); continue; } // Skip if user is already marked as spam and show warning. if ( $value === $user->spam ) { WP_CLI::warning( "User {$user_id} already {$action}." ); continue; } // Make that user's blog as spam too. $blogs = (array) get_blogs_of_user( $user_id, true ); foreach ( $blogs as $details ) { // Only mark site as spam if not main site. if ( ! is_main_site( $details->userblog_id, $details->site_id ) ) { update_blog_status( $details->userblog_id, $pref, $value ); } } if ( Utils\wp_version_compare( '5.3', '<' ) ) { // phpcs:ignore WordPress.WP.DeprecatedFunctions.update_user_statusFound -- Fallback for older versions. update_user_status( $user_id, $pref, $value ); } else { wp_update_user( [ 'ID' => $user_id, $pref => $value, ] ); } WP_CLI::log( "User {$user_id} {$action}." ); ++$successes; } Utils\report_batch_operation_results( 'user', $verb, count( $user_ids ), $successes, $errors ); } /** * Checks if a user's password is valid or not. * * ## OPTIONS * * * : The user login, user email or user ID of the user to check credentials for. * * * : A string that contains the plain text password for the user. * * [--escape-chars] * : Escape password with `wp_slash()` to mimic the same behavior as `wp-login.php`. * * ## EXAMPLES * * # Check whether given credentials are valid; exit status 0 if valid, otherwise 1 * $ wp user check-password admin adminpass * $ echo $? * 1 * * # Bash script for checking whether given credentials are valid or not * if ! $(wp user check-password admin adminpass); then * notify-send "Invalid Credentials"; * fi * * @subcommand check-password */ public function check_password( $args, $assoc_args ) { $escape_chars = Utils\get_flag_value( $assoc_args, 'escape-chars', false ); if ( ! $escape_chars && wp_slash( wp_unslash( $args[1] ) ) !== $args[1] ) { WP_CLI::warning( 'Password contains characters that need to be escaped. Please escape them manually or use the `--escape-chars` option.' ); } $user = $this->fetcher->get_check( $args[0] ); $user_pass = $escape_chars ? wp_slash( $args[1] ) : $args[1]; if ( wp_check_password( $user_pass, $user->data->user_pass, $user->ID ) ) { WP_CLI::halt( 0 ); } else { WP_CLI::halt( 1 ); } } }