PluginProbe
Stream – Activity Log & Audit Trail / 3.0.6
Stream – Activity Log & Audit Trail v3.0.6
4.4.0 4.3.0 4.2.2 4.2.1 trunk 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.1 3.1.1 3.10.0 3.2.0 3.2.1 3.2.2 3.2.3 All 50 releases
stream / classes / class-admin.php

class-admin.php in Stream – Activity Log & Audit Trail 3.0.6, at classes/class-admin.php

957 lines 26.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace WP_Stream;
3
4 use DateTime;
5 use DateTimeZone;
6 use DateInterval;
7 use \WP_CLI;
8 use \WP_Roles;
9
10 class Admin {
11 /**
12 * Hold Plugin class
13 *
14 * @var Plugin
15 */
16 public $plugin;
17
18 /**
19 * Holds Network class
20 *
21 * @var Network
22 */
23 public $network;
24
25 /**
26 * Holds Live Update class
27 *
28 * @var Live_Update
29 */
30 public $live_update;
31
32 /**
33 * Holds Export class
34 *
35 * @var Export
36 */
37 public $export;
38
39 /**
40 * Menu page screen id
41 *
42 * @var string
43 */
44 public $screen_id = array();
45
46 /**
47 * List table object
48 *
49 * @var List_Table
50 */
51 public $list_table = null;
52
53 /**
54 * Option to disable access to Stream
55 *
56 * @var bool
57 */
58 public $disable_access = false;
59
60 /**
61 * Class applied to the body of the admin screen
62 *
63 * @var string
64 */
65 public $admin_body_class = 'wp_stream_screen';
66
67 /**
68 * Slug of the records page
69 *
70 * @var string
71 */
72 public $records_page_slug = 'wp_stream';
73
74 /**
75 * Slug of the settings page
76 *
77 * @var string
78 */
79 public $settings_page_slug = 'wp_stream_settings';
80
81 /**
82 * Parent page of the records and settings pages
83 *
84 * @var string
85 */
86 public $admin_parent_page = 'admin.php';
87
88 /**
89 * Capability name for viewing records
90 *
91 * @var string
92 */
93 public $view_cap = 'view_stream';
94
95 /**
96 * Capability name for viewing settings
97 *
98 * @var string
99 */
100 public $settings_cap = 'manage_options';
101
102 /**
103 * Total amount of authors to pre-load
104 *
105 * @var int
106 */
107 public $preload_users_max = 50;
108
109 /**
110 * Admin notices, collected and displayed on proper action
111 *
112 * @var array
113 */
114 public $notices = array();
115
116 /**
117 * Class constructor.
118 *
119 * @param Plugin $plugin The main Plugin class.
120 */
121 public function __construct( $plugin ) {
122 $this->plugin = $plugin;
123
124 add_action( 'init', array( $this, 'init' ) );
125
126 // Ensure function used in various methods is pre-loaded.
127 if ( ! function_exists( 'is_plugin_active_for_network' ) ) {
128 require_once( ABSPATH . '/wp-admin/includes/plugin.php' );
129 }
130
131 // User and role caps.
132 add_filter( 'user_has_cap', array( $this, 'filter_user_caps' ), 10, 4 );
133 add_filter( 'role_has_cap', array( $this, 'filter_role_caps' ), 10, 3 );
134
135 if ( is_multisite() && is_plugin_active_for_network( $this->plugin->locations['plugin'] ) && ! is_network_admin() ) {
136 $options = (array) get_site_option( 'wp_stream_network', array() );
137 $option = isset( $options['general_site_access'] ) ? absint( $options['general_site_access'] ) : 1;
138
139 $this->disable_access = ( $option ) ? false : true;
140 }
141
142 // Register settings page.
143 if ( ! $this->disable_access ) {
144 add_action( 'admin_menu', array( $this, 'register_menu' ) );
145 }
146
147 // Admin notices.
148 add_action( 'admin_notices', array( $this, 'prepare_admin_notices' ) );
149 add_action( 'shutdown', array( $this, 'admin_notices' ) );
150
151 // Add admin body class.
152 add_filter( 'admin_body_class', array( $this, 'admin_body_class' ) );
153
154 // Plugin action links.
155 add_filter( 'plugin_action_links', array( $this, 'plugin_action_links' ), 10, 2 );
156
157 // Load admin scripts and styles.
158 add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
159 add_action( 'admin_enqueue_scripts', array( $this, 'admin_menu_css' ) );
160
161 // Reset Streams database.
162 add_action( 'wp_ajax_wp_stream_reset', array( $this, 'wp_ajax_reset' ) );
163
164 // Uninstall Streams and Deactivate plugin.
165 $uninstall = new Uninstall( $this->plugin );
166 add_action( 'wp_ajax_wp_stream_uninstall', array( $uninstall, 'uninstall' ) );
167
168 // Auto purge setup.
169 add_action( 'wp_loaded', array( $this, 'purge_schedule_setup' ) );
170 add_action( 'wp_stream_auto_purge', array( $this, 'purge_scheduled_action' ) );
171
172 // Ajax users list.
173 add_action( 'wp_ajax_wp_stream_filters', array( $this, 'ajax_filters' ) );
174 }
175
176 /**
177 * Load admin classes
178 *
179 * @action init
180 */
181 public function init() {
182 $this->network = new Network( $this->plugin );
183 $this->live_update = new Live_Update( $this->plugin );
184 $this->export = new Export( $this->plugin );
185 }
186
187 /**
188 * Output specific updates passed as URL parameters.
189 *
190 * @action admin_notices
191 *
192 * @return void
193 */
194 public function prepare_admin_notices() {
195 $message = wp_stream_filter_input( INPUT_GET, 'message' );
196
197 switch ( $message ) {
198 case 'settings_reset':
199 $this->notice( esc_html__( 'All site settings have been successfully reset.', 'stream' ) );
200 break;
201 }
202 }
203
204 /**
205 * Handle notice messages according to the appropriate context (WP-CLI or the WP Admin)
206 *
207 * @param string $message Message to output.
208 * @param bool $is_error If the message is error_level (true) or warning (false).
209 */
210 public function notice( $message, $is_error = true ) {
211 if ( defined( 'WP_CLI' ) && WP_CLI ) {
212 $message = strip_tags( $message );
213
214 if ( $is_error ) {
215 WP_CLI::warning( $message );
216 } else {
217 WP_CLI::success( $message );
218 }
219 } else {
220 // Trigger admin notices late, so that any notices which occur during page load are displayed.
221 add_action( 'shutdown', array( $this, 'admin_notices' ) );
222
223 $notice = compact( 'message', 'is_error' );
224
225 if ( ! in_array( $notice, $this->notices, true ) ) {
226 $this->notices[] = $notice;
227 }
228 }
229 }
230
231 /**
232 * Show an error or other message in the WP Admin
233 *
234 * @action shutdown
235 */
236 public function admin_notices() {
237 global $allowedposttags;
238
239 $custom = array(
240 'progress' => array(
241 'class' => true,
242 'id' => true,
243 'max' => true,
244 'style' => true,
245 'value' => true,
246 ),
247 );
248
249 $allowed_html = array_merge( $allowedposttags, $custom );
250
251 ksort( $allowed_html );
252
253 foreach ( $this->notices as $notice ) {
254 $class_name = empty( $notice['is_error'] ) ? 'updated' : 'error';
255 $html_message = sprintf( '<div class="%s">%s</div>', esc_attr( $class_name ), wpautop( $notice['message'] ) );
256
257 echo wp_kses( $html_message, $allowed_html );
258 }
259 }
260
261 /**
262 * Register menu page
263 *
264 * @action admin_menu
265 *
266 * @return void
267 */
268 public function register_menu() {
269 /**
270 * Filter the main admin menu title
271 *
272 * @return string
273 */
274 $main_menu_title = apply_filters( 'wp_stream_admin_menu_title', esc_html__( 'Stream', 'stream' ) );
275
276 /**
277 * Filter the main admin menu position
278 *
279 * Note: Using longtail decimal string to reduce the chance of position conflicts, see Codex
280 *
281 * @return string
282 */
283 $main_menu_position = apply_filters( 'wp_stream_menu_position', '2.999999' );
284
285 /**
286 * Filter the main admin page title
287 *
288 * @return string
289 */
290 $main_page_title = apply_filters( 'wp_stream_admin_page_title', esc_html__( 'Stream Records', 'stream' ) );
291
292 $this->screen_id['main'] = add_menu_page(
293 $main_page_title,
294 $main_menu_title,
295 $this->view_cap,
296 $this->records_page_slug,
297 array( $this, 'render_list_table' ),
298 'div',
299 $main_menu_position
300 );
301
302 /**
303 * Filter the Settings admin page title
304 *
305 * @return string
306 */
307 $settings_page_title = apply_filters( 'wp_stream_settings_form_title', esc_html__( 'Stream Settings', 'stream' ) );
308
309 $this->screen_id['settings'] = add_submenu_page(
310 $this->records_page_slug,
311 $settings_page_title,
312 esc_html__( 'Settings', 'stream' ),
313 $this->settings_cap,
314 $this->settings_page_slug,
315 array( $this, 'render_settings_page' )
316 );
317
318 if ( isset( $this->screen_id['main'] ) ) {
319 /**
320 * Fires just before the Stream list table is registered.
321 *
322 * @return void
323 */
324 do_action( 'wp_stream_admin_menu_screens' );
325
326 // Register the list table early, so it associates the column headers with 'Screen settings'.
327 add_action( 'load-' . $this->screen_id['main'], array( $this, 'register_list_table' ) );
328 }
329 }
330
331 /**
332 * Enqueue scripts/styles for admin screen
333 *
334 * @action admin_enqueue_scripts
335 *
336 * @param string $hook
337 *
338 * @return void
339 */
340 public function admin_enqueue_scripts( $hook ) {
341 wp_register_script( 'wp-stream-select2', $this->plugin->locations['url'] . 'ui/lib/select2/js/select2.js', array( 'jquery' ), '3.5.2', true );
342 wp_register_style( 'wp-stream-select2', $this->plugin->locations['url'] . 'ui/lib/select2/css/select2.css', array(), '3.5.2' );
343 wp_register_script( 'wp-stream-timeago', $this->plugin->locations['url'] . 'ui/lib/timeago/jquery.timeago.js', array(), '1.4.1', true );
344
345 $locale = strtolower( substr( get_locale(), 0, 2 ) );
346 $file_tmpl = 'ui/lib/timeago/locales/jquery.timeago.%s.js';
347
348 if ( file_exists( $this->plugin->locations['dir'] . sprintf( $file_tmpl, $locale ) ) ) {
349 wp_register_script( 'wp-stream-timeago-locale', $this->plugin->locations['url'] . sprintf( $file_tmpl, $locale ), array( 'wp-stream-timeago' ), '1' );
350 } else {
351 wp_register_script( 'wp-stream-timeago-locale', $this->plugin->locations['url'] . sprintf( $file_tmpl, 'en' ), array( 'wp-stream-timeago' ), '1' );
352 }
353
354 wp_enqueue_style( 'wp-stream-admin', $this->plugin->locations['url'] . 'ui/css/admin.css', array(), $this->plugin->get_version() );
355
356 $script_screens = array( 'plugins.php' );
357
358 if ( in_array( $hook, $this->screen_id, true ) || in_array( $hook, $script_screens, true ) ) {
359 wp_enqueue_script( 'wp-stream-select2' );
360 wp_enqueue_style( 'wp-stream-select2' );
361
362 wp_enqueue_script( 'wp-stream-timeago' );
363 wp_enqueue_script( 'wp-stream-timeago-locale' );
364
365 wp_enqueue_script( 'wp-stream-admin', $this->plugin->locations['url'] . 'ui/js/admin.js', array( 'jquery', 'wp-stream-select2' ), $this->plugin->get_version() );
366 wp_enqueue_script( 'wp-stream-live-updates', $this->plugin->locations['url'] . 'ui/js/live-updates.js', array( 'jquery', 'heartbeat' ), $this->plugin->get_version() );
367
368 wp_localize_script(
369 'wp-stream-admin',
370 'wp_stream',
371 array(
372 'i18n' => array(
373 'confirm_purge' => esc_html__( 'Are you sure you want to delete all Stream activity records from the database? This cannot be undone.', 'stream' ),
374 'confirm_defaults' => esc_html__( 'Are you sure you want to reset all site settings to default? This cannot be undone.', 'stream' ),
375 'confirm_uninstall' => esc_html__( 'Are you sure you want to uninstall and deactivate Stream? This will delete all Stream tables from the database and cannot be undone.', 'stream' ),
376 ),
377 'locale' => esc_js( $locale ),
378 'gmt_offset' => get_option( 'gmt_offset' ),
379 )
380 );
381
382 wp_localize_script(
383 'wp-stream-live-updates',
384 'wp_stream_live_updates',
385 array(
386 'current_screen' => $hook,
387 'current_page' => isset( $_GET['paged'] ) ? esc_js( $_GET['paged'] ) : '1', // input var okay
388 'current_order' => isset( $_GET['order'] ) ? esc_js( $_GET['order'] ) : 'desc', // input var okay
389 'current_query' => wp_stream_json_encode( $_GET ), // input var okay
390 'current_query_count' => count( $_GET ), // input var okay
391 )
392 );
393 }
394
395 /**
396 * The maximum number of items that can be updated in bulk without receiving a warning.
397 *
398 * Stream watches for bulk actions performed in the WordPress Admin (such as updating
399 * many posts at once) and warns the user before proceeding if the number of items they
400 * are attempting to update exceeds this threshold value. Since Stream will try to save
401 * a log for each item, it will take longer than usual to complete the operation.
402 *
403 * The default threshold is 100 items.
404 *
405 * @return int
406 */
407 $bulk_actions_threshold = apply_filters( 'wp_stream_bulk_actions_threshold', 100 );
408
409 wp_enqueue_script( 'wp-stream-global', $this->plugin->locations['url'] . 'ui/js/global.js', array( 'jquery' ), $this->plugin->get_version() );
410 wp_localize_script(
411 'wp-stream-global',
412 'wp_stream_global',
413 array(
414 'bulk_actions' => array(
415 'i18n' => array(
416 'confirm_action' => sprintf( esc_html__( 'Are you sure you want to perform bulk actions on over %s items? This process could take a while to complete.', 'stream' ), number_format( absint( $bulk_actions_threshold ) ) ),
417 ),
418 'threshold' => absint( $bulk_actions_threshold ),
419 ),
420 'plugins_screen_url' => self_admin_url( 'plugins.php#stream' ),
421 )
422 );
423 }
424
425 /**
426 * Check whether or not the current admin screen belongs to Stream
427 *
428 * @return bool
429 */
430 public function is_stream_screen() {
431 if ( is_admin() && false !== strpos( wp_stream_filter_input( INPUT_GET, 'page' ), $this->records_page_slug ) ) {
432 return true;
433 }
434
435 return false;
436 }
437
438 /**
439 * Add a specific body class to all Stream admin screens
440 *
441 * @param string $classes CSS classes to output to body
442 *
443 * @filter admin_body_class
444 *
445 * @return string
446 */
447 public function admin_body_class( $classes ) {
448 $stream_classes = array();
449
450 if ( $this->is_stream_screen() ) {
451 $stream_classes[] = $this->admin_body_class;
452
453 if ( isset( $_GET['page'] ) ) {
454 $stream_classes[] = sanitize_key( $_GET['page'] ); // input var okay
455 }
456 }
457
458 /**
459 * Filter the Stream admin body classes
460 *
461 * @return array
462 */
463 $stream_classes = apply_filters( 'wp_stream_admin_body_classes', $stream_classes );
464 $stream_classes = implode( ' ', array_map( 'trim', $stream_classes ) );
465
466 return sprintf( '%s %s ', $classes, $stream_classes );
467 }
468
469 /**
470 * Add menu styles for various WP Admin skins
471 *
472 * @uses \wp_add_inline_style()
473 *
474 * @action admin_enqueue_scripts
475 */
476 public function admin_menu_css() {
477 wp_register_style( 'wp-stream-datepicker', $this->plugin->locations['url'] . 'ui/css/datepicker.css', array(), $this->plugin->get_version() );
478 wp_register_style( 'wp-stream-icons', $this->plugin->locations['url'] . 'ui/stream-icons/style.css', array(), $this->plugin->get_version() );
479
480 // Make sure we're working off a clean version
481 if ( ! file_exists( ABSPATH . WPINC . '/version.php' ) ) {
482 return;
483 }
484 include( ABSPATH . WPINC . '/version.php' );
485
486 if ( ! isset( $wp_version ) ) {
487 return;
488 }
489
490 $body_class = $this->admin_body_class;
491 $records_page = $this->records_page_slug;
492 $stream_url = $this->plugin->locations['url'];
493
494 if ( version_compare( $wp_version, '3.8-alpha', '>=' ) ) {
495 wp_enqueue_style( 'wp-stream-icons' );
496
497 $css = "
498 #toplevel_page_{$records_page} .wp-menu-image:before {
499 font-family: 'WP Stream' !important;
500 content: '\\73' !important;
501 }
502 #toplevel_page_{$records_page} .wp-menu-image {
503 background-repeat: no-repeat;
504 }
505 #menu-posts-feedback .wp-menu-image:before {
506 font-family: dashicons !important;
507 content: '\\f175';
508 }
509 #adminmenu #menu-posts-feedback div.wp-menu-image {
510 background: none !important;
511 background-repeat: no-repeat;
512 }
513 body.{$body_class} #wpbody-content .wrap h1:nth-child(1):before {
514 font-family: 'WP Stream' !important;
515 content: '\\73';
516 padding: 0 8px 0 0;
517 }
518 ";
519 } else {
520 $css = "
521 #toplevel_page_{$records_page} .wp-menu-image {
522 background: url( {$stream_url}ui/stream-icons/menuicon-sprite.png ) 0 90% no-repeat;
523 }
524 /* Retina Stream Menu Icon */
525 @media only screen and (-moz-min-device-pixel-ratio: 1.5),
526 only screen and (-o-min-device-pixel-ratio: 3/2),
527 only screen and (-webkit-min-device-pixel-ratio: 1.5),
528 only screen and (min-device-pixel-ratio: 1.5) {
529 #toplevel_page_{$records_page} .wp-menu-image {
530 background: url( {$stream_url}ui/stream-icons/menuicon-sprite-2x.png ) 0 90% no-repeat;
531 background-size:30px 64px;
532 }
533 }
534 #toplevel_page_{$records_page}.current .wp-menu-image,
535 #toplevel_page_{$records_page}.wp-has-current-submenu .wp-menu-image,
536 #toplevel_page_{$records_page}:hover .wp-menu-image {
537 background-position: top left;
538 }
539 ";
540 }
541
542 \wp_add_inline_style( 'wp-admin', $css );
543 }
544
545 public function wp_ajax_reset() {
546 check_ajax_referer( 'stream_nonce', 'wp_stream_nonce' );
547
548 if ( ! current_user_can( $this->settings_cap ) ) {
549 wp_die(
550 esc_html__( "You don't have sufficient privileges to do this action.", 'stream' )
551 );
552 }
553
554 $this->erase_stream_records();
555
556 if ( defined( 'WP_STREAM_TESTS' ) && WP_STREAM_TESTS ) {
557 return true;
558 }
559
560 wp_redirect(
561 add_query_arg(
562 array(
563 'page' => is_network_admin() ? $this->network->network_settings_page_slug : $this->settings_page_slug,
564 'message' => 'data_erased',
565 ),
566 self_admin_url( $this->admin_parent_page )
567 )
568 );
569
570 exit;
571 }
572
573 private function erase_stream_records() {
574 global $wpdb;
575
576 $where = '';
577
578 if ( is_multisite() && ! is_plugin_active_for_network( $this->plugin->locations['plugin'] ) ) {
579 $where .= $wpdb->prepare( ' AND `blog_id` = %d', get_current_blog_id() );
580 }
581
582 $wpdb->query(
583 "DELETE `stream`, `meta`
584 FROM {$wpdb->stream} AS `stream`
585 LEFT JOIN {$wpdb->streammeta} AS `meta`
586 ON `meta`.`record_id` = `stream`.`ID`
587 WHERE 1=1 {$where};" // @codingStandardsIgnoreLine $where already prepared
588 );
589 }
590
591 public function purge_schedule_setup() {
592 if ( ! wp_next_scheduled( 'wp_stream_auto_purge' ) ) {
593 wp_schedule_event( time(), 'twicedaily', 'wp_stream_auto_purge' );
594 }
595 }
596
597 public function purge_scheduled_action() {
598 global $wpdb;
599
600 // Don't purge when in Network Admin unless Stream is network activated
601 if (
602 is_multisite()
603 &&
604 is_network_admin()
605 &&
606 ! is_plugin_active_for_network( $this->plugin->locations['plugin'] )
607 ) {
608 return;
609 }
610
611 if ( is_multisite() && is_plugin_active_for_network( $this->plugin->locations['plugin'] ) ) {
612 $options = (array) get_site_option( 'wp_stream_network', array() );
613 } else {
614 $options = (array) get_option( 'wp_stream', array() );
615 }
616
617 if ( isset( $options['general_keep_records_indefinitely'] ) || ! isset( $options['general_records_ttl'] ) ) {
618 return;
619 }
620
621 $days = $options['general_records_ttl'];
622 $date = new DateTime( 'now', $timezone = new DateTimeZone( 'UTC' ) );
623
624 $date->sub( DateInterval::createFromDateString( "$days days" ) );
625
626 $where = $wpdb->prepare( ' AND `stream`.`created` < %s', $date->format( 'Y-m-d H:i:s' ) );
627
628 // Multisite but NOT network activated, only purge the current blog
629 if ( is_multisite() && ! is_plugin_active_for_network( $this->plugin->locations['plugin'] ) ) {
630 $where .= $wpdb->prepare( ' AND `blog_id` = %d', get_current_blog_id() );
631 }
632
633 $wpdb->query(
634 "DELETE `stream`, `meta`
635 FROM {$wpdb->stream} AS `stream`
636 LEFT JOIN {$wpdb->streammeta} AS `meta`
637 ON `meta`.`record_id` = `stream`.`ID`
638 WHERE 1=1 {$where};" // @codingStandardsIgnoreLine $where already prepared
639 );
640 }
641
642 /**
643 * @param array $links
644 * @param string $file
645 *
646 * @filter plugin_action_links
647 *
648 * @return array
649 */
650 public function plugin_action_links( $links, $file ) {
651 if ( plugin_basename( $this->plugin->locations['dir'] . 'stream.php' ) !== $file ) {
652 return $links;
653 }
654
655 // Also don't show links in Network Admin if Stream isn't network enabled
656 if ( is_network_admin() && is_multisite() && ! is_plugin_active_for_network( $this->plugin->locations['plugin'] ) ) {
657 return $links;
658 }
659
660 if ( is_network_admin() ) {
661 $admin_page_url = add_query_arg( array( 'page' => $this->network->network_settings_page_slug ), network_admin_url( $this->admin_parent_page ) );
662 } else {
663 $admin_page_url = add_query_arg( array( 'page' => $this->settings_page_slug ), admin_url( $this->admin_parent_page ) );
664 }
665
666 $links[] = sprintf( '<a href="%s">%s</a>', esc_url( $admin_page_url ), esc_html__( 'Settings', 'default' ) );
667
668 $url = add_query_arg(
669 array(
670 'action' => 'wp_stream_uninstall',
671 'wp_stream_nonce' => wp_create_nonce( 'stream_nonce' ),
672 ),
673 admin_url( 'admin-ajax.php' )
674 );
675
676 $links[] = sprintf( '<span id="wp_stream_uninstall" class="delete"><a href="%s">%s</a></span>', esc_url( $url ), esc_html__( 'Uninstall', 'stream' ) );
677
678 return $links;
679 }
680
681 /**
682 * Render main page
683 */
684 public function render_list_table() {
685 $this->list_table->prepare_items();
686 ?>
687 <div class="wrap">
688 <h1><?php echo esc_html( get_admin_page_title() ) ?></h1>
689 <?php $this->list_table->display() ?>
690 </div>
691 <?php
692 }
693
694 /**
695 * Render settings page
696 */
697 public function render_settings_page() {
698 $option_key = $this->plugin->settings->option_key;
699 $form_action = apply_filters( 'wp_stream_settings_form_action', admin_url( 'options.php' ) );
700
701 $page_description = apply_filters( 'wp_stream_settings_form_description', '' );
702
703 $sections = $this->plugin->settings->get_fields();
704 $active_tab = wp_stream_filter_input( INPUT_GET, 'tab' );
705
706 wp_enqueue_script( 'wp-stream-settings', $this->plugin->locations['url'] . 'ui/js/settings.js', array( 'jquery' ), $this->plugin->get_version(), true );
707 ?>
708 <div class="wrap">
709 <h1><?php echo esc_html( get_admin_page_title() ) ?></h1>
710
711 <?php if ( ! empty( $page_description ) ) : ?>
712 <p><?php echo esc_html( $page_description ) ?></p>
713 <?php endif; ?>
714
715 <?php settings_errors() ?>
716
717 <?php if ( count( $sections ) > 1 ) : ?>
718 <h2 class="nav-tab-wrapper">
719 <?php $i = 0 ?>
720 <?php foreach ( $sections as $section => $data ) : ?>
721 <?php $i ++ ?>
722 <?php $is_active = ( ( 1 === $i && ! $active_tab ) || $active_tab === $section ) ?>
723 <a href="<?php echo esc_url( add_query_arg( 'tab', $section ) ) ?>" class="nav-tab<?php if ( $is_active ) { echo esc_attr( ' nav-tab-active' ); } ?>">
724 <?php echo esc_html( $data['title'] ) ?>
725 </a>
726 <?php endforeach; ?>
727 </h2>
728 <?php endif; ?>
729
730 <div class="nav-tab-content" id="tab-content-settings">
731 <form method="post" action="<?php echo esc_attr( $form_action ) ?>" enctype="multipart/form-data">
732 <div class="settings-sections">
733 <?php
734 $i = 0;
735 foreach ( $sections as $section => $data ) {
736 $i++;
737
738 $is_active = ( ( 1 === $i && ! $active_tab ) || $active_tab === $section );
739
740 if ( $is_active ) {
741 settings_fields( $option_key );
742 do_settings_sections( $option_key );
743 }
744 }
745 ?>
746 </div>
747 <?php submit_button() ?>
748 </form>
749 </div>
750 </div>
751 <?php
752 }
753
754 /**
755 * Instantiate the list table
756 */
757 public function register_list_table() {
758 $this->list_table = new List_Table( $this->plugin, array( 'screen' => $this->screen_id['main'] ) );
759 }
760
761 /**
762 * Check if a particular role has access
763 *
764 * @param string $role
765 *
766 * @return bool
767 */
768 private function role_can_view( $role ) {
769 if ( in_array( $role, $this->plugin->settings->options['general_role_access'], true ) ) {
770 return true;
771 }
772
773 return false;
774 }
775
776 /**
777 * Filter user caps to dynamically grant our view cap based on allowed roles
778 *
779 * @param $allcaps
780 * @param $caps
781 * @param $args
782 * @param $user
783 *
784 * @filter user_has_cap
785 *
786 * @return array
787 */
788 public function filter_user_caps( $allcaps, $caps, $args, $user = null ) {
789 global $wp_roles;
790
791 $_wp_roles = isset( $wp_roles ) ? $wp_roles : new WP_Roles();
792
793 $user = is_a( $user, 'WP_User' ) ? $user : wp_get_current_user();
794
795 // @see
796 // https://github.com/WordPress/WordPress/blob/c67c9565f1495255807069fdb39dac914046b1a0/wp-includes/capabilities.php#L758
797 $roles = array_unique(
798 array_merge(
799 $user->roles,
800 array_filter(
801 array_keys( $user->caps ),
802 array( $_wp_roles, 'is_role' )
803 )
804 )
805 );
806
807 $stream_view_caps = array( $this->view_cap );
808
809 foreach ( $caps as $cap ) {
810 if ( in_array( $cap, $stream_view_caps, true ) ) {
811 foreach ( $roles as $role ) {
812 if ( $this->role_can_view( $role ) ) {
813 $allcaps[ $cap ] = true;
814
815 break 2;
816 }
817 }
818 }
819 }
820
821 return $allcaps;
822 }
823
824 /**
825 * Filter role caps to dynamically grant our view cap based on allowed roles
826 *
827 * @filter role_has_cap
828 *
829 * @param $allcaps
830 * @param $cap
831 * @param $role
832 *
833 * @return array
834 */
835 public function filter_role_caps( $allcaps, $cap, $role ) {
836 $stream_view_caps = array( $this->view_cap );
837
838 if ( in_array( $cap, $stream_view_caps, true ) && $this->role_can_view( $role ) ) {
839 $allcaps[ $cap ] = true;
840 }
841
842 return $allcaps;
843 }
844
845 /**
846 * @action wp_ajax_wp_stream_filters
847 */
848 public function ajax_filters() {
849 if ( ! defined( 'DOING_AJAX' ) || ! current_user_can( $this->plugin->admin->settings_cap ) ) {
850 wp_die( '-1' );
851 }
852
853 check_ajax_referer( 'stream_filters_user_search_nonce', 'nonce' );
854
855 switch ( wp_stream_filter_input( INPUT_GET, 'filter' ) ) {
856 case 'user_id':
857 $users = array_merge(
858 array( 0 => (object) array( 'display_name' => 'WP-CLI' ) ),
859 get_users()
860 );
861
862 $search = wp_stream_filter_input( INPUT_GET, 'q' );
863 if ( $search ) {
864 // `search` arg for get_users() is not enough
865 $users = array_filter(
866 $users,
867 function( $user ) use ( $search ) {
868 return false !== mb_strpos( mb_strtolower( $user->display_name ), mb_strtolower( $search ) );
869 }
870 );
871 }
872
873 if ( count( $users ) > $this->preload_users_max ) {
874 $users = array_slice( $users, 0, $this->preload_users_max );
875 }
876
877 // Get gravatar / roles for final result set
878 $results = $this->get_users_record_meta( $users );
879
880 break;
881 }
882
883 if ( isset( $results ) ) {
884 echo wp_stream_json_encode( $results ); // xss ok
885 }
886
887 die();
888 }
889
890 public function get_users_record_meta( $authors ) {
891 $authors_records = array();
892
893 foreach ( $authors as $user_id => $args ) {
894 $author = new Author( $args->ID );
895
896 $authors_records[ $user_id ] = array(
897 'text' => $author->get_display_name(),
898 'id' => $author->id,
899 'label' => $author->get_display_name(),
900 'icon' => $author->get_avatar_src( 32 ),
901 'title' => '',
902 );
903 }
904
905 return $authors_records;
906 }
907
908 /**
909 * Get user meta in a way that is also safe for VIP
910 *
911 * @param int $user_id
912 * @param string $meta_key
913 * @param bool $single (optional)
914 *
915 * @return mixed
916 */
917 function get_user_meta( $user_id, $meta_key, $single = true ) {
918 if ( wp_stream_is_vip() && function_exists( 'get_user_attribute' ) ) {
919 return get_user_attribute( $user_id, $meta_key );
920 }
921 return get_user_meta( $user_id, $meta_key, $single );
922 }
923
924 /**
925 * Update user meta in a way that is also safe for VIP
926 *
927 * @param int $user_id
928 * @param string $meta_key
929 * @param mixed $meta_value
930 * @param mixed $prev_value (optional)
931 *
932 * @return int|bool
933 */
934 function update_user_meta( $user_id, $meta_key, $meta_value, $prev_value = '' ) {
935 if ( wp_stream_is_vip() && function_exists( 'update_user_attribute' ) ) {
936 return update_user_attribute( $user_id, $meta_key, $meta_value );
937 }
938 return update_user_meta( $user_id, $meta_key, $meta_value, $prev_value );
939 }
940
941 /**
942 * Delete user meta in a way that is also safe for VIP
943 *
944 * @param int $user_id
945 * @param string $meta_key
946 * @param mixed $meta_value (optional)
947 *
948 * @return bool
949 */
950 function delete_user_meta( $user_id, $meta_key, $meta_value = '' ) {
951 if ( wp_stream_is_vip() && function_exists( 'delete_user_attribute' ) ) {
952 return delete_user_attribute( $user_id, $meta_key, $meta_value );
953 }
954 return delete_user_meta( $user_id, $meta_key, $meta_value );
955 }
956 }
957