PluginProbe
Stream – Activity Log & Audit Trail / 3.4.2
Stream – Activity Log & Audit Trail v3.4.2
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
← All changes | classes/class-plugin.php +26 -410 4.3.03.4.2 View file →
@@ -1,18 +1,7 @@
1 1 <?php
2 -/**
3 - * Initializes plugin
4 - *
5 - * @package WP_Stream;
6 - */
7 -
8 2 namespace WP_Stream;
9 3
10 -use RuntimeException;
11 -
12 -/**
13 - * Class Plugin
14 - */
15 4 class Plugin {
16 5 /**
17 6 * Plugin version number.
18 7 *
@@ -19,9 +8,9 @@
19 8 * TODO Maybe pass this as a constructor dependency?
20 9 *
21 10 * @const string
22 11 */
23 - const VERSION = '4.3.0';
12 + const VERSION = '3.4.2';
24 13
25 14 /**
26 15 * WP-CLI command
27 16 *
@@ -28,116 +17,49 @@
28 17 * @const string
29 18 */
30 19 const WP_CLI_COMMAND = 'stream';
31 20
32 -
33 21 /**
34 - * Used to check if it's a single site, not multisite.
35 - *
36 - * @const string
37 - */
38 - const SINGLE_SITE = 'single';
39 -
40 - /**
41 - * Used to check if it's a multisite with the plugin network enabled.
42 - *
43 - * @const string
44 - */
45 - const MULTI_NETWORK = 'multisite-network';
46 -
47 - /**
48 - * Used to check if it's a multisite with the plugin not network enabled.
49 - *
50 - * @const string
51 - */
52 - const MULTI_NOT_NETWORK = 'multisite-not-network';
53 -
54 - /**
55 - * Holds and manages WordPress Admin configurations.
56 - *
57 22 * @var Admin
58 23 */
59 24 public $admin;
60 25
61 26 /**
62 - * Holds and manages alerts.
63 - *
64 27 * @var Alerts
65 28 */
66 29 public $alerts;
67 30
68 31 /**
69 - * Holds and manages alerts lists.
70 - *
71 32 * @var Alerts_List
72 33 */
73 34 public $alerts_list;
74 35
75 36 /**
76 - * Holds and manages WordPress Abilities API integration.
77 - *
78 - * @var Abilities
79 - */
80 - public $abilities;
81 -
82 - /**
83 - * Holds and manages connectors
84 - *
85 37 * @var Connectors
86 38 */
87 39 public $connectors;
88 40
89 41 /**
90 - * Holds and manages DB connections.
91 - *
92 42 * @var DB
93 43 */
94 44 public $db;
95 45
96 46 /**
97 - * Holds and manages records.
98 - *
99 47 * @var Log
100 48 */
101 49 public $log;
102 50
103 51 /**
104 - * Stores and manages WordPress settings.
105 - *
106 52 * @var Settings
107 53 */
108 54 public $settings;
109 55
110 56 /**
111 - * Process DB migrations.
112 - *
113 57 * @var Install
114 58 */
115 59 public $install;
116 60
117 61 /**
118 - * Backend used to schedule Stream's deferred work (purge / reset).
119 - *
120 - * Either an {@see AS_Scheduler} (Action Scheduler, default) or a
121 - * {@see Cron_Scheduler} (WP-Cron fallback), selected at construction via
122 - * the `wp_stream_use_action_scheduler` filter.
123 - *
124 - * @var Scheduler
125 - */
126 - public $scheduler;
127 -
128 - /**
129 - * Whether the bundled Action Scheduler library was loaded.
130 - *
131 - * Set from a file_exists() check at construction (see __construct), so it
132 - * is reliable on `plugins_loaded` even though AS only declares its as_*()
133 - * API later on `init`.
134 - *
135 - * @var bool
136 - */
137 - protected $action_scheduler_available = false;
138 -
139 - /**
140 62 * URLs and Paths used by the plugin
141 63 *
142 64 * @var array
143 65 */
@@ -143,15 +65,8 @@
143 65 */
144 66 public $locations = array();
145 67
146 68 /**
147 - * IP address for the current request to be associated with the log entry.
148 - *
149 - * @var null|false|string Valid IP address, null if not set, false if invalid.
150 - */
151 - protected $client_ip_address;
152 -
153 - /**
154 69 * Class constructor
155 70 */
156 71 public function __construct() {
157 72 $locate = $this->locate_plugin();
@@ -165,31 +80,12 @@
165 80 );
166 81
167 82 spl_autoload_register( array( $this, 'autoload' ) );
168 83
169 - // Determine the scheduler backend, then load Action Scheduler only if
170 - // it is the selected backend. AS remains a hard, bundled dependency
171 - // for the WordPress.org build (see issue #1907), but integrators who
172 - // opt into the WP-Cron fallback via `wp_stream_use_action_scheduler`
173 - // pay neither the require_once nor AS's own `init` bootstrap.
174 - //
175 - // Availability is tracked from a file_exists() check rather than
176 - // function_exists(): AS only declares its as_*() API on `init`, but
177 - // this constructor runs at plugin-file inclusion time (before the
178 - // `plugins_loaded` action fires), so the functions are not defined
179 - // yet. Scheduler methods are only ever called on/after `init`
180 - // (wp_loaded, AJAX, cron), by which point the API is loaded.
181 - $action_scheduler = $this->locations['dir'] . '/vendor/woocommerce/action-scheduler/action-scheduler.php';
182 - $this->action_scheduler_available = file_exists( $action_scheduler );
183 -
184 - // Select the scheduler backend for Stream's deferred work, loading the
185 - // bundled AS library only if it is the chosen backend.
186 - $this->scheduler = $this->create_scheduler();
187 -
188 - // Load helper functions.
84 + // Load helper functions
189 85 require_once $this->locations['inc_dir'] . 'functions.php';
190 86
191 - // Load DB helper interface/class.
87 + // Load DB helper interface/class
192 88 $driver_class = apply_filters( 'wp_stream_db_driver', '\WP_Stream\DB_Driver_WPDB' );
193 89 $driver = null;
194 90
195 91 if ( class_exists( $driver_class ) ) {
@@ -210,27 +106,24 @@
210 106 esc_html__( 'Stream DB Error', 'stream' )
211 107 );
212 108 }
213 109
214 - // Load languages.
110 + // Load languages
215 111 add_action( 'plugins_loaded', array( $this, 'i18n' ) );
216 112
217 - // Load logger class.
113 + // Load logger class
218 114 $this->log = apply_filters( 'wp_stream_log_handler', new Log( $this ) );
219 115
220 - // Set the IP address for the current request.
221 - $this->client_ip_address = wp_stream_filter_input( INPUT_SERVER, 'REMOTE_ADDR', FILTER_VALIDATE_IP );
222 -
223 - // Load settings and connectors after widgets_init and before the default init priority.
116 + // Load settings and connectors after widgets_init and before the default init priority
224 117 add_action( 'init', array( $this, 'init' ), 9 );
225 118
226 - // Add frontend indicator.
119 + // Add frontend indicator
227 120 add_action( 'wp_head', array( $this, 'frontend_indicator' ) );
228 121
229 - // Change DB driver after plugin loaded if any add-ons want to replace.
122 + // Change DB driver after plugin loaded if any add-ons want to replace
230 123 add_action( 'plugins_loaded', array( $this, 'plugins_loaded' ), 20 );
231 124
232 - // Load admin area classes.
125 + // Load admin area classes
233 126 if ( is_admin() || ( defined( 'WP_STREAM_DEV_DEBUG' ) && WP_STREAM_DEV_DEBUG ) || ( defined( 'WP_CLI' ) && WP_CLI ) ) {
234 127 $this->admin = new Admin( $this );
235 128 $this->install = $driver->setup_storage( $this );
236 129 } elseif ( defined( 'DOING_CRON' ) && DOING_CRON ) {
@@ -236,9 +129,9 @@
236 129 } elseif ( defined( 'DOING_CRON' ) && DOING_CRON ) {
237 130 $this->admin = new Admin( $this, $driver );
238 131 }
239 132
240 - // Load WP-CLI command.
133 + // Load WP-CLI command
241 134 if ( defined( 'WP_CLI' ) && WP_CLI ) {
242 135 \WP_CLI::add_command( self::WP_CLI_COMMAND, 'WP_Stream\CLI' );
243 136 }
244 137 }
@@ -243,71 +136,14 @@
243 136 }
244 137 }
245 138
246 139 /**
247 - * Build the scheduler backend for Stream's deferred work (purge / reset).
248 - *
249 - * Defaults to Action Scheduler when its bundled library is present.
250 - * Integrators that bundle Stream and run reliable cron (e.g. Cavalcade)
251 - * can force the WP-Cron fallback by returning false from
252 - * `wp_stream_use_action_scheduler`. When the fallback is chosen, the
253 - * bundled AS library is not loaded at all (no require_once, no AS `init`
254 - * bootstrap). See issue #1907.
255 - *
256 - * @return Scheduler
257 - */
258 - public function create_scheduler() {
259 - /**
260 - * Filter whether Stream uses Action Scheduler for its deferred work.
261 - *
262 - * IMPORTANT — timing: this filter is applied in Plugin::__construct(),
263 - * which runs when the Stream plugin file is included, i.e. BEFORE the
264 - * `plugins_loaded` action. Callbacks must therefore be registered from
265 - * code that loads before Stream: an mu-plugin, wp-config.php, or a
266 - * plugin guaranteed to load earlier. Registering it from a regular
267 - * plugin's `plugins_loaded` hook is too late and will be ignored.
268 - *
269 - * @param bool $use_action_scheduler Whether to use Action Scheduler.
270 - * Defaults to true when the bundled
271 - * AS library is present. Return a
272 - * real boolean: the value is cast
273 - * with (bool), so PHP string
274 - * truthiness applies to strings
275 - * (e.g. 'false' is truthy).
276 - */
277 - $use_action_scheduler = (bool) apply_filters(
278 - 'wp_stream_use_action_scheduler',
279 - $this->action_scheduler_available
280 - );
281 -
282 - if ( ! $use_action_scheduler ) {
283 - return new Cron_Scheduler();
284 - }
285 -
286 - // Guard a forced `__return_true` override when the bundled AS library
287 - // is absent: returning AS_Scheduler without loading AS would fatal on
288 - // the first unguarded as_*() call. Fall back to the cron scheduler
289 - // instead. The default path never hits this — the filter defaults to
290 - // $this->action_scheduler_available.
291 - if ( ! $this->action_scheduler_available ) {
292 - return new Cron_Scheduler();
293 - }
294 -
295 - // Load the bundled AS library before instantiating its scheduler.
296 - // AS's own ActionScheduler_Versions arbitration handles a host that
297 - // already provides its own copy.
298 - require_once $this->locations['dir'] . '/vendor/woocommerce/action-scheduler/action-scheduler.php';
299 -
300 - return new AS_Scheduler();
301 - }
302 -
303 - /**
304 140 * Autoloader for classes
305 141 *
306 - * @param string $class_name Fully qualified classname to be loaded.
142 + * @param string $class
307 143 */
308 - public function autoload( $class_name ) {
309 - if ( ! preg_match( '/^(?P<namespace>.+)\\\\(?P<autoload>[^\\\\]+)$/', $class_name, $matches ) ) {
144 + public function autoload( $class ) {
145 + if ( ! preg_match( '/^(?P<namespace>.+)\\\\(?P<autoload>[^\\\\]+)$/', $class, $matches ) ) {
310 146 return;
311 147 }
312 148
313 149 static $reflection;
@@ -337,9 +173,9 @@
337 173 public function i18n() {
338 174 load_plugin_textdomain( 'stream', false, dirname( $this->locations['plugin'] ) . '/languages/' );
339 175 }
340 176
341 - /**
177 + /*
342 178 * Load Settings, Notifications, and Connectors
343 179 *
344 180 * @action init
345 181 */
@@ -347,9 +183,9 @@
347 183 $this->settings = new Settings( $this );
348 184 $this->connectors = new Connectors( $this );
349 185 $this->alerts = new Alerts( $this );
350 186 $this->alerts_list = new Alerts_List( $this );
351 - $this->abilities = new Abilities( $this );
187 +
352 188 }
353 189
354 190 /**
355 191 * Displays an HTML comment in the frontend head to indicate that Stream is activated,
@@ -359,10 +195,9 @@
359 195 *
360 196 * @return string|void An HTML comment, or nothing if the value is filtered out.
361 197 */
362 198 public function frontend_indicator() {
363 - /* translators: Localization not needed */
364 - $comment = sprintf( 'Stream WordPress user activity plugin v%s', esc_html( $this->get_version() ) );
199 + $comment = sprintf( 'Stream WordPress user activity plugin v%s', esc_html( $this->get_version() ) ); // Localization not needed
365 200
366 201 /**
367 202 * Filter allows the HTML output of the frontend indicator comment
368 203 * to be altered or removed, if desired.
@@ -371,9 +206,9 @@
371 206 */
372 207 $comment = apply_filters( 'wp_stream_frontend_indicator', $comment );
373 208
374 209 if ( ! empty( $comment ) ) {
375 - printf( "<!-- %s -->\n", esc_html( $comment ) );
210 + echo sprintf( "<!-- %s -->\n", esc_html( $comment ) ); // xss ok
376 211 }
377 212 }
378 213
379 214 /**
@@ -379,15 +214,17 @@
379 214 /**
380 215 * Version of plugin_dir_url() which works for plugins installed in the plugins directory,
381 216 * and for plugins bundled with themes.
382 217 *
218 + * @throws \Exception
219 + *
383 220 * @return array
384 221 */
385 222 private function locate_plugin() {
386 - $dir_url = trailingslashit( plugins_url( '', __DIR__ ) );
387 - $dir_path = plugin_dir_path( __DIR__ );
223 + $dir_url = trailingslashit( plugins_url( '', dirname( __FILE__ ) ) );
224 + $dir_path = plugin_dir_path( dirname( __FILE__ ) );
388 225 $dir_basename = basename( $dir_path );
389 - $plugin_basename = trailingslashit( $dir_basename ) . 'stream.php';
226 + $plugin_basename = trailingslashit( $dir_basename ) . $dir_basename . '.php';
390 227
391 228 return compact( 'dir_url', 'dir_path', 'dir_basename', 'plugin_basename' );
392 229 }
393 230
@@ -403,9 +240,9 @@
403 240 /**
404 241 * Change plugin database driver in case driver plugin loaded after stream
405 242 */
406 243 public function plugins_loaded() {
407 - // Load DB helper interface/class.
244 + // Load DB helper interface/class
408 245 $driver_class = apply_filters( 'wp_stream_db_driver', '\WP_Stream\DB_Driver_WPDB' );
409 246
410 247 if ( class_exists( $driver_class ) ) {
411 248 $driver = new $driver_class();
@@ -433,10 +270,10 @@
433 270
434 271 /**
435 272 * Filter allows the network activated detection to be overridden.
436 273 *
437 - * @param string $is_network_activated Whether the plugin is network activated.
438 - * @param WP_Stream\Plugin $plugin The stream plugin object.
274 + * @param string $is_network_activated Whether the plugin is network activated
275 + * @param WP_Stream\Plugin $plugin The stream plugin object
439 276 */
440 277 return apply_filters( 'wp_stream_is_network_activated', $is_network_activated, $this );
441 278 }
442 279
@@ -445,8 +282,9 @@
445 282 *
446 283 * @return bool
447 284 */
448 285 public function is_mustuse() {
286 +
449 287 $stream_php = trailingslashit( WPMU_PLUGIN_DIR ) . $this->locations['plugin'];
450 288
451 289 if ( file_exists( $stream_php ) && class_exists( 'WP_Stream\Plugin' ) ) {
452 290 return true;
@@ -452,228 +290,6 @@
452 290 return true;
453 291 }
454 292
455 293 return false;
456 - }
457 -
458 - /**
459 - * Get the IP address for the current request.
460 - *
461 - * @return false|null|string Valid IP address, null if not set, false if invalid.
462 - */
463 - public function get_client_ip_address() {
464 - return apply_filters( 'wp_stream_client_ip_address', $this->client_ip_address );
465 - }
466 -
467 - /**
468 - * Get the site type.
469 - *
470 - * This function determines the type of site based on whether it is a single site or a multisite.
471 - * If it is a multisite, it also checks if it is network activated or not.
472 - *
473 - * @return string The site type
474 - */
475 - public function get_site_type(): string {
476 -
477 - // If it's a multisite, is it network activated or not?
478 - if ( is_multisite() ) {
479 - return $this->is_network_activated() ? self::MULTI_NETWORK : self::MULTI_NOT_NETWORK;
480 - }
481 -
482 - return self::SINGLE_SITE;
483 - }
484 -
485 - /**
486 - * Should the number of records which need to be processed be considered "large"?
487 - *
488 - * @param int $record_number The number of rows in the {$wpdb->prefix}_stream table to be processed.
489 - * @return bool Whether or not this should be considered large.
490 - */
491 - public function is_large_records_table( int $record_number ): bool {
492 - /**
493 - * Filters whether or not the number of records should be considered a large table.
494 - *
495 - * @since 4.1.0
496 - *
497 - * @param bool $is_large_table Whether or not the number of records should be considered large.
498 - * @param int $record_number The number of records being checked.
499 - */
500 - return apply_filters( 'wp_stream_is_large_records_table', $record_number > 1000000, $record_number );
501 - }
502 -
503 - /**
504 - * Checks if the plugin is running on a single site installation.
505 - *
506 - * @return bool True if the plugin is running on a single site installation, false otherwise.
507 - */
508 - public function is_single_site() {
509 - return self::SINGLE_SITE === $this->get_site_type();
510 - }
511 -
512 - /**
513 - * Check if the plugin is activated on a multisite installation but not network activated.
514 - *
515 - * @return bool True if the plugin is activated on a multisite installation but not network activated, false otherwise.
516 - */
517 - public function is_multisite_not_network_activated() {
518 - return self::MULTI_NOT_NETWORK === $this->get_site_type();
519 - }
520 -
521 - /**
522 - * Check if the plugin is activated on a multisite network.
523 - *
524 - * @return bool True if the plugin is network activated on a multisite, false otherwise.
525 - */
526 - public function is_multisite_network_activated() {
527 - return self::MULTI_NETWORK === $this->get_site_type();
528 - }
529 -
530 - /**
531 - * Enqueue a script along with a stylesheet if it exists.
532 - *
533 - * @param string $handle Script handle.
534 - * @param array $additional_dependencies Additional dependencies.
535 - * @param array $data Data to pass to the script.
536 - *
537 - * @throws RuntimeException If built JavaScript assets are not found.
538 - * @return void
539 - */
540 - public function enqueue_asset( $handle, $additional_dependencies = array(), $data = array() ) {
541 - // If is enqueued already, bail out.
542 - if ( wp_script_is( $handle ) ) {
543 - return;
544 - }
545 -
546 - $path = untrailingslashit( $this->locations['dir'] );
547 - $url = untrailingslashit( $this->locations['url'] );
548 -
549 - $script_asset_path = "$path/build/$handle.asset.php";
550 -
551 - if ( ! file_exists( $script_asset_path ) ) {
552 - throw new RuntimeException( 'Built JavaScript assets not found. Please run `npm run build`' );
553 - }
554 -
555 - $script_asset = require $script_asset_path; // phpcs:disable WPThemeReview.CoreFunctionality.FileInclude.FileIncludeFound
556 -
557 - wp_enqueue_script(
558 - "wp-stream-$handle",
559 - "$url/build/$handle.js",
560 - array_merge(
561 - $script_asset['dependencies'],
562 - (array) $additional_dependencies
563 - ),
564 - $script_asset['version'],
565 - true
566 - );
567 -
568 - if ( file_exists( "$path/build/$handle.css" ) ) {
569 - wp_enqueue_style(
570 - "wp-stream-$handle",
571 - "$url/build/$handle.css",
572 - array(),
573 - $script_asset['version']
574 - );
575 - }
576 -
577 - if ( ! empty( $data ) ) {
578 - wp_add_inline_script(
579 - "wp-stream-$handle",
580 - sprintf( 'window["%s"] = %s;', esc_attr( "wp-stream-$handle" ), wp_json_encode( $data ) ),
581 - 'before'
582 - );
583 - }
584 - }
585 -
586 - /**
587 - * Enqueue select2 script and locale file if exists.
588 - *
589 - * @return string Script handle.
590 - */
591 - public function with_select2() {
592 - $handle = 'wp-stream-select2';
593 -
594 - // If is enqueued already, bail out.
595 - if ( wp_script_is( $handle ) ) {
596 - return $handle;
597 - }
598 -
599 - $path = untrailingslashit( $this->locations['dir'] );
600 - $url = untrailingslashit( $this->locations['url'] );
601 -
602 - wp_enqueue_script(
603 - $handle,
604 - "$url/build/select2/js/select2.full.min.js",
605 - array( 'jquery' ),
606 - filemtime( "$path/build/select2/js/select2.full.min.js" ),
607 - true
608 - );
609 - wp_enqueue_style(
610 - $handle,
611 - "$url/build/select2/css/select2.min.css",
612 - array(),
613 - filemtime( "$path/build/select2/css/select2.min.css" )
614 - );
615 -
616 - $locale = get_locale();
617 - $lang = substr( $locale, 0, 2 );
618 - $search_files = array( $locale, $lang, 'en' );
619 -
620 - foreach ( $search_files as $search_file ) {
621 - if ( file_exists( "$path/build/select2/js/i18n/$search_file.js" ) ) {
622 - wp_enqueue_script(
623 - sanitize_title( "$handle-$search_file" ),
624 - "$url/build/select2/js/i18n/$search_file.js",
625 - array( $handle ),
626 - filemtime( "$path/build/select2/js/i18n/$search_file.js" ),
627 - true
628 - );
629 - break;
630 - }
631 - }
632 -
633 - return $handle;
634 - }
635 -
636 - /**
637 - * Enqueue jquery.timeago script and locale file if exists.
638 - *
639 - * @return string Script handle.
640 - */
641 - public function with_jquery_timeago() {
642 - $handle = 'wp-stream-jquery-timeago';
643 -
644 - // If is enqueued already, bail out.
645 - if ( wp_script_is( $handle ) ) {
646 - return $handle;
647 - }
648 -
649 - $path = untrailingslashit( $this->locations['dir'] );
650 - $url = untrailingslashit( $this->locations['url'] );
651 -
652 - wp_enqueue_script(
653 - $handle,
654 - "$url/build/timeago/js/jquery.timeago.js",
655 - array( 'jquery' ),
656 - filemtime( "$path/build/timeago/js/jquery.timeago.js" ),
657 - true
658 - );
659 -
660 - $locale = get_locale();
661 - $lang = substr( $locale, 0, 2 );
662 - $search_files = array( $locale, $lang, 'en' );
663 -
664 - foreach ( $search_files as $search_file ) {
665 - if ( file_exists( "$path/build/timeago/js/locales/jquery.timeago.$search_file.js" ) ) {
666 - wp_enqueue_script(
667 - sanitize_title( "$handle-$search_file" ),
668 - "$url/build/timeago/js/locales/jquery.timeago.$search_file.js",
669 - array( $handle ),
670 - filemtime( "$path/build/timeago/js/locales/jquery.timeago.$search_file.js" ),
671 - true
672 - );
673 - break;
674 - }
675 - }
676 -
677 - return $handle;
678 294 }
679 295 }