ru-se.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

class-wp-users-list-table.php (18337B)


      1 <?php
      2 /**
      3  * List Table API: WP_Users_List_Table class
      4  *
      5  * @package WordPress
      6  * @subpackage Administration
      7  * @since 3.1.0
      8  */
      9 
     10 /**
     11  * Core class used to implement displaying users in a list table.
     12  *
     13  * @since 3.1.0
     14  * @access private
     15  *
     16  * @see WP_List_Table
     17  */
     18 class WP_Users_List_Table extends WP_List_Table {
     19 
     20 	/**
     21 	 * Site ID to generate the Users list table for.
     22 	 *
     23 	 * @since 3.1.0
     24 	 * @var int
     25 	 */
     26 	public $site_id;
     27 
     28 	/**
     29 	 * Whether or not the current Users list table is for Multisite.
     30 	 *
     31 	 * @since 3.1.0
     32 	 * @var bool
     33 	 */
     34 	public $is_site_users;
     35 
     36 	/**
     37 	 * Constructor.
     38 	 *
     39 	 * @since 3.1.0
     40 	 *
     41 	 * @see WP_List_Table::__construct() for more information on default arguments.
     42 	 *
     43 	 * @param array $args An associative array of arguments.
     44 	 */
     45 	public function __construct( $args = array() ) {
     46 		parent::__construct(
     47 			array(
     48 				'singular' => 'user',
     49 				'plural'   => 'users',
     50 				'screen'   => isset( $args['screen'] ) ? $args['screen'] : null,
     51 			)
     52 		);
     53 
     54 		$this->is_site_users = 'site-users-network' === $this->screen->id;
     55 
     56 		if ( $this->is_site_users ) {
     57 			$this->site_id = isset( $_REQUEST['id'] ) ? (int) $_REQUEST['id'] : 0;
     58 		}
     59 	}
     60 
     61 	/**
     62 	 * Check the current user's permissions.
     63 	 *
     64 	 * @since 3.1.0
     65 	 *
     66 	 * @return bool
     67 	 */
     68 	public function ajax_user_can() {
     69 		if ( $this->is_site_users ) {
     70 			return current_user_can( 'manage_sites' );
     71 		} else {
     72 			return current_user_can( 'list_users' );
     73 		}
     74 	}
     75 
     76 	/**
     77 	 * Prepare the users list for display.
     78 	 *
     79 	 * @since 3.1.0
     80 	 *
     81 	 * @global string $role
     82 	 * @global string $usersearch
     83 	 */
     84 	public function prepare_items() {
     85 		global $role, $usersearch;
     86 
     87 		$usersearch = isset( $_REQUEST['s'] ) ? wp_unslash( trim( $_REQUEST['s'] ) ) : '';
     88 
     89 		$role = isset( $_REQUEST['role'] ) ? $_REQUEST['role'] : '';
     90 
     91 		$per_page       = ( $this->is_site_users ) ? 'site_users_network_per_page' : 'users_per_page';
     92 		$users_per_page = $this->get_items_per_page( $per_page );
     93 
     94 		$paged = $this->get_pagenum();
     95 
     96 		if ( 'none' === $role ) {
     97 			$args = array(
     98 				'number'  => $users_per_page,
     99 				'offset'  => ( $paged - 1 ) * $users_per_page,
    100 				'include' => wp_get_users_with_no_role( $this->site_id ),
    101 				'search'  => $usersearch,
    102 				'fields'  => 'all_with_meta',
    103 			);
    104 		} else {
    105 			$args = array(
    106 				'number' => $users_per_page,
    107 				'offset' => ( $paged - 1 ) * $users_per_page,
    108 				'role'   => $role,
    109 				'search' => $usersearch,
    110 				'fields' => 'all_with_meta',
    111 			);
    112 		}
    113 
    114 		if ( '' !== $args['search'] ) {
    115 			$args['search'] = '*' . $args['search'] . '*';
    116 		}
    117 
    118 		if ( $this->is_site_users ) {
    119 			$args['blog_id'] = $this->site_id;
    120 		}
    121 
    122 		if ( isset( $_REQUEST['orderby'] ) ) {
    123 			$args['orderby'] = $_REQUEST['orderby'];
    124 		}
    125 
    126 		if ( isset( $_REQUEST['order'] ) ) {
    127 			$args['order'] = $_REQUEST['order'];
    128 		}
    129 
    130 		/**
    131 		 * Filters the query arguments used to retrieve users for the current users list table.
    132 		 *
    133 		 * @since 4.4.0
    134 		 *
    135 		 * @param array $args Arguments passed to WP_User_Query to retrieve items for the current
    136 		 *                    users list table.
    137 		 */
    138 		$args = apply_filters( 'users_list_table_query_args', $args );
    139 
    140 		// Query the user IDs for this page.
    141 		$wp_user_search = new WP_User_Query( $args );
    142 
    143 		$this->items = $wp_user_search->get_results();
    144 
    145 		$this->set_pagination_args(
    146 			array(
    147 				'total_items' => $wp_user_search->get_total(),
    148 				'per_page'    => $users_per_page,
    149 			)
    150 		);
    151 	}
    152 
    153 	/**
    154 	 * Output 'no users' message.
    155 	 *
    156 	 * @since 3.1.0
    157 	 */
    158 	public function no_items() {
    159 		_e( 'No users found.' );
    160 	}
    161 
    162 	/**
    163 	 * Return an associative array listing all the views that can be used
    164 	 * with this table.
    165 	 *
    166 	 * Provides a list of roles and user count for that role for easy
    167 	 * Filtersing of the user table.
    168 	 *
    169 	 * @since 3.1.0
    170 	 *
    171 	 * @global string $role
    172 	 *
    173 	 * @return string[] An array of HTML links keyed by their view.
    174 	 */
    175 	protected function get_views() {
    176 		global $role;
    177 
    178 		$wp_roles = wp_roles();
    179 
    180 		if ( $this->is_site_users ) {
    181 			$url = 'site-users.php?id=' . $this->site_id;
    182 			switch_to_blog( $this->site_id );
    183 			$users_of_blog = count_users( 'time', $this->site_id );
    184 			restore_current_blog();
    185 		} else {
    186 			$url           = 'users.php';
    187 			$users_of_blog = count_users();
    188 		}
    189 
    190 		$total_users = $users_of_blog['total_users'];
    191 		$avail_roles =& $users_of_blog['avail_roles'];
    192 		unset( $users_of_blog );
    193 
    194 		$current_link_attributes = empty( $role ) ? ' class="current" aria-current="page"' : '';
    195 
    196 		$role_links        = array();
    197 		$role_links['all'] = sprintf(
    198 			'<a href="%s"%s>%s</a>',
    199 			$url,
    200 			$current_link_attributes,
    201 			sprintf(
    202 				/* translators: %s: Number of users. */
    203 				_nx(
    204 					'All <span class="count">(%s)</span>',
    205 					'All <span class="count">(%s)</span>',
    206 					$total_users,
    207 					'users'
    208 				),
    209 				number_format_i18n( $total_users )
    210 			)
    211 		);
    212 
    213 		foreach ( $wp_roles->get_names() as $this_role => $name ) {
    214 			if ( ! isset( $avail_roles[ $this_role ] ) ) {
    215 				continue;
    216 			}
    217 
    218 			$current_link_attributes = '';
    219 
    220 			if ( $this_role === $role ) {
    221 				$current_link_attributes = ' class="current" aria-current="page"';
    222 			}
    223 
    224 			$name = translate_user_role( $name );
    225 			$name = sprintf(
    226 				/* translators: 1: User role name, 2: Number of users. */
    227 				__( '%1$s <span class="count">(%2$s)</span>' ),
    228 				$name,
    229 				number_format_i18n( $avail_roles[ $this_role ] )
    230 			);
    231 
    232 			$role_links[ $this_role ] = "<a href='" . esc_url( add_query_arg( 'role', $this_role, $url ) ) . "'$current_link_attributes>$name</a>";
    233 		}
    234 
    235 		if ( ! empty( $avail_roles['none'] ) ) {
    236 
    237 			$current_link_attributes = '';
    238 
    239 			if ( 'none' === $role ) {
    240 				$current_link_attributes = ' class="current" aria-current="page"';
    241 			}
    242 
    243 			$name = __( 'No role' );
    244 			$name = sprintf(
    245 				/* translators: 1: User role name, 2: Number of users. */
    246 				__( '%1$s <span class="count">(%2$s)</span>' ),
    247 				$name,
    248 				number_format_i18n( $avail_roles['none'] )
    249 			);
    250 
    251 			$role_links['none'] = "<a href='" . esc_url( add_query_arg( 'role', 'none', $url ) ) . "'$current_link_attributes>$name</a>";
    252 		}
    253 
    254 		return $role_links;
    255 	}
    256 
    257 	/**
    258 	 * Retrieve an associative array of bulk actions available on this table.
    259 	 *
    260 	 * @since 3.1.0
    261 	 *
    262 	 * @return array Array of bulk action labels keyed by their action.
    263 	 */
    264 	protected function get_bulk_actions() {
    265 		$actions = array();
    266 
    267 		if ( is_multisite() ) {
    268 			if ( current_user_can( 'remove_users' ) ) {
    269 				$actions['remove'] = __( 'Remove' );
    270 			}
    271 		} else {
    272 			if ( current_user_can( 'delete_users' ) ) {
    273 				$actions['delete'] = __( 'Delete' );
    274 			}
    275 		}
    276 
    277 		// Add a password reset link to the bulk actions dropdown.
    278 		if ( current_user_can( 'edit_users' ) ) {
    279 			$actions['resetpassword'] = __( 'Send password reset' );
    280 		}
    281 
    282 		return $actions;
    283 	}
    284 
    285 	/**
    286 	 * Output the controls to allow user roles to be changed in bulk.
    287 	 *
    288 	 * @since 3.1.0
    289 	 *
    290 	 * @param string $which Whether this is being invoked above ("top")
    291 	 *                      or below the table ("bottom").
    292 	 */
    293 	protected function extra_tablenav( $which ) {
    294 		$id        = 'bottom' === $which ? 'new_role2' : 'new_role';
    295 		$button_id = 'bottom' === $which ? 'changeit2' : 'changeit';
    296 		?>
    297 	<div class="alignleft actions">
    298 		<?php if ( current_user_can( 'promote_users' ) && $this->has_items() ) : ?>
    299 		<label class="screen-reader-text" for="<?php echo $id; ?>"><?php _e( 'Change role to&hellip;' ); ?></label>
    300 		<select name="<?php echo $id; ?>" id="<?php echo $id; ?>">
    301 			<option value=""><?php _e( 'Change role to&hellip;' ); ?></option>
    302 			<?php wp_dropdown_roles(); ?>
    303 			<option value="none"><?php _e( '&mdash; No role for this site &mdash;' ); ?></option>
    304 		</select>
    305 			<?php
    306 			submit_button( __( 'Change' ), '', $button_id, false );
    307 		endif;
    308 
    309 		/**
    310 		 * Fires just before the closing div containing the bulk role-change controls
    311 		 * in the Users list table.
    312 		 *
    313 		 * @since 3.5.0
    314 		 * @since 4.6.0 The `$which` parameter was added.
    315 		 *
    316 		 * @param string $which The location of the extra table nav markup: 'top' or 'bottom'.
    317 		 */
    318 		do_action( 'restrict_manage_users', $which );
    319 		?>
    320 		</div>
    321 		<?php
    322 		/**
    323 		 * Fires immediately following the closing "actions" div in the tablenav for the users
    324 		 * list table.
    325 		 *
    326 		 * @since 4.9.0
    327 		 *
    328 		 * @param string $which The location of the extra table nav markup: 'top' or 'bottom'.
    329 		 */
    330 		do_action( 'manage_users_extra_tablenav', $which );
    331 	}
    332 
    333 	/**
    334 	 * Capture the bulk action required, and return it.
    335 	 *
    336 	 * Overridden from the base class implementation to capture
    337 	 * the role change drop-down.
    338 	 *
    339 	 * @since 3.1.0
    340 	 *
    341 	 * @return string The bulk action required.
    342 	 */
    343 	public function current_action() {
    344 		if ( isset( $_REQUEST['changeit'] ) && ! empty( $_REQUEST['new_role'] ) ) {
    345 			return 'promote';
    346 		}
    347 
    348 		return parent::current_action();
    349 	}
    350 
    351 	/**
    352 	 * Get a list of columns for the list table.
    353 	 *
    354 	 * @since 3.1.0
    355 	 *
    356 	 * @return string[] Array of column titles keyed by their column name.
    357 	 */
    358 	public function get_columns() {
    359 		$c = array(
    360 			'cb'       => '<input type="checkbox" />',
    361 			'username' => __( 'Username' ),
    362 			'name'     => __( 'Name' ),
    363 			'email'    => __( 'Email' ),
    364 			'role'     => __( 'Role' ),
    365 			'posts'    => __( 'Posts' ),
    366 		);
    367 
    368 		if ( $this->is_site_users ) {
    369 			unset( $c['posts'] );
    370 		}
    371 
    372 		return $c;
    373 	}
    374 
    375 	/**
    376 	 * Get a list of sortable columns for the list table.
    377 	 *
    378 	 * @since 3.1.0
    379 	 *
    380 	 * @return array Array of sortable columns.
    381 	 */
    382 	protected function get_sortable_columns() {
    383 		$c = array(
    384 			'username' => 'login',
    385 			'email'    => 'email',
    386 		);
    387 
    388 		return $c;
    389 	}
    390 
    391 	/**
    392 	 * Generate the list table rows.
    393 	 *
    394 	 * @since 3.1.0
    395 	 */
    396 	public function display_rows() {
    397 		// Query the post counts for this page.
    398 		if ( ! $this->is_site_users ) {
    399 			$post_counts = count_many_users_posts( array_keys( $this->items ) );
    400 		}
    401 
    402 		foreach ( $this->items as $userid => $user_object ) {
    403 			echo "\n\t" . $this->single_row( $user_object, '', '', isset( $post_counts ) ? $post_counts[ $userid ] : 0 );
    404 		}
    405 	}
    406 
    407 	/**
    408 	 * Generate HTML for a single row on the users.php admin panel.
    409 	 *
    410 	 * @since 3.1.0
    411 	 * @since 4.2.0 The `$style` parameter was deprecated.
    412 	 * @since 4.4.0 The `$role` parameter was deprecated.
    413 	 *
    414 	 * @param WP_User $user_object The current user object.
    415 	 * @param string  $style       Deprecated. Not used.
    416 	 * @param string  $role        Deprecated. Not used.
    417 	 * @param int     $numposts    Optional. Post count to display for this user. Defaults
    418 	 *                             to zero, as in, a new user has made zero posts.
    419 	 * @return string Output for a single row.
    420 	 */
    421 	public function single_row( $user_object, $style = '', $role = '', $numposts = 0 ) {
    422 		if ( ! ( $user_object instanceof WP_User ) ) {
    423 			$user_object = get_userdata( (int) $user_object );
    424 		}
    425 		$user_object->filter = 'display';
    426 		$email               = $user_object->user_email;
    427 
    428 		if ( $this->is_site_users ) {
    429 			$url = "site-users.php?id={$this->site_id}&amp;";
    430 		} else {
    431 			$url = 'users.php?';
    432 		}
    433 
    434 		$user_roles = $this->get_role_list( $user_object );
    435 
    436 		// Set up the hover actions for this user.
    437 		$actions     = array();
    438 		$checkbox    = '';
    439 		$super_admin = '';
    440 
    441 		if ( is_multisite() && current_user_can( 'manage_network_users' ) ) {
    442 			if ( in_array( $user_object->user_login, get_super_admins(), true ) ) {
    443 				$super_admin = ' &mdash; ' . __( 'Super Admin' );
    444 			}
    445 		}
    446 
    447 		// Check if the user for this row is editable.
    448 		if ( current_user_can( 'list_users' ) ) {
    449 			// Set up the user editing link.
    450 			$edit_link = esc_url( add_query_arg( 'wp_http_referer', urlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) ), get_edit_user_link( $user_object->ID ) ) );
    451 
    452 			if ( current_user_can( 'edit_user', $user_object->ID ) ) {
    453 				$edit            = "<strong><a href=\"{$edit_link}\">{$user_object->user_login}</a>{$super_admin}</strong><br />";
    454 				$actions['edit'] = '<a href="' . $edit_link . '">' . __( 'Edit' ) . '</a>';
    455 			} else {
    456 				$edit = "<strong>{$user_object->user_login}{$super_admin}</strong><br />";
    457 			}
    458 
    459 			if ( ! is_multisite() && get_current_user_id() != $user_object->ID && current_user_can( 'delete_user', $user_object->ID ) ) {
    460 				$actions['delete'] = "<a class='submitdelete' href='" . wp_nonce_url( "users.php?action=delete&amp;user=$user_object->ID", 'bulk-users' ) . "'>" . __( 'Delete' ) . '</a>';
    461 			}
    462 			if ( is_multisite() && current_user_can( 'remove_user', $user_object->ID ) ) {
    463 				$actions['remove'] = "<a class='submitdelete' href='" . wp_nonce_url( $url . "action=remove&amp;user=$user_object->ID", 'bulk-users' ) . "'>" . __( 'Remove' ) . '</a>';
    464 			}
    465 
    466 			// Add a link to the user's author archive, if not empty.
    467 			$author_posts_url = get_author_posts_url( $user_object->ID );
    468 			if ( $author_posts_url ) {
    469 				$actions['view'] = sprintf(
    470 					'<a href="%s" aria-label="%s">%s</a>',
    471 					esc_url( $author_posts_url ),
    472 					/* translators: %s: Author's display name. */
    473 					esc_attr( sprintf( __( 'View posts by %s' ), $user_object->display_name ) ),
    474 					__( 'View' )
    475 				);
    476 			}
    477 
    478 			// Add a link to send the user a reset password link by email.
    479 			if ( get_current_user_id() !== $user_object->ID && current_user_can( 'edit_user', $user_object->ID ) ) {
    480 				$actions['resetpassword'] = "<a class='resetpassword' href='" . wp_nonce_url( "users.php?action=resetpassword&amp;users=$user_object->ID", 'bulk-users' ) . "'>" . __( 'Send password reset' ) . '</a>';
    481 			}
    482 
    483 			/**
    484 			 * Filters the action links displayed under each user in the Users list table.
    485 			 *
    486 			 * @since 2.8.0
    487 			 *
    488 			 * @param string[] $actions     An array of action links to be displayed.
    489 			 *                              Default 'Edit', 'Delete' for single site, and
    490 			 *                              'Edit', 'Remove' for Multisite.
    491 			 * @param WP_User  $user_object WP_User object for the currently listed user.
    492 			 */
    493 			$actions = apply_filters( 'user_row_actions', $actions, $user_object );
    494 
    495 			// Role classes.
    496 			$role_classes = esc_attr( implode( ' ', array_keys( $user_roles ) ) );
    497 
    498 			// Set up the checkbox (because the user is editable, otherwise it's empty).
    499 			$checkbox = sprintf(
    500 				'<label class="screen-reader-text" for="user_%1$s">%2$s</label>' .
    501 				'<input type="checkbox" name="users[]" id="user_%1$s" class="%3$s" value="%1$s" />',
    502 				$user_object->ID,
    503 				/* translators: %s: User login. */
    504 				sprintf( __( 'Select %s' ), $user_object->user_login ),
    505 				$role_classes
    506 			);
    507 
    508 		} else {
    509 			$edit = "<strong>{$user_object->user_login}{$super_admin}</strong>";
    510 		}
    511 
    512 		$avatar = get_avatar( $user_object->ID, 32 );
    513 
    514 		// Comma-separated list of user roles.
    515 		$roles_list = implode( ', ', $user_roles );
    516 
    517 		$r = "<tr id='user-$user_object->ID'>";
    518 
    519 		list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
    520 
    521 		foreach ( $columns as $column_name => $column_display_name ) {
    522 			$classes = "$column_name column-$column_name";
    523 			if ( $primary === $column_name ) {
    524 				$classes .= ' has-row-actions column-primary';
    525 			}
    526 			if ( 'posts' === $column_name ) {
    527 				$classes .= ' num'; // Special case for that column.
    528 			}
    529 
    530 			if ( in_array( $column_name, $hidden, true ) ) {
    531 				$classes .= ' hidden';
    532 			}
    533 
    534 			$data = 'data-colname="' . esc_attr( wp_strip_all_tags( $column_display_name ) ) . '"';
    535 
    536 			$attributes = "class='$classes' $data";
    537 
    538 			if ( 'cb' === $column_name ) {
    539 				$r .= "<th scope='row' class='check-column'>$checkbox</th>";
    540 			} else {
    541 				$r .= "<td $attributes>";
    542 				switch ( $column_name ) {
    543 					case 'username':
    544 						$r .= "$avatar $edit";
    545 						break;
    546 					case 'name':
    547 						if ( $user_object->first_name && $user_object->last_name ) {
    548 							$r .= "$user_object->first_name $user_object->last_name";
    549 						} elseif ( $user_object->first_name ) {
    550 							$r .= $user_object->first_name;
    551 						} elseif ( $user_object->last_name ) {
    552 							$r .= $user_object->last_name;
    553 						} else {
    554 							$r .= sprintf(
    555 								'<span aria-hidden="true">&#8212;</span><span class="screen-reader-text">%s</span>',
    556 								_x( 'Unknown', 'name' )
    557 							);
    558 						}
    559 						break;
    560 					case 'email':
    561 						$r .= "<a href='" . esc_url( "mailto:$email" ) . "'>$email</a>";
    562 						break;
    563 					case 'role':
    564 						$r .= esc_html( $roles_list );
    565 						break;
    566 					case 'posts':
    567 						if ( $numposts > 0 ) {
    568 							$r .= sprintf(
    569 								'<a href="%s" class="edit"><span aria-hidden="true">%s</span><span class="screen-reader-text">%s</span></a>',
    570 								"edit.php?author={$user_object->ID}",
    571 								$numposts,
    572 								sprintf(
    573 									/* translators: %s: Number of posts. */
    574 									_n( '%s post by this author', '%s posts by this author', $numposts ),
    575 									number_format_i18n( $numposts )
    576 								)
    577 							);
    578 						} else {
    579 							$r .= 0;
    580 						}
    581 						break;
    582 					default:
    583 						/**
    584 						 * Filters the display output of custom columns in the Users list table.
    585 						 *
    586 						 * @since 2.8.0
    587 						 *
    588 						 * @param string $output      Custom column output. Default empty.
    589 						 * @param string $column_name Column name.
    590 						 * @param int    $user_id     ID of the currently-listed user.
    591 						 */
    592 						$r .= apply_filters( 'manage_users_custom_column', '', $column_name, $user_object->ID );
    593 				}
    594 
    595 				if ( $primary === $column_name ) {
    596 					$r .= $this->row_actions( $actions );
    597 				}
    598 				$r .= '</td>';
    599 			}
    600 		}
    601 		$r .= '</tr>';
    602 
    603 		return $r;
    604 	}
    605 
    606 	/**
    607 	 * Gets the name of the default primary column.
    608 	 *
    609 	 * @since 4.3.0
    610 	 *
    611 	 * @return string Name of the default primary column, in this case, 'username'.
    612 	 */
    613 	protected function get_default_primary_column_name() {
    614 		return 'username';
    615 	}
    616 
    617 	/**
    618 	 * Returns an array of user roles for a given user object.
    619 	 *
    620 	 * @since 4.4.0
    621 	 *
    622 	 * @param WP_User $user_object The WP_User object.
    623 	 * @return string[] An array of user roles.
    624 	 */
    625 	protected function get_role_list( $user_object ) {
    626 		$wp_roles = wp_roles();
    627 
    628 		$role_list = array();
    629 
    630 		foreach ( $user_object->roles as $role ) {
    631 			if ( isset( $wp_roles->role_names[ $role ] ) ) {
    632 				$role_list[ $role ] = translate_user_role( $wp_roles->role_names[ $role ] );
    633 			}
    634 		}
    635 
    636 		if ( empty( $role_list ) ) {
    637 			$role_list['none'] = _x( 'None', 'no user roles' );
    638 		}
    639 
    640 		/**
    641 		 * Filters the returned array of roles for a user.
    642 		 *
    643 		 * @since 4.4.0
    644 		 *
    645 		 * @param string[] $role_list   An array of user roles.
    646 		 * @param WP_User  $user_object A WP_User object.
    647 		 */
    648 		return apply_filters( 'get_role_list', $role_list, $user_object );
    649 	}
    650 
    651 }