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