PluginProbe
Groups – Memberships and Access Control / 3.9.0
Groups – Memberships and Access Control v3.9.0
4.7.1 4.7.0 4.6.0 4.5.0 4.4.0 4.3.0 trunk 1.0.0-beta-1 1.0.0-beta-2 1.0.0-beta-3 1.0.0-beta-3b 1.0.0-beta-3c 1.0.0-beta-3d 1.1.4 1.1.5 1.10.0 1.10.1 1.10.2 1.10.3 1.11.0 1.11.1 1.11.2 1.11.3 1.12.0 1.13.0 All 131 releases
groups / lib / admin / groups-admin-groups.php

groups-admin-groups.php in Groups – Memberships and Access Control 3.9.0, at lib/admin/groups-admin-groups.php

772 lines 27.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * groups-admin-groups.php
4 *
5 * Copyright (c) "kento" Karim Rahimpur www.itthinx.com
6 *
7 * This code is released under the GNU General Public License.
8 * See COPYRIGHT.txt and LICENSE.txt.
9 *
10 * This code is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * This header and all notices must be kept intact.
16 *
17 * @author Karim Rahimpur
18 * @package groups
19 * @since groups 1.0.0
20 */
21
22 if ( !defined( 'ABSPATH' ) ) {
23 exit;
24 }
25
26 // phpcs:disable PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
27
28 // admin defines
29 define( 'GROUPS_GROUPS_PER_PAGE', 10 );
30 define( 'GROUPS_ADMIN_GROUPS_NONCE_1', 'groups-nonce-1');
31 define( 'GROUPS_ADMIN_GROUPS_NONCE_2', 'groups-nonce-2');
32 define( 'GROUPS_ADMIN_GROUPS_ACTION_NONCE', 'groups-action-nonce');
33 define( 'GROUPS_ADMIN_GROUPS_FILTER_NONCE', 'groups-filter-nonce' );
34
35 require_once GROUPS_CORE_LIB . '/class-groups-pagination.php';
36 require_once GROUPS_ADMIN_LIB . '/groups-admin-groups-add.php';
37 require_once GROUPS_ADMIN_LIB . '/groups-admin-groups-edit.php';
38 require_once GROUPS_ADMIN_LIB . '/groups-admin-groups-remove.php';
39
40 /**
41 * Manage Groups: table of groups and add, edit, remove actions.
42 */
43 function groups_admin_groups() {
44
45 global $wpdb;
46
47 $output = '';
48 // $today = date( 'Y-m-d', time() ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
49
50 if ( !Groups_User::current_user_can( GROUPS_ADMINISTER_GROUPS ) ) {
51 wp_die( esc_html__( 'Access denied.', 'groups' ) );
52 }
53
54 //
55 // handle actions
56 //
57 if ( isset( $_POST['action'] ) ) {
58 // handle action submit - do it
59 switch( $_POST['action'] ) {
60 case 'add' :
61 if ( !( $group_id = groups_admin_groups_add_submit() ) ) {
62 return groups_admin_groups_add();
63 } else {
64 $group = Groups_Group::read( $group_id );
65 Groups_Admin::add_message( sprintf(
66 /* translators: group name */
67 __( 'The <em>%s</em> group has been created.', 'groups' ),
68 $group->name ? stripslashes( wp_filter_nohtml_kses( $group->name ) ) : ''
69 ) );
70 }
71 break;
72 case 'edit' :
73 if ( !( $group_id = groups_admin_groups_edit_submit() ) ) {
74 return groups_admin_groups_edit( $_POST['group-id-field'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
75 } else {
76 $group = Groups_Group::read( $group_id );
77 Groups_Admin::add_message( sprintf(
78 /* translators: group name */
79 __( 'The <em>%s</em> group has been updated.', 'groups' ),
80 $group->name ? stripslashes( wp_filter_nohtml_kses( $group->name ) ) : ''
81 ) );
82 }
83 break;
84 case 'remove' :
85 if ( $group_id = groups_admin_groups_remove_submit() ) {
86 Groups_Admin::add_message( __( 'The group has been deleted.', 'groups' ) );
87 }
88 break;
89 // bulk actions on groups: add capabilities, remove capabilities, remove groups
90 case 'groups-action' :
91 if ( wp_verify_nonce( $_POST[GROUPS_ADMIN_GROUPS_ACTION_NONCE], 'admin' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
92 $group_ids = isset( $_POST['group_ids'] ) ? $_POST['group_ids'] : null; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
93 $bulk_action = null;
94 if ( isset( $_POST['bulk'] ) ) {
95 $bulk_action = $_POST['bulk-action']; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
96 }
97 if ( is_array( $group_ids ) && ( $bulk_action !== null ) ) {
98 foreach ( $group_ids as $group_id ) {
99 switch ( $bulk_action ) {
100 case 'add-capability' :
101 $capabilities_id = isset( $_POST['capability_id'] ) ? $_POST['capability_id'] : null; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
102 if ( $capabilities_id !== null && is_array( $_POST['capability_id'] ) ) {
103 foreach ( $capabilities_id as $capability_id ) {
104 Groups_Group_Capability::create( array( 'group_id' => $group_id, 'capability_id' => $capability_id ) );
105 }
106 }
107 break;
108 case 'remove-capability' :
109 $capabilities_id = isset( $_POST['capability_id'] ) ? $_POST['capability_id'] : null; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
110 if ( $capabilities_id !== null && is_array( $_POST['capability_id'] ) ) {
111 foreach ( $capabilities_id as $capability_id ) {
112 Groups_Group_Capability::delete( $group_id, $capability_id );
113 }
114 }
115 break;
116 case 'remove-group' :
117 $bulk_confirm = isset( $_POST['confirm'] ) ? true : false;
118 if ( $bulk_confirm ) {
119 groups_admin_groups_bulk_remove_submit();
120 } else {
121 return groups_admin_groups_bulk_remove();
122 }
123 break;
124 default:
125 if ( has_action( 'groups_admin_groups_handle_bulk_action' ) ) {
126 /**
127 * Handle the requested bulk action.
128 *
129 * @param string $bulk_action the requested bulk action
130 * @param string|int $group_id the requested group ID
131 */
132 do_action( 'groups_admin_groups_handle_bulk_action', sanitize_text_field( $bulk_action ), $group_id );
133 }
134 }
135 }
136 }
137 }
138 break;
139 default:
140 if ( has_filter( 'groups_admin_groups_handle_action_submit' ) ) {
141 /**
142 * Handle a requested action after $_POST.
143 *
144 * @since 3.7.0
145 *
146 * @param boolean $handle whether to handle the posted action
147 * @param string $action the requested action
148 *
149 * @return boolean whether the posted data was accepted and action was taken
150 */
151 if ( apply_filters( 'groups_admin_groups_handle_action_submit', false, sanitize_text_field( $_POST['action'] ) ) ) {
152 /**
153 * Fires after the posted data for an action was accepted.
154 *
155 * Should produce output to provide feedback to the user.
156 *
157 * @since 3.7.0
158 *
159 * @param string $action the requested action
160 */
161 do_action( 'groups_admin_groups_handle_action_confirm', sanitize_text_field( $_POST['action'] ) );
162 } else {
163 /**
164 * Fires after the posted data for an action was rejected.
165 *
166 * Should produce output to provide feedback to the user.
167 *
168 * @since 3.7.0
169 *
170 * @param string $action the requested action
171 */
172 do_action( 'groups_admin_groups_handle_action_reject', sanitize_text_field( $_POST['action'] ) );
173 return;
174 }
175 }
176 }
177 } else if ( isset ( $_GET['action'] ) ) {
178 // handle action request - show form
179 switch( $_GET['action'] ) {
180 case 'add' :
181 return groups_admin_groups_add();
182 break;
183 case 'edit' :
184 if ( isset( $_GET['group_id'] ) ) {
185 return groups_admin_groups_edit( $_GET['group_id'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
186 }
187 break;
188 case 'remove' :
189 if ( isset( $_GET['group_id'] ) ) {
190 return groups_admin_groups_remove( $_GET['group_id'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
191 }
192 break;
193 default:
194 if ( isset( $_GET['group_id'] ) ) {
195 if ( has_action( 'groups_admin_groups_handle_action' ) ) {
196 /**
197 * Handle the requested action and produce the corresponding output.
198 *
199 * @param string $action the requested action
200 * @param string|int $group_id the requested group ID
201 */
202 do_action( 'groups_admin_groups_handle_action', sanitize_text_field( $_GET['action'] ), sanitize_text_field( $_GET['group_id'] ) );
203 return;
204 }
205 }
206 }
207 }
208
209 //
210 // group table
211 //
212 if (
213 isset( $_POST['clear_filters'] ) ||
214 isset( $_POST['group_id'] ) ||
215 isset( $_POST['group_name'] )
216 ) {
217 if ( !wp_verify_nonce( $_POST[GROUPS_ADMIN_GROUPS_FILTER_NONCE], 'admin' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
218 wp_die( esc_html__( 'Access denied.', 'groups' ) );
219 }
220 }
221
222 // filters
223 $group_id = Groups_Options::get_user_option( 'groups_group_id', null );
224 $group_name = Groups_Options::get_user_option( 'groups_group_name', null );
225
226 if ( isset( $_POST['clear_filters'] ) ) {
227 Groups_Options::delete_user_option( 'groups_group_id' );
228 Groups_Options::delete_user_option( 'groups_group_name' );
229 $group_id = null;
230 $group_name = null;
231 } else if ( isset( $_POST['submitted'] ) ) {
232 // filter by name
233 if ( !empty( $_POST['group_name'] ) ) {
234 $group_name = sanitize_text_field( $_POST['group_name'] );
235 Groups_Options::update_user_option( 'groups_group_name', $group_name );
236 }
237 // filter by group id
238 if ( !empty( $_POST['group_id'] ) ) {
239 $group_id = intval( $_POST['group_id'] );
240 Groups_Options::update_user_option( 'groups_group_id', $group_id );
241 } else if ( isset( $_POST['group_id'] ) ) { // empty && isset => '' => all
242 $group_id = null;
243 Groups_Options::delete_user_option( 'groups_group_id' );
244 }
245 }
246
247 if ( isset( $_POST['row_count'] ) ) {
248 if ( !wp_verify_nonce( $_POST[GROUPS_ADMIN_GROUPS_NONCE_1], 'admin' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
249 wp_die( esc_html__( 'Access denied.', 'groups' ) );
250 }
251 }
252
253 if ( isset( $_POST['paged'] ) ) {
254 if ( !wp_verify_nonce( $_POST[GROUPS_ADMIN_GROUPS_NONCE_2], 'admin' ) ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
255 wp_die( esc_html__( 'Access denied.', 'groups' ) );
256 }
257 }
258
259 $current_url = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
260 $current_url = remove_query_arg( 'paged', $current_url );
261 $current_url = remove_query_arg( 'action', $current_url );
262 $current_url = remove_query_arg( 'group_id', $current_url );
263
264 $group_table = _groups_get_tablename( 'group' );
265
266 $output .=
267 '<div class="manage-groups wrap">' .
268 '<h1>' .
269 _x( 'Groups', 'page-title', 'groups' ) .
270 sprintf(
271 '<a title="%s" class="add page-title-action" href="%s">',
272 esc_attr__( 'Click to add a new group', 'groups' ),
273 esc_url( $current_url . '&action=add' )
274 ) .
275 sprintf(
276 '<img class="icon" alt="%s" src="%s" />',
277 esc_attr__( 'Add', 'groups' ),
278 esc_url( GROUPS_PLUGIN_URL . 'images/add.png' )
279 ) .
280 sprintf(
281 '<span class="label">%s</span>',
282 esc_html__( 'New Group', 'groups' )
283 ) .
284 '</a>' .
285 '</h1>';
286
287 $output .= Groups_Admin::render_messages();
288
289 $row_count = isset( $_POST['row_count'] ) ? intval( $_POST['row_count'] ) : 0;
290
291 if ($row_count <= 0) {
292 $row_count = Groups_Options::get_user_option( 'groups_per_page', GROUPS_GROUPS_PER_PAGE );
293 } else {
294 Groups_Options::update_user_option('groups_per_page', $row_count );
295 }
296 $offset = isset( $_GET['offset'] ) ? intval( $_GET['offset'] ) : 0;
297 if ( $offset < 0 ) {
298 $offset = 0;
299 }
300 $paged = isset( $_REQUEST['paged'] ) ? intval( $_REQUEST['paged'] ) : 0;
301 if ( $paged < 0 ) {
302 $paged = 0;
303 }
304
305 $orderby = isset( $_GET['orderby'] ) ? $_GET['orderby'] : null; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
306 switch ( $orderby ) {
307 case 'group_id' :
308 case 'name' :
309 case 'description' :
310 break;
311 default:
312 $orderby = 'name';
313 }
314
315 $order = isset( $_GET['order'] ) ? $_GET['order'] : null; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
316 switch ( $order ) {
317 case 'asc' :
318 case 'ASC' :
319 $switch_order = 'DESC';
320 break;
321 case 'desc' :
322 case 'DESC' :
323 $switch_order = 'ASC';
324 break;
325 default:
326 $order = 'ASC';
327 $switch_order = 'DESC';
328 }
329
330 $filters = array( " 1=%d " );
331 $filter_params = array( 1 );
332 if ( $group_id ) {
333 $filters[] = " $group_table.group_id = %d ";
334 $filter_params[] = $group_id;
335 }
336 if ( $group_name ) {
337 $filters[] = " $group_table.name LIKE %s ";
338 $filter_params[] = '%' . $wpdb->esc_like( $group_name ) . '%';
339 }
340
341 if ( !empty( $filters ) ) { // @phpstan-ignore empty.variable
342 $filters = " WHERE " . implode( " AND ", $filters );
343 } else {
344 $filters = '';
345 }
346
347 $count_query = $wpdb->prepare( "SELECT COUNT(*) FROM $group_table $filters", $filter_params ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
348 $count = $wpdb->get_var( $count_query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
349 if ( $count > $row_count ) {
350 $paginate = true;
351 } else {
352 $paginate = false;
353 }
354 $pages = ceil ( $count / $row_count );
355 if ( $paged > $pages ) {
356 $paged = $pages;
357 }
358 if ( $paged != 0 ) {
359 $offset = ( $paged - 1 ) * $row_count;
360 }
361
362 $query = $wpdb->prepare(
363 // nosemgrep: audit.php.wp.security.sqli.input-in-sinks
364 "SELECT * FROM $group_table $filters ORDER BY $orderby $order LIMIT $row_count OFFSET $offset", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
365 $filter_params
366 );
367
368 /**
369 * Allows to modify the query for the groups table.
370 *
371 * @since 3.7.0
372 *
373 * @param string $query the query
374 *
375 * @return string
376 */
377 $query = apply_filters( 'groups_admin_groups_query', $query );
378
379 // nosemgrep: audit.php.wp.security.sqli.input-in-sinks
380 $results = $wpdb->get_results( $query, OBJECT ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
381
382 /**
383 * Allows to modify the results for the groups table.
384 *
385 * @since 3.7.0
386 *
387 * @param object[] $results result to show
388 *
389 * @return object[]
390 */
391 $results = apply_filters( 'groups_admin_groups_results', $results );
392
393 $columns = array(
394 'group_id' => array( 'label' => __( 'ID', 'groups' ), 'sortable' => true ),
395 'name' => array( 'label' => __( 'Group', 'groups' ), 'sortable' => true ),
396 'description' => array( 'label' => __( 'Description', 'groups' ), 'sortable' => true ),
397 'capabilities' => array( 'label' => __( 'Capabilities', 'groups' ), 'sortable' => false )
398 );
399
400 /**
401 * Allows to modify the columns of the groups table.
402 *
403 * @since 3.7.0
404 *
405 * @param array $columns maps column keys to column details; keys must be alphanumeric allowing also for underscores '_' and dashes '-', columns with invalid keys are removed; 'checkbox' is a reserved column key and must not be used
406 *
407 * @return array
408 */
409 $columns = apply_filters( 'groups_admin_groups_columns', $columns );
410 unset( $columns['checkbox'] );
411 foreach ( $columns as $key => $column ) {
412 if ( preg_replace( '/[^a-zA-Z0-9_-]/', '', $key ) !== $key ) {
413 unset( $columns[$key] );
414 }
415 }
416
417 $column_count = count( $columns ) + 1;
418
419 $output .= '<div class="groups-overview">';
420
421 $filters_html = '<div class="filters">';
422 $filters_html .= '<form id="setfilters" action="" method="post">';
423 $filters_html .= '<fieldset>';
424 $filters_html .= '<legend>' . esc_html__( 'Filters', 'groups' ) . '</legend>';
425 $filters_html .= '<label class="group-id-filter">' . esc_html__( 'Group ID', 'groups' ) . ' ';
426 $filters_html .= '<input class="group-id-filter" name="group_id" type="text" value="' . esc_attr( $group_id ) . '"/>';
427 $filters_html .= '</label>' . ' ';
428 $filters_html .= '<label class="group-name-filter">' . esc_html__( 'Group Name', 'groups' ) . ' ';
429 $filters_html .= '<input class="group-name-filter" name="group_name" type="text" value="' . esc_attr( stripslashes( $group_name !== null ? $group_name : '' ) ) . '"/>';
430 $filters_html .= '</label>' . ' ';
431 /**
432 * Allows to add markup after the standard filter fields of the groups table.
433 *
434 * @since 3.7.0
435 *
436 * @param string $markup additional markup
437 *
438 * @return string
439 */
440 $filters_html .= apply_filters( 'groups_admin_groups_filters_fields_epilogue', '' );
441 $filters_html .= wp_nonce_field( 'admin', GROUPS_ADMIN_GROUPS_FILTER_NONCE, true, false );
442 $filters_html .= '<input class="button" type="submit" value="' . esc_attr__( 'Apply', 'groups' ) . '"/>' . ' ';
443 $filters_html .= '<input class="button" type="submit" name="clear_filters" value="' . esc_attr__( 'Clear', 'groups' ) . '"/>';
444 $filters_html .= '<input type="hidden" value="submitted" name="submitted"/>';
445 $filters_html .= '</fieldset>';
446 $filters_html .= '</form>';
447 $filters_html .= '</div>'; // .filters
448
449 /**
450 * Allows to process the HTML of the filters section of the groups table.
451 *
452 * @since 3.7.0
453 *
454 * @param string $filters_html markup
455 *
456 * @return string
457 */
458 $output .= apply_filters( 'groups_admin_groups_filters_html', $filters_html );
459
460 if ( $paginate ) {
461 require_once GROUPS_CORE_LIB . '/class-groups-pagination.php';
462 $pagination = new Groups_Pagination( $count, null, $row_count );
463 $output .= '<form id="posts-filter" method="post" action="">';
464 $output .= '<div>';
465 $output .= wp_nonce_field( 'admin', GROUPS_ADMIN_GROUPS_NONCE_2, true, false );
466 $output .= '</div>';
467 $output .= '<div class="tablenav top">';
468 $output .= $pagination->pagination( 'top' );
469 $output .= '</div>';
470 $output .= '</form>';
471 }
472
473 $output .= '<div class="page-options right">';
474 $output .= '<form id="setrowcount" action="" method="post">';
475 $output .= '<div>';
476 $output .= '<label for="row_count">' . esc_html__( 'Results per page', 'groups' ) . '</label>';
477 $output .= '<input name="row_count" type="text" size="2" value="' . esc_attr( $row_count ) .'" />';
478 $output .= wp_nonce_field( 'admin', GROUPS_ADMIN_GROUPS_NONCE_1, true, false );
479 $output .= '<input class="button" type="submit" value="' . esc_attr__( 'Apply', 'groups' ) . '"/>';
480 $output .= '</div>';
481 $output .= '</form>';
482 $output .= '</div>';
483
484 $capability_table = _groups_get_tablename( "capability" );
485 // $group_capability_table = _groups_get_tablename( "group_capability" );
486
487 // capabilities select
488 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
489 $capabilities = $wpdb->get_results( "SELECT * FROM $capability_table ORDER BY capability" );
490 $capabilities_select = sprintf(
491 '<select class="select capability" name="capability_id[]" multiple="multiple" placeholder="%s" data-placeholder="%s">',
492 esc_attr__( 'Capabilities &hellip;', 'groups' ),
493 esc_attr__( 'Capabilities &hellip;', 'groups' )
494 );
495 foreach( $capabilities as $capability ) {
496 $capabilities_select .= sprintf(
497 '<option value="%s">%s</option>',
498 esc_attr( $capability->capability_id ),
499 $capability->capability ? stripslashes( wp_filter_nohtml_kses( $capability->capability ) ) : ''
500 );
501 }
502 $capabilities_select .= '</select>';
503 $capabilities_select .= Groups_UIE::render_select( '.select.capability' );
504
505 $output .= '<form id="groups-action" method="post" action="">';
506
507 $output .= '<div class="tablenav top">';
508
509 $bulk_html = '<div class="groups-bulk-container">';
510 $bulk_html .= '<div class="capabilities-select-container">';
511 $bulk_html .= $capabilities_select;
512 $bulk_html .= wp_nonce_field( 'admin', GROUPS_ADMIN_GROUPS_ACTION_NONCE, true, false );
513 $bulk_html .= '</div>';
514 $bulk_html .= '<select class="bulk-action" name="bulk-action">';
515 $bulk_html .= '<option selected="selected" value="-1">' . esc_html__( 'Bulk Actions', 'groups' ) . '</option>';
516 $bulk_html .= '<option value="remove-group">' . esc_html__( 'Remove group', 'groups' ) . '</option>';
517 $bulk_html .= '<option value="add-capability">' . esc_html__( 'Add capability', 'groups' ) . '</option>';
518 $bulk_html .= '<option value="remove-capability">' . esc_html__( 'Remove capability', 'groups' ) . '</option>';
519 $bulk_html .= '</select>';
520 /**
521 * Allows to add markup after the standard bulk actions fields of the groups table.
522 *
523 * @since 3.7.0
524 *
525 * @param string $markup additional markup
526 *
527 * @return string
528 */
529 $filters_html .= apply_filters( 'groups_admin_groups_bulk_actions_fields_epilogue', '' );
530 $bulk_html .= sprintf( '<input class="button" type="submit" name="bulk" value="%s" />', esc_attr__( 'Apply', 'groups' ) );
531 $bulk_html .= '<input type="hidden" name="action" value="groups-action"/>';
532 $bulk_html .= '</div>';
533 $bulk_html .= '</div>';
534
535 /**
536 * Allows to process the HTML of the bulk actions section of the groups table.
537 *
538 * @since 3.7.0
539 *
540 * @param string $bulk_html markup
541 *
542 * @return string
543 */
544 $output .= apply_filters( 'groups_admin_groups_bulk_actions_html', $bulk_html );
545
546 $output .= '<table id="" class="wp-list-table widefat fixed" cellspacing="0">';
547 $output .= '<thead>';
548 $output .= '<tr>';
549
550 $output .= '<th id="cb" class="manage-column column-cb check-column" scope="col"><input type="checkbox"></th>';
551
552 foreach ( $columns as $key => $column ) {
553 $options = array(
554 'orderby' => $key,
555 'order' => $switch_order
556 );
557 $class = $key;
558 if ( isset( $column['sortable'] ) && $column['sortable'] ) {
559 if ( strcmp( $key, $orderby ) == 0 ) {
560 $lorder = strtolower( $order );
561 $class = "$key manage-column sorted $lorder";
562 } else {
563 $class = "$key manage-column sortable";
564 }
565 $heading =
566 sprintf(
567 '<a href="%s"><span>%s</span><span class="sorting-indicator"></span></a>',
568 esc_url( add_query_arg( $options, $current_url ) ),
569 esc_html( $column['label'] )
570 );
571 } else {
572 $heading = esc_html( $column['label'] );
573 }
574 $output .= sprintf(
575 '<th scope="col" class="%s">%s</th>',
576 esc_attr( $class ),
577 $heading
578 );
579 }
580
581 $output .= '</tr>';
582 $output .= '</thead>';
583 $output .= '<tbody>';
584
585 if ( count( $results ) > 0 ) {
586 for ( $i = 0; $i < count( $results ); $i++ ) {
587
588 $result = $results[$i];
589
590 /**
591 * @var Groups_Group
592 */
593 $group = new Groups_Group( $result->group_id );
594
595 // Construct the "edit" URL.
596 $edit_url = add_query_arg(
597 array(
598 'group_id' => intval( $result->group_id ),
599 'action' => 'edit',
600 'paged' => $paged
601 ),
602 $current_url
603 );
604
605 // Construct the "delete" URL.
606 $delete_url = add_query_arg(
607 array(
608 'group_id' => intval( $result->group_id ),
609 'action' => 'remove',
610 'paged' => $paged
611 ),
612 $current_url
613 );
614
615 $users_url = add_query_arg(
616 array( 'filter_group_ids[0]' => intval( $result->group_id ) ),
617 admin_url( 'users.php' )
618 );
619
620 // Construct row actions for this group.
621 $row_actions = array(
622 'edit' => sprintf( '<a href="%s"><img src="%s"/>&nbsp;%s</a>', esc_url( $edit_url ), esc_url( GROUPS_PLUGIN_URL . 'images/edit.png' ), esc_html__( 'Edit', 'groups' ) )
623 );
624 if ( $result->name !== Groups_Registered::REGISTERED_GROUP_NAME ) {
625 $row_actions['remove trash'] = sprintf( '<a href="%s" class="submitdelete"><img src="%s"/>&nbsp;%s</a>', esc_url( $delete_url ), esc_url( GROUPS_PLUGIN_URL . 'images/remove.png' ), esc_html__( 'Remove', 'groups' ) );
626 }
627
628 /**
629 * Allows to alter the row actions for a group in the groups table.
630 *
631 * @since 3.7.0
632 *
633 * @param array $row_actions row actions as HTML
634 * @param int $group_id ID of the group
635 *
636 * @return array
637 */
638 $row_actions = apply_filters( 'groups_admin_groups_row_actions', $row_actions, intval( $result->group_id ) );
639
640 $n = 1;
641 $row_actions_html = '<div class="row-actions">';
642 foreach ( $row_actions as $row_action_key => $row_action ) {
643 $row_actions_html .= sprintf( '<span class="%s">', esc_attr( $row_action_key ) );
644 $row_actions_html .= $row_action;
645 $row_actions_html .= '</span>';
646 if ( $n < count( $row_actions ) ) {
647 $row_actions_html .= '&emsp;|&emsp;';
648 }
649 $n++;
650 }
651 $row_actions_html .= '</div>'; // .row-actions
652
653 /**
654 * Allows to process the HTML of the row actions for a group in the groups table.
655 *
656 * @since 3.7.0
657 *
658 * @param string $row_actions_html markup
659 * @param int $group_id ID of the group
660 *
661 * @return string
662 */
663 $row_actions_html = apply_filters( 'groups_admin_groups_row_actions_html', $row_actions_html, intval( $result->group_id ) );
664
665 $output .= '<tr class="' . ( $i % 2 == 0 ? 'even' : 'odd' ) . '">';
666
667 $columns = array( 'checkbox' => array() ) + $columns;
668 foreach ( $columns as $key => $column ) {
669 switch ( $key ) {
670 case 'checkbox':
671 $output .= '<th class="check-column">';
672 $output .= '<input type="checkbox" value="' . esc_attr( $result->group_id ) . '" name="group_ids[]"/>';
673 $output .= '</th>';
674 break;
675 case 'group_id':
676 $output .= '<td class="group-id">';
677 $output .= $result->group_id;
678 $output .= '</td>';
679 break;
680 case 'name':
681 $output .= '<td class="group-name">';
682 $output .= sprintf(
683 '<a href="%s">%s</a>',
684 esc_url( $edit_url ),
685 $result->name ? stripslashes( wp_filter_nohtml_kses( $result->name ) ) : ''
686 );
687 $output .= ' ';
688 $user_ids = $group->get_user_ids();
689 $user_count = is_array( $user_ids ) ? count( $user_ids ) : 0; // guard against null when there are no users
690 $output .= sprintf(
691 '(<a href="%s">%s</a>)',
692 esc_url( $users_url ),
693 $user_count
694 );
695 $output .= $row_actions_html;
696 $output .= '</td>';
697 break;
698 case 'description':
699 $output .= '<td class="group-description">';
700 $output .= $result->description ? stripslashes( wp_filter_nohtml_kses( $result->description ) ) : '';
701 $output .= '</td>';
702 break;
703 case 'capabilities':
704 $output .= '<td class="capabilities">';
705 $group_capabilities = $group->get_capabilities();
706 $group_capabilities_deep = $group->get_capabilities_deep();
707 usort( $group_capabilities_deep, array( 'Groups_Utility', 'cmp' ) );
708 if ( count( $group_capabilities_deep ) > 0 ) {
709 $output .= '<ul>';
710 foreach ( $group_capabilities_deep as $group_capability ) {
711 $output .= '<li>';
712 $class = '';
713 if ( empty( $group_capabilities ) || !in_array( $group_capability, $group_capabilities ) ) {
714 $class = 'inherited';
715 }
716 $output .= sprintf( '<span class="%s">', $class );
717 $output .= stripslashes( wp_filter_nohtml_kses( $group_capability->get_capability() ) );
718 $output .= '</span>';
719 $output .= '</li>';
720 }
721 $output .= '</ul>';
722 } else {
723 $output .= esc_html__( 'This group has no capabilities.', 'groups' );
724 }
725 $output .= '</td>';
726 break;
727 default:
728 $output .= sprintf( '<td class="custom-column %s">', esc_attr( $key ) );
729 /**
730 * Provide the row's output for the column identified by $key for the group given by its ID.
731 *
732 * @param string $content column content
733 * @param string $key the column key
734 * @param int $group_id the group's ID
735 *
736 * @return string content HTML
737 */
738 $output .= apply_filters( 'groups_admin_groups_column_content', '', $key, $group->get_group_id() );
739 $output .= '</td>'; // .custom-column ...
740 }
741 }
742 $output .= '</tr>';
743 }
744 } else {
745 $output .= '<tr>';
746 $output .= sprintf( '<td colspan="%d">', esc_attr( $column_count ) );
747 $output .= esc_html__( 'There are no results.', 'groups' );
748 $output .= '</td>';
749 $output .= '</tr>';
750 }
751
752 $output .= '</tbody>';
753 $output .= '</table>';
754
755 $output .= Groups_UIE::render_add_titles( '.groups-overview table td' );
756
757 $output .= '</form>'; // #groups-action
758
759 if ( $paginate ) {
760 require_once GROUPS_CORE_LIB . '/class-groups-pagination.php';
761 $pagination = new Groups_Pagination($count, null, $row_count);
762 $output .= '<div class="tablenav bottom">';
763 $output .= $pagination->pagination( 'bottom' );
764 $output .= '</div>';
765 }
766
767 $output .= '</div>'; // .groups-overview
768 $output .= '</div>'; // .manage-groups
769
770 echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
771 } // function groups_admin_groups()
772