WP Security Audit Log - Version 4.4.1

Version Description

(2022-03-23) =

Release notes: Out now: Activity Log for MainWP 2.0 & WP Activity Log 4.4.1

  • Improvements & changes

    • All of the plugin's code is now using the WordPress coding standards.
    • Removed the reporting and search code from the free edition plugin that was used by the MainWP extension.
  • Bug fixes

    • Fixed: PHP fatal error when index.php file is saved in the custom sensors directory.

Refer to the complete plugin changelog for more detailed information about what was new, improved and fixed in previous versions of the WP Activity Log plugin.

Download this release

Release Info

Developer WPWhiteSecurity
Plugin Icon 128x128 WP Security Audit Log
Version 4.4.1
Comparing to
See all releases

Code changes from version 4.4.0 to 4.4.1

Files changed (94) hide show
  1. classes/AbstractLogger.php +17 -6
  2. classes/AbstractMetaDataSensor.php +19 -18
  3. classes/AbstractSandboxTask.php +20 -12
  4. classes/AbstractSensor.php +25 -32
  5. classes/AbstractView.php +54 -41
  6. classes/Adapters/ActiveRecordInterface.php +17 -15
  7. classes/Adapters/MetaInterface.php +2 -2
  8. classes/Adapters/MySQL/ActiveRecordAdapter.php +158 -149
  9. classes/Adapters/MySQL/MetaAdapter.php +18 -18
  10. classes/Adapters/MySQL/OccurrenceAdapter.php +81 -80
  11. classes/Adapters/MySQL/QueryAdapter.php +105 -91
  12. classes/Adapters/MySQL/TmpUserAdapter.php +10 -10
  13. classes/Adapters/OccurrenceInterface.php +10 -10
  14. classes/Adapters/QueryInterface.php +18 -7
  15. classes/Alert.php +76 -61
  16. classes/AlertFormatter.php +107 -71
  17. classes/AlertFormatterConfiguration.php +138 -63
  18. classes/AlertFormatterFactory.php +35 -21
  19. classes/AlertManager.php +257 -215
  20. classes/AuditLogGridView.php +99 -120
  21. classes/AuditLogListView.php +76 -85
  22. classes/Autoloader.php +10 -4
  23. classes/Connector/AbstractConnector.php +14 -14
  24. classes/Connector/ConnectorFactory.php +14 -14
  25. classes/Connector/ConnectorInterface.php +12 -12
  26. classes/Connector/MySQLDB.php +126 -127
  27. classes/Connector/wp-db-custom.php +16 -14
  28. classes/ConstantManager.php +24 -19
  29. classes/ExtensionPlaceholderView.php +42 -18
  30. classes/Helpers/DataHelper.php +4 -4
  31. classes/Helpers/Options.php +38 -44
  32. classes/Loggers/Database.php +37 -36
  33. classes/MainWpApi.php +32 -171
  34. classes/Models/ActiveRecord.php +79 -75
  35. classes/Models/Meta.php +19 -19
  36. classes/Models/Occurrence.php +123 -95
  37. classes/Models/OccurrenceQuery.php +1 -1
  38. classes/Models/Query.php +79 -36
  39. classes/Models/TmpUser.php +1 -1
  40. classes/Nicer.php +10 -0
  41. classes/Ref.php +1 -0
  42. classes/ReportArgs.php +18 -5
  43. classes/SensorManager.php +16 -15
  44. classes/Sensors/ACFMeta.php +45 -36
  45. classes/Sensors/Comments.php +27 -26
  46. classes/Sensors/Content.php +126 -139
  47. classes/Sensors/Database.php +75 -69
  48. classes/Sensors/Files.php +25 -20
  49. classes/Sensors/LogInOut.php +93 -92
  50. classes/Sensors/MainWP.php +47 -43
  51. classes/Sensors/Menus.php +133 -124
  52. classes/Sensors/MetaData.php +53 -50
  53. classes/Sensors/Multisite.php +52 -50
  54. classes/Sensors/MultisiteSignUp.php +4 -4
  55. classes/Sensors/PluginsThemes.php +120 -102
  56. classes/Sensors/Register.php +5 -5
  57. classes/Sensors/System.php +85 -81
  58. classes/Sensors/UserProfile.php +56 -42
  59. classes/Sensors/Widgets.php +65 -57
  60. classes/Settings.php +544 -379
  61. classes/ThirdPartyExtensions/AbstractExtension.php +41 -6
  62. classes/ThirdPartyExtensions/BBPressExtension.php +34 -1
  63. classes/ThirdPartyExtensions/GravityFormsExtension.php +32 -2
  64. classes/ThirdPartyExtensions/TablePressExtension.php +33 -0
  65. classes/ThirdPartyExtensions/WFCMExtension.php +46 -5
  66. classes/ThirdPartyExtensions/WPFormsExtension.php +35 -2
  67. classes/ThirdPartyExtensions/WooCommerceExtension.php +40 -4
  68. classes/ThirdPartyExtensions/YoastSeoExtension.php +34 -1
  69. classes/Uninstall.php +12 -7
  70. classes/Upgrade/MetadataMigration.php +50 -37
  71. classes/Upgrade/Upgrade_43000_to_44400.php +53 -22
  72. classes/Utilities/DateTimeFormatter.php +59 -21
  73. classes/Utilities/Emailer.php +11 -8
  74. classes/Utilities/FileSystemUtils.php +8 -2
  75. classes/Utilities/PluginInstallAndActivate.php +4 -5
  76. classes/Utilities/PluginInstallerAction.php +3 -4
  77. classes/Utilities/RequestUtils.php +19 -2
  78. classes/Utilities/UserUtils.php +16 -6
  79. classes/ViewManager.php +138 -125
  80. classes/Views/AuditLog.php +200 -199
  81. classes/Views/EmailNotifications.php +30 -28
  82. classes/Views/ExternalDB.php +25 -23
  83. classes/Views/Help.php +58 -65
  84. classes/Views/LogInUsers.php +26 -24
  85. classes/Views/Reports.php +25 -23
  86. classes/Views/Search.php +27 -27
  87. classes/Views/Settings.php +674 -642
  88. classes/Views/SetupWizard.php +68 -63
  89. classes/Views/ToggleAlerts.php +78 -74
  90. classes/Views/addons/html-view.php +8 -7
  91. classes/WidgetManager.php +23 -23
  92. css/dist/wsal-wizard.css +1 -177
  93. css/dist/wsal-wizard.min.css +0 -1
  94. defaults.php +819 -819
classes/AbstractLogger.php CHANGED
@@ -1,4 +1,15 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  /**
4
  * Abstract class used in the Logger.
@@ -29,12 +40,12 @@ abstract class WSAL_AbstractLogger {
29
  /**
30
  * Log alert abstract.
31
  *
32
- * @param integer $type - Alert code.
33
- * @param array $data - Metadata.
34
- * @param integer $date (Optional) - Created on.
35
  * @param integer $site_id (Optional) - Site id.
36
  */
37
- public abstract function Log( $type, $data = array(), $date = null, $site_id = null );
38
 
39
  /**
40
  * Determines what is the correct timestamp for the event.
@@ -43,8 +54,8 @@ abstract class WSAL_AbstractLogger {
43
  * action scheduler in 4.3.0. The $legacy_date attribute is only used for migration of legacy data. This should be
44
  * removed in future releases.
45
  *
46
- * @param array $metadata Event metadata.
47
- * @param int $legacy_date Legacy date only used when migrating old db event format to the new one.
48
  *
49
  * @return float GMT timestamp including microseconds.
50
  * @since 4.3.0
1
  <?php
2
+ /**
3
+ * Abstract logger class.
4
+ *
5
+ * @package wsal
6
+ * @subpackage loggers
7
+ */
8
+
9
+ // Exit if accessed directly.
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
 
14
  /**
15
  * Abstract class used in the Logger.
40
  /**
41
  * Log alert abstract.
42
  *
43
+ * @param integer $type - Alert code.
44
+ * @param array $data - Metadata.
45
+ * @param integer $date (Optional) - Created on.
46
  * @param integer $site_id (Optional) - Site id.
47
  */
48
+ abstract public function log( $type, $data = array(), $date = null, $site_id = null );
49
 
50
  /**
51
  * Determines what is the correct timestamp for the event.
54
  * action scheduler in 4.3.0. The $legacy_date attribute is only used for migration of legacy data. This should be
55
  * removed in future releases.
56
  *
57
+ * @param array $metadata Event metadata.
58
+ * @param int $legacy_date Legacy date only used when migrating old db event format to the new one.
59
  *
60
  * @return float GMT timestamp including microseconds.
61
  * @since 4.3.0
classes/AbstractMetaDataSensor.php CHANGED
@@ -4,8 +4,9 @@
4
  *
5
  * Abstract meta data sensor file.
6
  *
7
- * @since 4.1.3
8
- * @package wsal
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -16,9 +17,9 @@ if ( ! defined( 'ABSPATH' ) ) {
16
  /**
17
  * Abstract sensor for meta data.
18
  *
19
- * @package wsal
20
  * @subpackage sensors
21
- * @since 4.1.3
22
  */
23
  abstract class WSAL_AbstractMetaDataSensor extends WSAL_AbstractSensor {
24
 
@@ -33,12 +34,12 @@ abstract class WSAL_AbstractMetaDataSensor extends WSAL_AbstractSensor {
33
  * Check "Excluded Custom Fields" or meta keys starts with "_".
34
  *
35
  * @param string $object_type Object type - user or post.
36
- * @param int $object_id - Object ID.
37
- * @param string $meta_key - Meta key.
38
  *
39
- * @return boolean can log true|false
40
  */
41
- protected function CanLogMetaKey( $object_type, $object_id, $meta_key ) {
42
  // Check if excluded meta key or starts with _.
43
  if ( '_' === substr( $meta_key, 0, 1 ) ) {
44
  /**
@@ -54,7 +55,7 @@ abstract class WSAL_AbstractMetaDataSensor extends WSAL_AbstractSensor {
54
  }
55
 
56
  return false;
57
- } elseif ( $this->IsExcludedCustomFields( $object_type, $meta_key ) ) {
58
  return false;
59
  } else {
60
  return true;
@@ -68,7 +69,7 @@ abstract class WSAL_AbstractMetaDataSensor extends WSAL_AbstractSensor {
68
  *
69
  * @return array $editor_link - Name and value link
70
  */
71
- protected function GetEditorLink( $post ) {
72
  $post_id = is_int( $post ) ? intval( $post ) : $post->ID;
73
  return array(
74
  'name' => 'EditorLinkPost',
@@ -85,22 +86,22 @@ abstract class WSAL_AbstractMetaDataSensor extends WSAL_AbstractSensor {
85
  *
86
  * @return boolean is excluded from monitoring true|false
87
  */
88
- public function IsExcludedCustomFields( $object_type, $custom ) {
89
- $custom_fields = [];
90
- if ('post' === $object_type) {
91
- $custom_fields = $this->plugin->settings()->GetExcludedPostMetaFields();
92
- } else if ('user' === $object_type) {
93
- $custom_fields = $this->plugin->settings()->GetExcludedUserMetaFields();
94
  }
95
 
96
- if ( in_array( $custom, $custom_fields ) ) {
97
  return true;
98
  }
99
 
100
  foreach ( $custom_fields as $field ) {
101
  if ( false !== strpos( $field, '*' ) ) {
102
  // Wildcard str[any_character] when you enter (str*).
103
- if ( substr( $field, - 1 ) == '*' ) {
104
  $field = rtrim( $field, '*' );
105
  if ( preg_match( "/^$field/", $custom ) ) {
106
  return true;
4
  *
5
  * Abstract meta data sensor file.
6
  *
7
+ * @since 4.1.3
8
+ * @package wsal
9
+ * @subpackage sensors
10
  */
11
 
12
  // Exit if accessed directly.
17
  /**
18
  * Abstract sensor for meta data.
19
  *
20
+ * @package wsal
21
  * @subpackage sensors
22
+ * @since 4.1.3
23
  */
24
  abstract class WSAL_AbstractMetaDataSensor extends WSAL_AbstractSensor {
25
 
34
  * Check "Excluded Custom Fields" or meta keys starts with "_".
35
  *
36
  * @param string $object_type Object type - user or post.
37
+ * @param int $object_id - Object ID.
38
+ * @param string $meta_key - Meta key.
39
  *
40
+ * @return boolean Can log true|false
41
  */
42
+ protected function can_log_meta_key( $object_type, $object_id, $meta_key ) {
43
  // Check if excluded meta key or starts with _.
44
  if ( '_' === substr( $meta_key, 0, 1 ) ) {
45
  /**
55
  }
56
 
57
  return false;
58
+ } elseif ( $this->is_excluded_custom_fields( $object_type, $meta_key ) ) {
59
  return false;
60
  } else {
61
  return true;
69
  *
70
  * @return array $editor_link - Name and value link
71
  */
72
+ protected function get_editor_link( $post ) {
73
  $post_id = is_int( $post ) ? intval( $post ) : $post->ID;
74
  return array(
75
  'name' => 'EditorLinkPost',
86
  *
87
  * @return boolean is excluded from monitoring true|false
88
  */
89
+ public function is_excluded_custom_fields( $object_type, $custom ) {
90
+ $custom_fields = array();
91
+ if ( 'post' === $object_type ) {
92
+ $custom_fields = $this->plugin->settings()->get_excluded_post_meta_fields();
93
+ } elseif ( 'user' === $object_type ) {
94
+ $custom_fields = $this->plugin->settings()->get_excluded_user_meta_fields();
95
  }
96
 
97
+ if ( in_array( $custom, $custom_fields ) ) { // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
98
  return true;
99
  }
100
 
101
  foreach ( $custom_fields as $field ) {
102
  if ( false !== strpos( $field, '*' ) ) {
103
  // Wildcard str[any_character] when you enter (str*).
104
+ if ( '*' === substr( $field, - 1 ) ) {
105
  $field = rtrim( $field, '*' );
106
  if ( preg_match( "/^$field/", $custom ) ) {
107
  return true;
classes/AbstractSandboxTask.php CHANGED
@@ -1,4 +1,10 @@
1
  <?php
 
 
 
 
 
 
2
  /**
3
  * Abstract Sandbox Task class.
4
  *
@@ -20,17 +26,17 @@ abstract class WSAL_AbstractSandboxTask {
20
  }
21
 
22
  // Set up shutdown handler.
23
- register_shutdown_function( array( $this, 'Shutdown' ) );
24
 
25
  // Run event sequence.
26
- $this->Header();
27
  try {
28
- $this->Execute();
29
  } catch ( Exception $ex ) {
30
- $this->Message( get_class( $ex ) . ' [' . basename( $ex->getFile() ) . ':' . $ex->getLine() . ']: ' . $ex->getMessage() );
31
- $this->Message( $ex->getTraceAsString(), true );
32
  }
33
- $this->Footer();
34
 
35
  // Shutdown.
36
  die();
@@ -39,7 +45,7 @@ abstract class WSAL_AbstractSandboxTask {
39
  /**
40
  * Header.
41
  */
42
- protected function Header() {
43
  echo '<!DOCTYPE html><html><body style="margin: 0; padding: 8px; font: 12px Arial; color: #333;">';
44
  echo '<div style="position: fixed; top: 0; left: 0; right: 0; padding: 8px; background: #F0F0F0;">';
45
  echo ' <div id="bar" style=" border-top: 2px solid #0AE; top: 20px; height: 0; width: 0%;"> </div>';
@@ -58,7 +64,7 @@ abstract class WSAL_AbstractSandboxTask {
58
  /**
59
  * Footer.
60
  */
61
- protected function Footer() {
62
  echo '<div style="display: none;">';
63
  flush();
64
  }
@@ -66,12 +72,12 @@ abstract class WSAL_AbstractSandboxTask {
66
  /**
67
  * Method: Execute.
68
  */
69
- protected abstract function Execute();
70
 
71
  /**
72
  * Method: Shutdown.
73
  */
74
- public function Shutdown() {
75
  echo '</div></body></html>';
76
  flush();
77
  }
@@ -81,7 +87,7 @@ abstract class WSAL_AbstractSandboxTask {
81
  *
82
  * @param mixed $percent - Progress percentage.
83
  */
84
- protected function Progress( $percent ) {
85
  echo '<script>bar.style.width=prg.innerHTML="' . number_format( $percent, 2 ) . '%";</script>';
86
  flush();
87
  }
@@ -91,8 +97,10 @@ abstract class WSAL_AbstractSandboxTask {
91
  *
92
  * @param string $message - Message.
93
  * @param bool $sticky - True if sticky.
 
 
94
  */
95
- protected function Message( $message, $sticky = false ) {
96
  if ( $sticky ) {
97
  echo '<script>msgs.appendChild(document.createTextNode(' . json_encode( $message . PHP_EOL ) . ')); window.scroll(0, document.body.scrollHeight);</script>';
98
  } else {
1
  <?php
2
+ /**
3
+ * WSAL_AbstractSandboxTask class.
4
+ *
5
+ * @package wsal
6
+ */
7
+
8
  /**
9
  * Abstract Sandbox Task class.
10
  *
26
  }
27
 
28
  // Set up shutdown handler.
29
+ register_shutdown_function( array( $this, 'shutdown' ) );
30
 
31
  // Run event sequence.
32
+ $this->header();
33
  try {
34
+ $this->execute();
35
  } catch ( Exception $ex ) {
36
+ $this->message( get_class( $ex ) . ' [' . basename( $ex->getFile() ) . ':' . $ex->getLine() . ']: ' . $ex->getMessage() );
37
+ $this->message( $ex->getTraceAsString(), true );
38
  }
39
+ $this->footer();
40
 
41
  // Shutdown.
42
  die();
45
  /**
46
  * Header.
47
  */
48
+ protected function header() {
49
  echo '<!DOCTYPE html><html><body style="margin: 0; padding: 8px; font: 12px Arial; color: #333;">';
50
  echo '<div style="position: fixed; top: 0; left: 0; right: 0; padding: 8px; background: #F0F0F0;">';
51
  echo ' <div id="bar" style=" border-top: 2px solid #0AE; top: 20px; height: 0; width: 0%;"> </div>';
64
  /**
65
  * Footer.
66
  */
67
+ protected function footer() {
68
  echo '<div style="display: none;">';
69
  flush();
70
  }
72
  /**
73
  * Method: Execute.
74
  */
75
+ abstract protected function execute();
76
 
77
  /**
78
  * Method: Shutdown.
79
  */
80
+ public function shutdown() {
81
  echo '</div></body></html>';
82
  flush();
83
  }
87
  *
88
  * @param mixed $percent - Progress percentage.
89
  */
90
+ protected function progress( $percent ) {
91
  echo '<script>bar.style.width=prg.innerHTML="' . number_format( $percent, 2 ) . '%";</script>';
92
  flush();
93
  }
97
  *
98
  * @param string $message - Message.
99
  * @param bool $sticky - True if sticky.
100
+ *
101
+ * @phpcs:disable WordPress.WP.AlternativeFunctions.json_encode_json_encode
102
  */
103
+ protected function message( $message, $sticky = false ) {
104
  if ( $sticky ) {
105
  echo '<script>msgs.appendChild(document.createTextNode(' . json_encode( $message . PHP_EOL ) . ')); window.scroll(0, document.body.scrollHeight);</script>';
106
  } else {
classes/AbstractSensor.php CHANGED
@@ -4,8 +4,9 @@
4
  *
5
  * Abstract sensor class file.
6
  *
7
- * @since 1.0.0
8
- * @package wsal
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -16,8 +17,9 @@ if ( ! defined( 'ABSPATH' ) ) {
16
  /**
17
  * Abstract class used in all the sensors.
18
  *
19
- * @see Sensors/*.php
20
- * @package wsal
 
21
  */
22
  abstract class WSAL_AbstractSensor {
23
 
@@ -42,14 +44,17 @@ abstract class WSAL_AbstractSensor {
42
  *
43
  * @return boolean
44
  */
45
- protected function IsMultisite() {
46
- return $this->plugin->IsMultisite();
47
  }
48
 
49
  /**
50
  * Method: Hook events related to sensor.
51
  */
52
- abstract function HookEvents();
 
 
 
53
 
54
  /**
55
  * Method: Log the message for sensor.
@@ -58,13 +63,13 @@ abstract class WSAL_AbstractSensor {
58
  * @param string $message - Alert message.
59
  * @param mixed $args - Message arguments.
60
  */
61
- protected function Log( $type, $message, $args ) {
62
- $this->plugin->alerts->Trigger(
63
  $type,
64
  array(
65
  'Message' => $message,
66
  'Context' => $args,
67
- 'Trace' => debug_backtrace(),
68
  )
69
  );
70
  }
@@ -75,8 +80,8 @@ abstract class WSAL_AbstractSensor {
75
  * @param string $message - Alert message.
76
  * @param mixed $args - Message arguments.
77
  */
78
- protected function LogError( $message, $args ) {
79
- $this->Log( 0001, $message, $args );
80
  }
81
 
82
  /**
@@ -85,8 +90,8 @@ abstract class WSAL_AbstractSensor {
85
  * @param string $message - Alert message.
86
  * @param mixed $args - Message arguments.
87
  */
88
- protected function LogWarn( $message, $args ) {
89
- $this->Log( 0002, $message, $args );
90
  }
91
 
92
  /**
@@ -95,28 +100,16 @@ abstract class WSAL_AbstractSensor {
95
  * @param string $message - Alert message.
96
  * @param mixed $args - Message arguments.
97
  */
98
- protected function LogInfo( $message, $args ) {
99
- $this->Log( 0003, $message, $args );
100
  }
101
 
102
  /**
103
- * Check to see whether or not the specified directory is accessible.
104
  *
105
- * @param string $dir_path - Directory path.
106
  *
107
- * @return boolean
108
  */
109
- protected function CheckDirectory( $dir_path ) {
110
- if ( ! is_dir( $dir_path ) ) {
111
- return false;
112
- }
113
- if ( ! is_readable( $dir_path ) ) {
114
- return false;
115
- }
116
- if ( ! is_writable( $dir_path ) ) {
117
- return false;
118
- }
119
-
120
- return true;
121
- }
122
  }
4
  *
5
  * Abstract sensor class file.
6
  *
7
+ * @since 1.0.0
8
+ * @package wsal
9
+ * @subpackage sensors
10
  */
11
 
12
  // Exit if accessed directly.
17
  /**
18
  * Abstract class used in all the sensors.
19
  *
20
+ * @see Sensors/*.php
21
+ * @package wsal
22
+ * @subpackage sensors
23
  */
24
  abstract class WSAL_AbstractSensor {
25
 
44
  *
45
  * @return boolean
46
  */
47
+ protected function is_multisite() {
48
+ return $this->plugin->is_multisite();
49
  }
50
 
51
  /**
52
  * Method: Hook events related to sensor.
53
  */
54
+ public function hook_events() {
55
+ // We call the deprecated function for backwards compatibility.
56
+ $this->HookEvents();
57
+ }
58
 
59
  /**
60
  * Method: Log the message for sensor.
63
  * @param string $message - Alert message.
64
  * @param mixed $args - Message arguments.
65
  */
66
+ protected function log( $type, $message, $args ) {
67
+ $this->plugin->alerts->trigger_event(
68
  $type,
69
  array(
70
  'Message' => $message,
71
  'Context' => $args,
72
+ 'Trace' => debug_backtrace(), // phpcs:ignore
73
  )
74
  );
75
  }
80
  * @param string $message - Alert message.
81
  * @param mixed $args - Message arguments.
82
  */
83
+ protected function log_error( $message, $args ) {
84
+ $this->log( 0001, $message, $args );
85
  }
86
 
87
  /**
90
  * @param string $message - Alert message.
91
  * @param mixed $args - Message arguments.
92
  */
93
+ protected function log_warn( $message, $args ) {
94
+ $this->log( 0002, $message, $args );
95
  }
96
 
97
  /**
100
  * @param string $message - Alert message.
101
  * @param mixed $args - Message arguments.
102
  */
103
+ protected function log_info( $message, $args ) {
104
+ $this->log( 0003, $message, $args );
105
  }
106
 
107
  /**
108
+ * Deprecated placeholder function.
109
  *
110
+ * @see WSAL_AbstractSensor::hook_events()
111
  *
112
+ * @deprecated 4.4.1 Replaced by function hook_events.
113
  */
114
+ public function HookEvents() {}
 
 
 
 
 
 
 
 
 
 
 
 
115
  }
classes/AbstractView.php CHANGED
@@ -1,9 +1,22 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
2
  /**
3
  * Abstract class used in all the views.
4
  *
5
- * @see Views/*.php
6
- * @package wsal
 
7
  */
8
  abstract class WSAL_AbstractView {
9
 
@@ -12,14 +25,14 @@ abstract class WSAL_AbstractView {
12
  *
13
  * @var WpSecurityAuditLog
14
  */
15
- protected $_plugin;
16
 
17
  /**
18
  * WordPress version.
19
  *
20
  * @var string
21
  */
22
- protected $_wpversion;
23
 
24
  /**
25
  * Contains the result to a call to add_submenu_page().
@@ -40,25 +53,25 @@ abstract class WSAL_AbstractView {
40
  *
41
  * @var array
42
  */
43
- public static $AllowedNoticeNames = array();
44
 
45
  /**
46
  * Method: Constructor.
47
  *
48
- * @param object $plugin - Instance of WpSecurityAuditLog.
49
  */
50
  public function __construct( WpSecurityAuditLog $plugin ) {
51
- $this->_plugin = $plugin;
52
 
53
  // Get and store WordPress version.
54
  global $wp_version;
55
  if ( ! isset( $wp_version ) ) {
56
- $wp_version = get_bloginfo( 'version' );
57
  }
58
- $this->_wpversion = floatval( $wp_version );
59
 
60
  // Handle admin notices.
61
- add_action( 'wp_ajax_AjaxDismissNotice', array( $this, 'AjaxDismissNotice' ) );
62
  }
63
 
64
  /**
@@ -66,8 +79,8 @@ abstract class WSAL_AbstractView {
66
  *
67
  * @internal
68
  */
69
- public function AjaxDismissNotice() {
70
- if ( ! $this->_plugin->settings()->CurrentUserCan( 'view' ) ) {
71
  die( 'Access Denied.' );
72
  }
73
 
@@ -78,7 +91,7 @@ abstract class WSAL_AbstractView {
78
  die( 'Notice name expected as "notice" parameter.' );
79
  }
80
 
81
- $this->DismissNotice( $post_array['notice'] );
82
  }
83
 
84
  /**
@@ -87,11 +100,11 @@ abstract class WSAL_AbstractView {
87
  * @param string $name — Name of notice.
88
  * @return boolean — Whether notice got dismissed or not.
89
  */
90
- public function IsNoticeDismissed( $name ) {
91
  $user_id = get_current_user_id();
92
  $meta_key = 'wsal-notice-' . $name;
93
 
94
- self::$AllowedNoticeNames[] = $name;
95
  return get_user_meta( $user_id, $meta_key, true );
96
  }
97
 
@@ -100,11 +113,11 @@ abstract class WSAL_AbstractView {
100
  *
101
  * @param string $name — Name of notice to dismiss.
102
  */
103
- public function DismissNotice( $name ) {
104
  $user_id = get_current_user_id();
105
  $meta_key = 'wsal-notice-' . $name;
106
  $old_value = get_user_meta( $user_id, $meta_key, true );
107
- if ( in_array( $name, self::$AllowedNoticeNames ) || false === $old_value || empty( $old_value ) ) {
108
  update_user_meta( $user_id, $meta_key, '1' );
109
  }
110
  }
@@ -114,8 +127,8 @@ abstract class WSAL_AbstractView {
114
  *
115
  * @param string $name — Makes this notice available.
116
  */
117
- public function RegisterNotice( $name ) {
118
- self::$AllowedNoticeNames[] = $name;
119
  }
120
 
121
  /**
@@ -123,38 +136,38 @@ abstract class WSAL_AbstractView {
123
  *
124
  * @return string
125
  */
126
- abstract public function GetName();
127
 
128
  /**
129
  * Method: Return page title.
130
  *
131
  * @return string
132
  */
133
- abstract public function GetTitle();
134
 
135
  /**
136
  * Method: Page icon name.
137
  *
138
  * @return string
139
  */
140
- abstract public function GetIcon();
141
 
142
  /**
143
  * Method: Menu weight, the higher this is, the lower it goes.
144
  *
145
  * @return int
146
  */
147
- abstract public function GetWeight();
148
 
149
  /**
150
  * Renders and outputs the view directly.
151
  */
152
- abstract public function Render();
153
 
154
  /**
155
  * Renders the view icon (this has been deprecated in newwer WP versions).
156
  */
157
- public function RenderIcon() {
158
  ?>
159
  <div id="icon-plugins" class="icon32"><br></div>
160
  <?php
@@ -163,19 +176,19 @@ abstract class WSAL_AbstractView {
163
  /**
164
  * Renders the view title.
165
  */
166
- public function RenderTitle() {
167
  if ( $this->is_title_visible() ) {
168
- echo '<h2>' . esc_html( $this->GetTitle() ) . '</h2>';
169
  }
170
  }
171
 
172
  /**
173
  * Method: Render content of the view.
174
  *
175
- * @link self::Render()
176
  */
177
- public function RenderContent() {
178
- $this->Render();
179
  }
180
 
181
  /**
@@ -183,7 +196,7 @@ abstract class WSAL_AbstractView {
183
  *
184
  * @return boolean
185
  */
186
- public function IsVisible() {
187
  return true;
188
  }
189
 
@@ -192,7 +205,7 @@ abstract class WSAL_AbstractView {
192
  *
193
  * @return boolean
194
  */
195
- public function IsAccessible() {
196
  return true;
197
  }
198
 
@@ -208,20 +221,20 @@ abstract class WSAL_AbstractView {
208
  /**
209
  * Used for rendering stuff into head tag.
210
  */
211
- public function Header() {}
212
 
213
  /**
214
- * Used for rendering stuff in page fotoer.
215
  */
216
- public function Footer() {}
217
 
218
  /**
219
  * Method: Safe view menu name.
220
  *
221
  * @return string
222
  */
223
- public function GetSafeViewName() {
224
- return 'wsal-' . preg_replace( '/[^A-Za-z0-9\-]/', '-', $this->GetViewName() );
225
  }
226
 
227
  /**
@@ -229,7 +242,7 @@ abstract class WSAL_AbstractView {
229
  *
230
  * @return boolean
231
  */
232
- public function HasPluginShortcutLink() {
233
  return false;
234
  }
235
 
@@ -238,9 +251,9 @@ abstract class WSAL_AbstractView {
238
  *
239
  * @return string
240
  */
241
- public function GetUrl() {
242
  $fn = function_exists( 'network_admin_url' ) ? 'network_admin_url' : 'admin_url';
243
- return $fn( 'admin.php?page=' . $this->GetSafeViewName() );
244
  }
245
 
246
  /**
@@ -248,7 +261,7 @@ abstract class WSAL_AbstractView {
248
  *
249
  * @return string
250
  */
251
- public function GetViewName() {
252
  return strtolower( str_replace( array( 'WSAL_Views_', 'WSAL_' ), '', get_class( $this ) ) );
253
  }
254
 
1
  <?php
2
+ /**
3
+ * Abstract view class file.
4
+ *
5
+ * @package wsal
6
+ * @subpackage views
7
+ */
8
+
9
+ // Exit if accessed directly.
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
+
14
  /**
15
  * Abstract class used in all the views.
16
  *
17
+ * @see Views/*.php
18
+ * @package wsal
19
+ * @subpackage views
20
  */
21
  abstract class WSAL_AbstractView {
22
 
25
  *
26
  * @var WpSecurityAuditLog
27
  */
28
+ protected $plugin;
29
 
30
  /**
31
  * WordPress version.
32
  *
33
  * @var string
34
  */
35
+ protected $wp_version;
36
 
37
  /**
38
  * Contains the result to a call to add_submenu_page().
53
  *
54
  * @var array
55
  */
56
+ public static $allowed_notice_names = array();
57
 
58
  /**
59
  * Method: Constructor.
60
  *
61
+ * @param WpSecurityAuditLog $plugin - Instance of WpSecurityAuditLog.
62
  */
63
  public function __construct( WpSecurityAuditLog $plugin ) {
64
+ $this->plugin = $plugin;
65
 
66
  // Get and store WordPress version.
67
  global $wp_version;
68
  if ( ! isset( $wp_version ) ) {
69
+ $wp_version = get_bloginfo( 'version' ); // phpcs:ignore
70
  }
71
+ $this->wp_version = floatval( $wp_version );
72
 
73
  // Handle admin notices.
74
+ add_action( 'wp_ajax_AjaxDismissNotice', array( $this, 'ajax_dismiss_notice' ) );
75
  }
76
 
77
  /**
79
  *
80
  * @internal
81
  */
82
+ public function ajax_dismiss_notice() {
83
+ if ( ! $this->plugin->settings()->current_user_can( 'view' ) ) {
84
  die( 'Access Denied.' );
85
  }
86
 
91
  die( 'Notice name expected as "notice" parameter.' );
92
  }
93
 
94
+ $this->dismiss_notice( $post_array['notice'] );
95
  }
96
 
97
  /**
100
  * @param string $name — Name of notice.
101
  * @return boolean — Whether notice got dismissed or not.
102
  */
103
+ public function is_notice_dismissed( $name ) {
104
  $user_id = get_current_user_id();
105
  $meta_key = 'wsal-notice-' . $name;
106
 
107
+ self::$allowed_notice_names[] = $name;
108
  return get_user_meta( $user_id, $meta_key, true );
109
  }
110
 
113
  *
114
  * @param string $name — Name of notice to dismiss.
115
  */
116
+ public function dismiss_notice( $name ) {
117
  $user_id = get_current_user_id();
118
  $meta_key = 'wsal-notice-' . $name;
119
  $old_value = get_user_meta( $user_id, $meta_key, true );
120
+ if ( in_array( $name, self::$allowed_notice_names ) || false === $old_value || empty( $old_value ) ) { // phpcs:ignore
121
  update_user_meta( $user_id, $meta_key, '1' );
122
  }
123
  }
127
  *
128
  * @param string $name — Makes this notice available.
129
  */
130
+ public function register_notice( $name ) {
131
+ self::$allowed_notice_names[] = $name;
132
  }
133
 
134
  /**
136
  *
137
  * @return string
138
  */
139
+ abstract public function get_name();
140
 
141
  /**
142
  * Method: Return page title.
143
  *
144
  * @return string
145
  */
146
+ abstract public function get_title();
147
 
148
  /**
149
  * Method: Page icon name.
150
  *
151
  * @return string
152
  */
153
+ abstract public function get_icon();
154
 
155
  /**
156
  * Method: Menu weight, the higher this is, the lower it goes.
157
  *
158
  * @return int
159
  */
160
+ abstract public function get_weight();
161
 
162
  /**
163
  * Renders and outputs the view directly.
164
  */
165
+ abstract public function render();
166
 
167
  /**
168
  * Renders the view icon (this has been deprecated in newwer WP versions).
169
  */
170
+ public function render_icon() {
171
  ?>
172
  <div id="icon-plugins" class="icon32"><br></div>
173
  <?php
176
  /**
177
  * Renders the view title.
178
  */
179
+ public function render_title() {
180
  if ( $this->is_title_visible() ) {
181
+ echo '<h2>' . esc_html( $this->get_title() ) . '</h2>';
182
  }
183
  }
184
 
185
  /**
186
  * Method: Render content of the view.
187
  *
188
+ * @see WSAL_AbstractView::render()
189
  */
190
+ public function render_content() {
191
+ $this->render();
192
  }
193
 
194
  /**
196
  *
197
  * @return boolean
198
  */
199
+ public function is_visible() {
200
  return true;
201
  }
202
 
205
  *
206
  * @return boolean
207
  */
208
+ public function is_accessible() {
209
  return true;
210
  }
211
 
221
  /**
222
  * Used for rendering stuff into head tag.
223
  */
224
+ public function header() {}
225
 
226
  /**
227
+ * Used for rendering stuff in page footer.
228
  */
229
+ public function footer() {}
230
 
231
  /**
232
  * Method: Safe view menu name.
233
  *
234
  * @return string
235
  */
236
+ public function get_safe_view_name() {
237
+ return 'wsal-' . preg_replace( '/[^A-Za-z0-9\-]/', '-', $this->get_view_name() );
238
  }
239
 
240
  /**
242
  *
243
  * @return boolean
244
  */
245
+ public function has_plugin_shortcut_link() {
246
  return false;
247
  }
248
 
251
  *
252
  * @return string
253
  */
254
+ public function get_url() {
255
  $fn = function_exists( 'network_admin_url' ) ? 'network_admin_url' : 'admin_url';
256
+ return $fn( 'admin.php?page=' . $this->get_safe_view_name() );
257
  }
258
 
259
  /**
261
  *
262
  * @return string
263
  */
264
+ public function get_view_name() {
265
  return strtolower( str_replace( array( 'WSAL_Views_', 'WSAL_' ), '', get_class( $this ) ) );
266
  }
267
 
classes/Adapters/ActiveRecordInterface.php CHANGED
@@ -25,17 +25,17 @@ interface WSAL_Adapters_ActiveRecordInterface {
25
  * @deprecated
26
  * @return boolean
27
  */
28
- public function IsInstalled();
29
 
30
  /**
31
  * Install this ActiveRecord structure into DB.
32
  */
33
- public function Install();
34
 
35
  /**
36
  * Remove this ActiveRecord structure from DB.
37
  */
38
- public function Uninstall();
39
 
40
  /**
41
  * Load.
@@ -43,33 +43,35 @@ interface WSAL_Adapters_ActiveRecordInterface {
43
  * @param string $cond - Query Condition.
44
  * @param array $args - Query arguments.
45
  */
46
- public function Load( $cond = '%d', $args = array( 1 ) );
47
 
48
  /**
49
  * Save an active record into DB.
50
  *
51
- * @param object $active_record - ActiveRecord object.
 
52
  * @return integer|boolean - Either the number of modified/inserted rows or false on failure.
53
  */
54
- public function Save( $activeRecord );
55
 
56
  /**
57
  * Delete DB record.
58
  *
59
- * @param object $active_record - ActiveRecord object.
 
60
  * @return int|boolean - Either the amount of deleted rows or False on error.
61
  */
62
- public function Delete( $activeRecord );
63
 
64
  /**
65
  * Load multiple records from DB.
66
  *
67
  * @param string $cond (Optional) Load condition (eg: 'some_id = %d' ).
68
- * @param array $args (Optional) Load condition arguments (rg: array(45) ).
69
  *
70
  * @return self[] List of loaded records.
71
  */
72
- public function LoadMulti( $cond, $args = array() );
73
 
74
  /**
75
  * Load multiple records from DB and call a callback for each record.
@@ -79,7 +81,7 @@ interface WSAL_Adapters_ActiveRecordInterface {
79
  * @param string $cond (Optional) Load condition.
80
  * @param array $args (Optional) Load condition arguments.
81
  */
82
- public function LoadAndCallForEach( $callback, $cond = '%d', $args = array( 1 ) );
83
 
84
  /**
85
  * Count records in the DB matching a condition.
@@ -89,23 +91,23 @@ interface WSAL_Adapters_ActiveRecordInterface {
89
  * @param array $args (Optional) Condition arguments.
90
  * @return int Number of matching records.
91
  */
92
- public function Count( $cond = '%d', $args = array( 1 ) );
93
 
94
  /**
95
  * Similar to LoadMulti but allows the use of a full SQL query.
96
  *
97
  * @param string $query Full SQL query.
98
- * @param array $args (Optional) Query arguments.
99
  *
100
  * @return array List of loaded records.
101
  * @throws Exception
102
  */
103
- public function LoadMultiQuery( $query, $args = array() );
104
 
105
  /**
106
  * Returns the model class for adapter.
107
  *
108
  * @return WSAL_Models_ActiveRecord
109
  */
110
- public function GetModel();
111
  }
25
  * @deprecated
26
  * @return boolean
27
  */
28
+ public function is_installed();
29
 
30
  /**
31
  * Install this ActiveRecord structure into DB.
32
  */
33
+ public function install();
34
 
35
  /**
36
  * Remove this ActiveRecord structure from DB.
37
  */
38
+ public function uninstall();
39
 
40
  /**
41
  * Load.
43
  * @param string $cond - Query Condition.
44
  * @param array $args - Query arguments.
45
  */
46
+ public function load( $cond = '%d', $args = array( 1 ) );
47
 
48
  /**
49
  * Save an active record into DB.
50
  *
51
+ * @param WSAL_Models_ActiveRecord $active_record - ActiveRecord object.
52
+ *
53
  * @return integer|boolean - Either the number of modified/inserted rows or false on failure.
54
  */
55
+ public function save( $active_record );
56
 
57
  /**
58
  * Delete DB record.
59
  *
60
+ * @param WSAL_Models_ActiveRecord $active_record - ActiveRecord object.
61
+ *
62
  * @return int|boolean - Either the amount of deleted rows or False on error.
63
  */
64
+ public function delete( $active_record );
65
 
66
  /**
67
  * Load multiple records from DB.
68
  *
69
  * @param string $cond (Optional) Load condition (eg: 'some_id = %d' ).
70
+ * @param array $args (Optional) Load condition arguments (rg: array(45) ).
71
  *
72
  * @return self[] List of loaded records.
73
  */
74
+ public function load_multi( $cond, $args = array() );
75
 
76
  /**
77
  * Load multiple records from DB and call a callback for each record.
81
  * @param string $cond (Optional) Load condition.
82
  * @param array $args (Optional) Load condition arguments.
83
  */
84
+ public function load_and_call_for_each( $callback, $cond = '%d', $args = array( 1 ) );
85
 
86
  /**
87
  * Count records in the DB matching a condition.
91
  * @param array $args (Optional) Condition arguments.
92
  * @return int Number of matching records.
93
  */
94
+ public function count( $cond = '%d', $args = array( 1 ) );
95
 
96
  /**
97
  * Similar to LoadMulti but allows the use of a full SQL query.
98
  *
99
  * @param string $query Full SQL query.
100
+ * @param array $args (Optional) Query arguments.
101
  *
102
  * @return array List of loaded records.
103
  * @throws Exception
104
  */
105
+ public function load_multi_query( $query, $args = array() );
106
 
107
  /**
108
  * Returns the model class for adapter.
109
  *
110
  * @return WSAL_Models_ActiveRecord
111
  */
112
+ public function get_model();
113
  }
classes/Adapters/MetaInterface.php CHANGED
@@ -24,7 +24,7 @@ interface WSAL_Adapters_MetaInterface {
24
  *
25
  * @param int[] $occurrence_ids - Array of occurrence IDs.
26
  */
27
- public function DeleteByOccurrenceIds( $occurrence_ids );
28
 
29
  /**
30
  * Load meta by name and occurrence id.
@@ -32,5 +32,5 @@ interface WSAL_Adapters_MetaInterface {
32
  * @param string $meta_name - Meta name.
33
  * @param int $occurrence_id - Occurrence ID.
34
  */
35
- public function LoadByNameAndOccurrenceId( $meta_name, $occurrence_id );
36
  }
24
  *
25
  * @param int[] $occurrence_ids - Array of occurrence IDs.
26
  */
27
+ public function delete_by_occurrence_ids( $occurrence_ids );
28
 
29
  /**
30
  * Load meta by name and occurrence id.
32
  * @param string $meta_name - Meta name.
33
  * @param int $occurrence_id - Occurrence ID.
34
  */
35
+ public function load_by_name_and_occurrence_id( $meta_name, $occurrence_id );
36
  }
classes/Adapters/MySQL/ActiveRecordAdapter.php CHANGED
@@ -36,21 +36,21 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
36
  *
37
  * @var string
38
  */
39
- protected $_table;
40
 
41
  /**
42
  * Contains primary key column name, override as required.
43
  *
44
  * @var string
45
  */
46
- protected $_idkey = '';
47
 
48
  /**
49
  * Local cache for a list of columns.
50
  *
51
  * @var string[]
52
  */
53
- protected $_column_cache = [];
54
 
55
  /**
56
  * Method: Constructor.
@@ -125,18 +125,18 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
125
  *
126
  * @return string Returns table name of WordPress.
127
  */
128
- public function GetWPTable() {
129
  global $wpdb;
130
 
131
- return $wpdb->base_prefix . $this->_table;
132
  }
133
 
134
  /**
135
- * @inheritDoc
136
  */
137
- public function Install() {
138
  $_wpdb = $this->connection;
139
- $_wpdb->query( $this->_GetInstallQuery() );
140
  }
141
 
142
  /**
@@ -146,18 +146,18 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
146
  *
147
  * @return string - Must return SQL for creating table.
148
  */
149
- protected function _GetInstallQuery( $prefix = false ) {
150
  $_wpdb = $this->connection;
151
  $class = get_class( $this );
152
  $copy = new $class( $this->connection );
153
- $table_name = $this->GetTable();
154
  $sql = 'CREATE TABLE IF NOT EXISTS ' . $table_name . ' (' . PHP_EOL;
155
- $cols = $this->GetColumns();
156
  foreach ( $cols as $key ) {
157
- $sql .= $this->_GetSqlColumnDefinition( $copy, $key );
158
  }
159
 
160
- $sql .= $this->GetTableOptions() . PHP_EOL;
161
  $sql .= ') ' . $_wpdb->get_charset_collate();
162
 
163
  return $sql;
@@ -168,10 +168,10 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
168
  *
169
  * @return string
170
  */
171
- public function GetTable() {
172
  $_wpdb = $this->connection;
173
 
174
- return $_wpdb->base_prefix . $this->_table;
175
  }
176
 
177
  /**
@@ -179,40 +179,40 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
179
  *
180
  * @return array
181
  */
182
- public function GetColumns() {
183
- $model = $this->GetModel();
184
 
185
- if ( empty( $this->_column_cache ) ) {
186
- $this->_column_cache = array();
187
  foreach ( array_keys( get_object_vars( $model ) ) as $col ) {
188
- if ( trim( $col ) && $col[0] != '_' ) {
189
- $this->_column_cache[] = $col;
190
  }
191
  }
192
  }
193
 
194
- return $this->_column_cache;
195
  }
196
 
197
  /**
198
- * @inheritDoc
199
  */
200
- public function GetModel() {
201
  return new WSAL_Models_Query();
202
  }
203
 
204
  /**
205
  * Generate SQL column definition string for the CREATE TABLE statement.
206
  *
207
- * @param object $copy
208
- * @param string $key
209
  *
210
  * @return string
211
  */
212
- protected function _GetSqlColumnDefinition( $copy, $key ) {
213
  $result = ' ';
214
  switch ( true ) {
215
- case ( $key === $this->_idkey ):
216
  $result .= $key . ' BIGINT NOT NULL AUTO_INCREMENT,' . PHP_EOL;
217
  break;
218
  case is_int( $copy->$key ):
@@ -238,7 +238,7 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
238
  $result .= $key . ' LONGTEXT NOT NULL,' . PHP_EOL;
239
  break;
240
  default:
241
- // fallback for any other columns would go here
242
  break;
243
  }
244
 
@@ -250,27 +250,27 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
250
  *
251
  * @return string
252
  */
253
- protected function GetTableOptions() {
254
- return ' PRIMARY KEY (' . $this->_idkey . ')';
255
  }
256
 
257
  /**
258
  * Install this ActiveRecord structure into DB WordPress.
259
  */
260
- public function InstallOriginal() {
261
  global $wpdb;
262
- $wpdb->query( $this->_GetInstallQuery( true ) );
263
  }
264
 
265
  /**
266
- * @inheritDoc
267
  */
268
- public function Uninstall() {
269
  $_wpdb = $this->connection;
270
 
271
  // Check if table exists.
272
  if ( $this->table_exists() ) {
273
- $_wpdb->query( $this->_GetUninstallQuery() );
274
  }
275
  }
276
 
@@ -283,7 +283,7 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
283
  $_wpdb = $this->connection;
284
 
285
  // Query table exists.
286
- $table_exists_query = "SHOW TABLES LIKE '" . $this->GetTable() . "'";
287
 
288
  return $_wpdb->query( $table_exists_query );
289
  }
@@ -293,23 +293,23 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
293
  *
294
  * @return string
295
  */
296
- protected function _GetUninstallQuery() {
297
- return 'DROP TABLE IF EXISTS ' . $this->GetTable();
298
  }
299
 
300
  /**
301
- * @inheritDoc
302
  */
303
- public function Save( $active_record ) {
304
  $_wpdb = $this->connection;
305
  $copy = $active_record;
306
  $data = array();
307
  $format = array();
308
 
309
- $columns = $this->GetColumns();
310
  foreach ( $columns as $index => $key ) {
311
- if ( $key == $this->_idkey ) {
312
- $_id_index = $index;
313
  }
314
 
315
  $val = $copy->$key;
@@ -323,7 +323,7 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
323
  }
324
 
325
  if ( is_array( $copy->$key ) || is_object( $copy->$key ) ) {
326
- $data[ $key ] = WSAL_Helpers_DataHelper::JsonEncode( $val );
327
  } else {
328
  $data[ $key ] = $val;
329
  }
@@ -331,15 +331,15 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
331
  $format[] = $deffmt;
332
  }
333
 
334
- if ( isset( $data[ $this->_idkey ] ) && empty( $data[ $this->_idkey ] ) ) {
335
- unset( $data[ $this->_idkey ] );
336
- unset( $format[ $_id_index ] );
337
  }
338
 
339
- $result = $_wpdb->replace( $this->GetTable(), $data, $format );
340
 
341
  if ( false !== $result && $_wpdb->insert_id ) {
342
- $copy->setId( $_wpdb->insert_id );
343
  }
344
 
345
  return $result;
@@ -353,9 +353,9 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
353
  *
354
  * @return array
355
  */
356
- public function Load( $cond = '%d', $args = array( 1 ) ) {
357
  $_wpdb = $this->connection;
358
- $sql = $_wpdb->prepare( 'SELECT * FROM ' . $this->GetTable() . ' WHERE ' . $cond, $args );
359
 
360
  return $_wpdb->get_row( $sql, ARRAY_A );
361
  }
@@ -367,29 +367,28 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
367
  * @param array $args (Optional) Load condition arguments.
368
  *
369
  * @return array
370
- * @throws Exception
371
  */
372
- public function LoadArray( $cond, $args = array() ) {
373
  $_wpdb = $this->connection;
374
  $result = array();
375
- $sql = $_wpdb->prepare( 'SELECT * FROM ' . $this->GetTable() . ' WHERE ' . $cond, $args );
376
  foreach ( $_wpdb->get_results( $sql, ARRAY_A ) as $data ) {
377
- $result[] = $this->getModel()->LoadData( $data );
378
  }
379
 
380
  return $result;
381
  }
382
 
383
  /**
384
- * @inheritDoc
385
  */
386
- public function Delete( $active_record ) {
387
  $_wpdb = $this->connection;
388
 
389
  return $_wpdb->delete(
390
- $this->GetTable(),
391
  array(
392
- $this->_idkey => $active_record->getId(),
393
  ),
394
  array( '%d' )
395
  );
@@ -403,7 +402,7 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
403
  *
404
  * @return int|bool
405
  */
406
- public function DeleteQuery( $query, $args = array() ) {
407
  $_wpdb = $this->connection;
408
  $sql = count( $args ) ? $_wpdb->prepare( $query, $args ) : $query;
409
 
@@ -411,39 +410,39 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
411
  }
412
 
413
  /**
414
- * @inheritDoc
415
  */
416
- public function LoadMulti( $cond, $args = array() ) {
417
  $_wpdb = $this->connection;
418
  $result = array();
419
  $sql = ( ! is_array( $args ) || ! count( $args ) ) // Do we really need to prepare() or not?
420
  ? ( $cond )
421
  : $_wpdb->prepare( $cond, $args );
422
  foreach ( $_wpdb->get_results( $sql, ARRAY_A ) as $data ) {
423
- $result[] = $this->getModel()->LoadData( $data );
424
  }
425
 
426
  return $result;
427
  }
428
 
429
  /**
430
- * @inheritDoc
431
  */
432
- public function LoadAndCallForEach( $callback, $cond = '%d', $args = array( 1 ) ) {
433
  $_wpdb = $this->connection;
434
  $class = get_called_class();
435
- $sql = $_wpdb->prepare( 'SELECT * FROM ' . $this->GetTable() . ' WHERE ' . $cond, $args );
436
  foreach ( $_wpdb->get_results( $sql, ARRAY_A ) as $data ) {
437
  call_user_func( $callback, new $class( $data ) );
438
  }
439
  }
440
 
441
  /**
442
- * @inheritDoc
443
  */
444
- public function Count( $cond = '%d', $args = array( 1 ) ) {
445
  $_wpdb = $this->connection;
446
- $sql = $_wpdb->prepare( 'SELECT COUNT(*) FROM ' . $this->GetTable() . ' WHERE ' . $cond, $args );
447
 
448
  return (int) $_wpdb->get_var( $sql );
449
  }
@@ -456,7 +455,7 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
456
  *
457
  * @return int Number of matching records.
458
  */
459
- public function CountQuery( $query, $args = array() ) {
460
  $_wpdb = $this->connection;
461
  $sql = count( $args ) ? $_wpdb->prepare( $query, $args ) : $query;
462
 
@@ -464,14 +463,14 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
464
  }
465
 
466
  /**
467
- * @inheritDoc
468
  */
469
- public function LoadMultiQuery( $query, $args = array() ) {
470
  $_wpdb = $this->connection;
471
  $result = array();
472
  $sql = count( $args ) ? $_wpdb->prepare( $query, $args ) : $query;
473
  foreach ( $_wpdb->get_results( $sql, ARRAY_A ) as $data ) {
474
- $result[] = $this->getModel()->LoadData( $data );
475
  }
476
 
477
  return $result;
@@ -529,38 +528,38 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
529
  */
530
  private function build_reporting_query( $report_args, $count_only, $grouping = null, $next_date = null, $limit = 0 ) {
531
  $occurrence = new WSAL_Adapters_MySQL_Occurrence( $this->connection );
532
- $table_occ = $occurrence->GetTable();
533
 
534
  if ( $count_only ) {
535
  $select_fields = array( 'COUNT(1) as count' );
536
  $group_by = array( 'occ.id' );
537
  } elseif ( is_null( $grouping ) ) {
538
  $select_fields = array(
539
- "occ.id",
540
- "occ.alert_id",
541
- "occ.site_id",
542
- "occ.created_on",
543
  "replace( replace( replace( occ.user_roles, '[', ''), ']', ''), '\\'', '') AS roles",
544
- "occ.client_ip AS ip",
545
- "occ.user_agent AS ua",
546
- "COALESCE( occ.username, occ.user_id ) as user_id",
547
- "occ.object",
548
- "occ.event_type",
549
- "occ.post_id",
550
- "occ.post_type",
551
- "occ.post_status",
552
  );
553
  } else {
554
  $select_fields = array();
555
  $group_by = array();
556
  foreach ( $grouping as $grouping_item ) {
557
- switch ($grouping_item) {
558
  case 'site':
559
  array_push( $select_fields, 'site_id' );
560
  array_push( $group_by, 'site_id' );
561
  break;
562
  case 'users':
563
- array_push( $select_fields, "COALESCE( occ.username, occ.user_id ) as user" );
564
  array_push( $group_by, 'user' );
565
  break;
566
  case 'posts':
@@ -593,14 +592,17 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
593
  }
594
 
595
  if ( isset( $group_by ) && ! empty( $group_by ) ) {
596
- $sql .= " GROUP BY " . implode( ',', $group_by );
597
- $orderby_parts = array_map( function ( $item ) {
598
- return 'period' === $item ? $item . ' DESC ' : $item . ' ASC ';
599
- }, $group_by );
 
 
 
600
 
601
- $sql .= " ORDER BY " . implode( ',', $orderby_parts );
602
  } else {
603
- $sql .= " ORDER BY created_on DESC ";
604
  }
605
 
606
  if ( ! empty( $limit ) ) {
@@ -621,92 +623,92 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
621
  $_site_id = null;
622
  $sites_negate_expression = '';
623
  if ( $report_args->site__in ) {
624
- $_site_id = $this->formatArrayForQuery( $report_args->site__in );
625
  } elseif ( $report_args->site__not_in ) {
626
- $_site_id = $this->formatArrayForQuery( $report_args->site__not_in );
627
  $sites_negate_expression = 'NOT';
628
  }
629
 
630
  $_user_id = null;
631
  $users_negate_expression = '';
632
  if ( $report_args->user__in ) {
633
- $_user_id = $this->formatArrayForQuery( $report_args->user__in );
634
  } elseif ( $report_args->user__not_in ) {
635
- $_user_id = $this->formatArrayForQuery( $report_args->user__not_in );
636
  $users_negate_expression = 'NOT';
637
  }
638
 
639
- $user_names = $this->GetUserNames( $_user_id );
640
 
641
  $_role_name = null;
642
  $roles_negate_expression = '';
643
  if ( $report_args->role__in ) {
644
- $_role_name = $this->formatArrayForQueryRegex( $report_args->role__in );
645
  } elseif ( $report_args->role__not_in ) {
646
- $_role_name = $this->formatArrayForQueryRegex( $report_args->role__not_in );
647
  $roles_negate_expression = 'NOT';
648
  }
649
 
650
  $_alert_code = null;
651
  $alert_code_negate_expression = '';
652
  if ( $report_args->code__in ) {
653
- $_alert_code = $this->formatArrayForQuery( $report_args->code__in );
654
  } elseif ( $report_args->code__not_in ) {
655
- $_alert_code = $this->formatArrayForQuery( $report_args->code__not_in );
656
  $alert_code_negate_expression = 'NOT';
657
  }
658
 
659
  $_post_ids = null;
660
  $post_ids_negate_expression = '';
661
  if ( $report_args->post__in ) {
662
- $_post_ids = $this->formatArrayForQueryRegex( $report_args->post__in );
663
  } elseif ( $report_args->post__not_in ) {
664
- $_post_ids = $this->formatArrayForQueryRegex( $report_args->post__not_in );
665
  $post_ids_negate_expression = 'NOT';
666
  }
667
 
668
  $_post_types = null;
669
  $post_types_negate_expression = '';
670
  if ( $report_args->post_type__in ) {
671
- $_post_types = $this->formatArrayForQueryRegex( $report_args->post_type__in );
672
  } elseif ( $report_args->post_type__not_in ) {
673
- $_post_types = $this->formatArrayForQueryRegex( $report_args->post_type__not_in );
674
  $post_types_negate_expression = 'NOT';
675
  }
676
 
677
  $_post_statuses = null;
678
  $post_statuses_negate_expression = '';
679
  if ( $report_args->post_status__in ) {
680
- $_post_statuses = $this->formatArrayForQueryRegex( $report_args->post_status__in );
681
- } else if ( $report_args->post_status__not_in ) {
682
- $_post_statuses = $this->formatArrayForQueryRegex( $report_args->post_status__not_in );
683
  $post_statuses_negate_expression = 'NOT';
684
  }
685
 
686
  $_ip_addresses = null;
687
  $ip_addresses_negate_expression = '';
688
  if ( $report_args->ip__in ) {
689
- $_ip_addresses = $this->formatArrayForQuery( $report_args->ip__in );
690
- } else if ( $report_args->ip__not_in ) {
691
- $_ip_addresses = $this->formatArrayForQuery( $report_args->ip__not_in );
692
  $ip_addresses_negate_expression = 'NOT';
693
  }
694
 
695
  $_objects = null;
696
  $objects_negate_expression = '';
697
  if ( $report_args->object__in ) {
698
- $_objects = $this->formatArrayForQuery( $report_args->object__in );
699
  } elseif ( $report_args->object__not_in ) {
700
- $_objects = $this->formatArrayForQuery( $report_args->object__not_in );
701
  $objects_negate_expression = 'NOT';
702
  }
703
 
704
  $_event_types = null;
705
  $event_types_negate_expression = '';
706
  if ( $report_args->type__in ) {
707
- $_event_types = $this->formatArrayForQuery( $report_args->type__in );
708
  } elseif ( $report_args->type__not_in ) {
709
- $_event_types = $this->formatArrayForQuery( $report_args->type__not_in );
710
  $event_types_negate_expression = 'NOT';
711
  }
712
 
@@ -731,7 +733,7 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
731
  array_push( $users_condition_parts, " {$users_negate_expression} replace( occ.username, '\"', '' ) IN ( $user_names ) " );
732
  }
733
 
734
- $where_statement = " WHERE 1 = 1 ";
735
 
736
  if ( ! empty( $users_condition_parts ) ) {
737
  $where_statement .= ' AND ( ' . implode( 'OR', $users_condition_parts ) . ' ) ';
@@ -785,30 +787,32 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
785
  }
786
 
787
  /**
788
- * @param array $data
 
 
789
  *
790
  * @return string
791
  * @since 4.3.2
792
  */
793
- protected function formatArrayForQuery( $data ) {
794
  return "'" . implode( ',', $data ) . "'";
795
  }
796
 
797
  /**
798
  * Get Users user_login.
799
  *
800
- * @param int $_user_id - User ID.
801
  *
802
  * @return string comma separated users login
803
  */
804
- private function GetUserNames( $_user_id ) {
805
  global $wpdb;
806
 
807
  $user_names = null;
808
- if ( ! empty( $_user_id ) && 'null' != $_user_id && ! is_null( $_user_id ) ) {
809
  $sql = 'SELECT user_login FROM ' . $wpdb->users . ' WHERE find_in_set(ID, @userId) > 0';
810
- $wpdb->query( "SET @userId = $_user_id" );
811
- $result = $wpdb->get_results( $sql, ARRAY_A );
812
  $users_array = array();
813
  foreach ( $result as $item ) {
814
  $users_array[] = '"' . $item['user_login'] . '"';
@@ -820,15 +824,17 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
820
  }
821
 
822
  /**
823
- * @param array $data
 
 
824
  *
825
  * @return string
826
  * @since 4.3.2
827
  */
828
- protected function formatArrayForQueryRegex( $data ) {
829
  $result = array();
830
  foreach ( $data as $item ) {
831
- array_push( $result, esc_sql( preg_quote( $item ) ) );
832
  }
833
 
834
  return "'" . implode( '|', $result ) . "'";
@@ -840,9 +846,9 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
840
  *
841
  * @param WSAL_ReportArgs $report_args - Query conditions.
842
  *
843
- * @return int count of distinct values
844
  */
845
- public function CheckMatchReportCriteria( $report_args ) {
846
  $query = $this->build_reporting_query( $report_args, true );
847
 
848
  return (int) $this->connection->get_var( $query );
@@ -864,14 +870,14 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
864
 
865
  // Tables.
866
  $occurrence = new WSAL_Adapters_MySQL_Occurrence( $_wpdb );
867
- $table_occ = $occurrence->GetTable();
868
 
869
  // Get temp table `wsal_tmp_users`.
870
  $tmp_users = new WSAL_Adapters_MySQL_TmpUser( $_wpdb );
871
  // If the table exist.
872
- if ( $tmp_users->IsInstalled() ) {
873
- $table_users = $tmp_users->GetTable();
874
- $this->TempUsers( $table_users );
875
  } else {
876
  $table_users = $wpdb->users;
877
  }
@@ -912,8 +918,8 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
912
 
913
  $where_statement = $this->build_where_statement( $report_args );
914
 
915
- $sql = "
916
- SELECT " . implode( ',', $select_fields ) . " FROM (
917
  SELECT occ.created_on, occ.site_id, occ.username, occ.client_ip
918
  FROM $table_occ AS occ
919
  {$where_statement}
@@ -927,11 +933,14 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
927
  ) ip_logins
928
  GROUP BY " . implode( ',', $group_by_columns );
929
 
930
- $orderby_parts = array_map( function ( $item ) {
931
- return 'period' === $item ? $item . ' DESC ' : $item . ' ASC ';
932
- }, $group_by_columns );
 
 
 
933
 
934
- $sql .= " ORDER BY " . implode( ',', $orderby_parts );
935
 
936
  if ( ! empty( $limit ) ) {
937
  $sql .= " LIMIT {$limit}";
@@ -946,19 +955,19 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
946
  }
947
 
948
  /**
949
- * @inheritDoc
950
  */
951
- public function IsInstalled() {
952
  $_wpdb = $this->connection;
953
- $sql = "SHOW TABLES LIKE '" . $this->GetTable() . "'";
954
 
955
  // Table transient.
956
- $wsal_table_transient = 'wsal_' . strtolower( $this->GetTable() ) . '_status';
957
  $wsal_db_table_status = get_transient( $wsal_table_transient );
958
 
959
  // If transient does not exist, then run SQL query.
960
  if ( ! $wsal_db_table_status ) {
961
- $wsal_db_table_status = strtolower( $_wpdb->get_var( $sql ) ) == strtolower( $this->GetTable() );
962
  set_transient( $wsal_table_transient, $wsal_db_table_status, DAY_IN_SECONDS );
963
  }
964
 
@@ -971,7 +980,7 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
971
  *
972
  * @param string $table_users - Table name.
973
  */
974
- private function TempUsers( $table_users ) {
975
  $_wpdb = $this->connection;
976
  $sql = "DELETE FROM $table_users";
977
  $_wpdb->query( $sql );
@@ -992,7 +1001,7 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
992
  /**
993
  * Updates records in DB matching a query.
994
  *
995
- * @param string $table Table name
996
  * @param array $data Data to update (in column => value pairs).
997
  * Both $data columns and $data values should be "raw" (neither should be SQL
998
  * escaped). Sending a null value will cause the column to be set to NULL - the
@@ -1006,7 +1015,7 @@ class WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_ActiveRecordInte
1006
  * @return int|false The number of rows updated, or false on error.
1007
  * @since 4.1.3
1008
  */
1009
- public function UpdateQuery( $table, $data, $where ) {
1010
  return $this->connection->update( $table, $data, $where );
1011
  }
1012
  }
36
  *
37
  * @var string
38
  */
39
+ protected $table;
40
 
41
  /**
42
  * Contains primary key column name, override as required.
43
  *
44
  * @var string
45
  */
46
+ protected $idkey = '';
47
 
48
  /**
49
  * Local cache for a list of columns.
50
  *
51
  * @var string[]
52
  */
53
+ protected $column_cache = array();
54
 
55
  /**
56
  * Method: Constructor.
125
  *
126
  * @return string Returns table name of WordPress.
127
  */
128
+ public function get_wp_table() {
129
  global $wpdb;
130
 
131
+ return $wpdb->base_prefix . $this->table;
132
  }
133
 
134
  /**
135
+ * {@inheritDoc}
136
  */
137
+ public function install() {
138
  $_wpdb = $this->connection;
139
+ $_wpdb->query( $this->get_install_query() );
140
  }
141
 
142
  /**
146
  *
147
  * @return string - Must return SQL for creating table.
148
  */
149
+ protected function get_install_query( $prefix = false ) {
150
  $_wpdb = $this->connection;
151
  $class = get_class( $this );
152
  $copy = new $class( $this->connection );
153
+ $table_name = $this->get_table();
154
  $sql = 'CREATE TABLE IF NOT EXISTS ' . $table_name . ' (' . PHP_EOL;
155
+ $cols = $this->get_columns();
156
  foreach ( $cols as $key ) {
157
+ $sql .= $this->get_sql_column_definition( $copy, $key );
158
  }
159
 
160
+ $sql .= $this->get_table_options() . PHP_EOL;
161
  $sql .= ') ' . $_wpdb->get_charset_collate();
162
 
163
  return $sql;
168
  *
169
  * @return string
170
  */
171
+ public function get_table() {
172
  $_wpdb = $this->connection;
173
 
174
+ return $_wpdb->base_prefix . $this->table;
175
  }
176
 
177
  /**
179
  *
180
  * @return array
181
  */
182
+ public function get_columns() {
183
+ $model = $this->get_model();
184
 
185
+ if ( empty( $this->column_cache ) ) {
186
+ $this->column_cache = array();
187
  foreach ( array_keys( get_object_vars( $model ) ) as $col ) {
188
+ if ( trim( $col ) && $col[0] != '_' ) { // phpcs:ignore
189
+ $this->column_cache[] = $col;
190
  }
191
  }
192
  }
193
 
194
+ return $this->column_cache;
195
  }
196
 
197
  /**
198
+ * {@inheritDoc}
199
  */
200
+ public function get_model() {
201
  return new WSAL_Models_Query();
202
  }
203
 
204
  /**
205
  * Generate SQL column definition string for the CREATE TABLE statement.
206
  *
207
+ * @param object $copy Object copy to populate.
208
+ * @param string $key Column key.
209
  *
210
  * @return string
211
  */
212
+ protected function get_sql_column_definition( $copy, $key ) {
213
  $result = ' ';
214
  switch ( true ) {
215
+ case ( $key === $this->idkey ):
216
  $result .= $key . ' BIGINT NOT NULL AUTO_INCREMENT,' . PHP_EOL;
217
  break;
218
  case is_int( $copy->$key ):
238
  $result .= $key . ' LONGTEXT NOT NULL,' . PHP_EOL;
239
  break;
240
  default:
241
+ // Fallback for any other columns would go here.
242
  break;
243
  }
244
 
250
  *
251
  * @return string
252
  */
253
+ protected function get_table_options() {
254
+ return ' PRIMARY KEY (' . $this->idkey . ')';
255
  }
256
 
257
  /**
258
  * Install this ActiveRecord structure into DB WordPress.
259
  */
260
+ public function install_original() {
261
  global $wpdb;
262
+ $wpdb->query( $this->get_install_query( true ) ); // phpcs:ignore
263
  }
264
 
265
  /**
266
+ * {@inheritDoc}
267
  */
268
+ public function uninstall() {
269
  $_wpdb = $this->connection;
270
 
271
  // Check if table exists.
272
  if ( $this->table_exists() ) {
273
+ $_wpdb->query( $this->get_uninstall_query() );
274
  }
275
  }
276
 
283
  $_wpdb = $this->connection;
284
 
285
  // Query table exists.
286
+ $table_exists_query = "SHOW TABLES LIKE '" . $this->get_table() . "'";
287
 
288
  return $_wpdb->query( $table_exists_query );
289
  }
293
  *
294
  * @return string
295
  */
296
+ protected function get_uninstall_query() {
297
+ return 'DROP TABLE IF EXISTS ' . $this->get_table();
298
  }
299
 
300
  /**
301
+ * {@inheritDoc}
302
  */
303
+ public function save( $active_record ) {
304
  $_wpdb = $this->connection;
305
  $copy = $active_record;
306
  $data = array();
307
  $format = array();
308
 
309
+ $columns = $this->get_columns();
310
  foreach ( $columns as $index => $key ) {
311
+ if ( $key == $this->idkey ) { // phpcs:ignore
312
+ $id_index = $index;
313
  }
314
 
315
  $val = $copy->$key;
323
  }
324
 
325
  if ( is_array( $copy->$key ) || is_object( $copy->$key ) ) {
326
+ $data[ $key ] = WSAL_Helpers_DataHelper::json_encode( $val );
327
  } else {
328
  $data[ $key ] = $val;
329
  }
331
  $format[] = $deffmt;
332
  }
333
 
334
+ if ( isset( $data[ $this->idkey ] ) && empty( $data[ $this->idkey ] ) ) {
335
+ unset( $data[ $this->idkey ] );
336
+ unset( $format[ $id_index ] );
337
  }
338
 
339
+ $result = $_wpdb->replace( $this->get_table(), $data, $format );
340
 
341
  if ( false !== $result && $_wpdb->insert_id ) {
342
+ $copy->set_id( $_wpdb->insert_id );
343
  }
344
 
345
  return $result;
353
  *
354
  * @return array
355
  */
356
+ public function load( $cond = '%d', $args = array( 1 ) ) {
357
  $_wpdb = $this->connection;
358
+ $sql = $_wpdb->prepare( 'SELECT * FROM ' . $this->get_table() . ' WHERE ' . $cond, $args );
359
 
360
  return $_wpdb->get_row( $sql, ARRAY_A );
361
  }
367
  * @param array $args (Optional) Load condition arguments.
368
  *
369
  * @return array
 
370
  */
371
+ public function load_array( $cond, $args = array() ) {
372
  $_wpdb = $this->connection;
373
  $result = array();
374
+ $sql = $_wpdb->prepare( 'SELECT * FROM ' . $this->get_table() . ' WHERE ' . $cond, $args );
375
  foreach ( $_wpdb->get_results( $sql, ARRAY_A ) as $data ) {
376
+ $result[] = $this->get_model()->load_data( $data );
377
  }
378
 
379
  return $result;
380
  }
381
 
382
  /**
383
+ * {@inheritDoc}
384
  */
385
+ public function delete( $active_record ) {
386
  $_wpdb = $this->connection;
387
 
388
  return $_wpdb->delete(
389
+ $this->get_table(),
390
  array(
391
+ $this->idkey => $active_record->get_id(),
392
  ),
393
  array( '%d' )
394
  );
402
  *
403
  * @return int|bool
404
  */
405
+ public function delete_query( $query, $args = array() ) {
406
  $_wpdb = $this->connection;
407
  $sql = count( $args ) ? $_wpdb->prepare( $query, $args ) : $query;
408
 
410
  }
411
 
412
  /**
413
+ * {@inheritDoc}
414
  */
415
+ public function load_multi( $cond, $args = array() ) {
416
  $_wpdb = $this->connection;
417
  $result = array();
418
  $sql = ( ! is_array( $args ) || ! count( $args ) ) // Do we really need to prepare() or not?
419
  ? ( $cond )
420
  : $_wpdb->prepare( $cond, $args );
421
  foreach ( $_wpdb->get_results( $sql, ARRAY_A ) as $data ) {
422
+ $result[] = $this->get_model()->load_data( $data );
423
  }
424
 
425
  return $result;
426
  }
427
 
428
  /**
429
+ * {@inheritDoc}
430
  */
431
+ public function load_and_call_for_each( $callback, $cond = '%d', $args = array( 1 ) ) {
432
  $_wpdb = $this->connection;
433
  $class = get_called_class();
434
+ $sql = $_wpdb->prepare( 'SELECT * FROM ' . $this->get_table() . ' WHERE ' . $cond, $args );
435
  foreach ( $_wpdb->get_results( $sql, ARRAY_A ) as $data ) {
436
  call_user_func( $callback, new $class( $data ) );
437
  }
438
  }
439
 
440
  /**
441
+ * {@inheritDoc}
442
  */
443
+ public function count( $cond = '%d', $args = array( 1 ) ) {
444
  $_wpdb = $this->connection;
445
+ $sql = $_wpdb->prepare( 'SELECT COUNT(*) FROM ' . $this->get_table() . ' WHERE ' . $cond, $args );
446
 
447
  return (int) $_wpdb->get_var( $sql );
448
  }
455
  *
456
  * @return int Number of matching records.
457
  */
458
+ public function count_query( $query, $args = array() ) {
459
  $_wpdb = $this->connection;
460
  $sql = count( $args ) ? $_wpdb->prepare( $query, $args ) : $query;
461
 
463
  }
464
 
465
  /**
466
+ * {@inheritDoc}
467
  */
468
+ public function load_multi_query( $query, $args = array() ) {
469
  $_wpdb = $this->connection;
470
  $result = array();
471
  $sql = count( $args ) ? $_wpdb->prepare( $query, $args ) : $query;
472
  foreach ( $_wpdb->get_results( $sql, ARRAY_A ) as $data ) {
473
+ $result[] = $this->get_model()->load_data( $data );
474
  }
475
 
476
  return $result;
528
  */
529
  private function build_reporting_query( $report_args, $count_only, $grouping = null, $next_date = null, $limit = 0 ) {
530
  $occurrence = new WSAL_Adapters_MySQL_Occurrence( $this->connection );
531
+ $table_occ = $occurrence->get_table();
532
 
533
  if ( $count_only ) {
534
  $select_fields = array( 'COUNT(1) as count' );
535
  $group_by = array( 'occ.id' );
536
  } elseif ( is_null( $grouping ) ) {
537
  $select_fields = array(
538
+ 'occ.id',
539
+ 'occ.alert_id',
540
+ 'occ.site_id',
541
+ 'occ.created_on',
542
  "replace( replace( replace( occ.user_roles, '[', ''), ']', ''), '\\'', '') AS roles",
543
+ 'occ.client_ip AS ip',
544
+ 'occ.user_agent AS ua',
545
+ 'COALESCE( occ.username, occ.user_id ) as user_id',
546
+ 'occ.object',
547
+ 'occ.event_type',
548
+ 'occ.post_id',
549
+ 'occ.post_type',
550
+ 'occ.post_status',
551
  );
552
  } else {
553
  $select_fields = array();
554
  $group_by = array();
555
  foreach ( $grouping as $grouping_item ) {
556
+ switch ( $grouping_item ) {
557
  case 'site':
558
  array_push( $select_fields, 'site_id' );
559
  array_push( $group_by, 'site_id' );
560
  break;
561
  case 'users':
562
+ array_push( $select_fields, 'COALESCE( occ.username, occ.user_id ) as user' );
563
  array_push( $group_by, 'user' );
564
  break;
565
  case 'posts':
592
  }
593
 
594
  if ( isset( $group_by ) && ! empty( $group_by ) ) {
595
+ $sql .= ' GROUP BY ' . implode( ',', $group_by );
596
+ $orderby_parts = array_map(
597
+ function ( $item ) {
598
+ return 'period' === $item ? $item . ' DESC ' : $item . ' ASC ';
599
+ },
600
+ $group_by
601
+ );
602
 
603
+ $sql .= ' ORDER BY ' . implode( ',', $orderby_parts );
604
  } else {
605
+ $sql .= ' ORDER BY created_on DESC ';
606
  }
607
 
608
  if ( ! empty( $limit ) ) {
623
  $_site_id = null;
624
  $sites_negate_expression = '';
625
  if ( $report_args->site__in ) {
626
+ $_site_id = $this->format_array_for_query( $report_args->site__in );
627
  } elseif ( $report_args->site__not_in ) {
628
+ $_site_id = $this->format_array_for_query( $report_args->site__not_in );
629
  $sites_negate_expression = 'NOT';
630
  }
631
 
632
  $_user_id = null;
633
  $users_negate_expression = '';
634
  if ( $report_args->user__in ) {
635
+ $_user_id = $this->format_array_for_query( $report_args->user__in );
636
  } elseif ( $report_args->user__not_in ) {
637
+ $_user_id = $this->format_array_for_query( $report_args->user__not_in );
638
  $users_negate_expression = 'NOT';
639
  }
640
 
641
+ $user_names = $this->get_user_names( $_user_id );
642
 
643
  $_role_name = null;
644
  $roles_negate_expression = '';
645
  if ( $report_args->role__in ) {
646
+ $_role_name = $this->format_array_for_query_regex( $report_args->role__in );
647
  } elseif ( $report_args->role__not_in ) {
648
+ $_role_name = $this->format_array_for_query_regex( $report_args->role__not_in );
649
  $roles_negate_expression = 'NOT';
650
  }
651
 
652
  $_alert_code = null;
653
  $alert_code_negate_expression = '';
654
  if ( $report_args->code__in ) {
655
+ $_alert_code = $this->format_array_for_query( $report_args->code__in );
656
  } elseif ( $report_args->code__not_in ) {
657
+ $_alert_code = $this->format_array_for_query( $report_args->code__not_in );
658
  $alert_code_negate_expression = 'NOT';
659
  }
660
 
661
  $_post_ids = null;
662
  $post_ids_negate_expression = '';
663
  if ( $report_args->post__in ) {
664
+ $_post_ids = $this->format_array_for_query_regex( $report_args->post__in );
665
  } elseif ( $report_args->post__not_in ) {
666
+ $_post_ids = $this->format_array_for_query_regex( $report_args->post__not_in );
667
  $post_ids_negate_expression = 'NOT';
668
  }
669
 
670
  $_post_types = null;
671
  $post_types_negate_expression = '';
672
  if ( $report_args->post_type__in ) {
673
+ $_post_types = $this->format_array_for_query_regex( $report_args->post_type__in );
674
  } elseif ( $report_args->post_type__not_in ) {
675
+ $_post_types = $this->format_array_for_query_regex( $report_args->post_type__not_in );
676
  $post_types_negate_expression = 'NOT';
677
  }
678
 
679
  $_post_statuses = null;
680
  $post_statuses_negate_expression = '';
681
  if ( $report_args->post_status__in ) {
682
+ $_post_statuses = $this->format_array_for_query_regex( $report_args->post_status__in );
683
+ } elseif ( $report_args->post_status__not_in ) {
684
+ $_post_statuses = $this->format_array_for_query_regex( $report_args->post_status__not_in );
685
  $post_statuses_negate_expression = 'NOT';
686
  }
687
 
688
  $_ip_addresses = null;
689
  $ip_addresses_negate_expression = '';
690
  if ( $report_args->ip__in ) {
691
+ $_ip_addresses = $this->format_array_for_query( $report_args->ip__in );
692
+ } elseif ( $report_args->ip__not_in ) {
693
+ $_ip_addresses = $this->format_array_for_query( $report_args->ip__not_in );
694
  $ip_addresses_negate_expression = 'NOT';
695
  }
696
 
697
  $_objects = null;
698
  $objects_negate_expression = '';
699
  if ( $report_args->object__in ) {
700
+ $_objects = $this->format_array_for_query( $report_args->object__in );
701
  } elseif ( $report_args->object__not_in ) {
702
+ $_objects = $this->format_array_for_query( $report_args->object__not_in );
703
  $objects_negate_expression = 'NOT';
704
  }
705
 
706
  $_event_types = null;
707
  $event_types_negate_expression = '';
708
  if ( $report_args->type__in ) {
709
+ $_event_types = $this->format_array_for_query( $report_args->type__in );
710
  } elseif ( $report_args->type__not_in ) {
711
+ $_event_types = $this->format_array_for_query( $report_args->type__not_in );
712
  $event_types_negate_expression = 'NOT';
713
  }
714
 
733
  array_push( $users_condition_parts, " {$users_negate_expression} replace( occ.username, '\"', '' ) IN ( $user_names ) " );
734
  }
735
 
736
+ $where_statement = ' WHERE 1 = 1 ';
737
 
738
  if ( ! empty( $users_condition_parts ) ) {
739
  $where_statement .= ' AND ( ' . implode( 'OR', $users_condition_parts ) . ' ) ';
787
  }
788
 
789
  /**
790
+ * Formats array for use in SQL query.
791
+ *
792
+ * @param array $data Data to format.
793
  *
794
  * @return string
795
  * @since 4.3.2
796
  */
797
+ protected function format_array_for_query( $data ) {
798
  return "'" . implode( ',', $data ) . "'";
799
  }
800
 
801
  /**
802
  * Get Users user_login.
803
  *
804
+ * @param int $user_id - User ID.
805
  *
806
  * @return string comma separated users login
807
  */
808
+ private function get_user_names( $user_id ) {
809
  global $wpdb;
810
 
811
  $user_names = null;
812
+ if ( ! empty( $user_id ) && 'null' !== $user_id && ! is_null( $user_id ) ) {
813
  $sql = 'SELECT user_login FROM ' . $wpdb->users . ' WHERE find_in_set(ID, @userId) > 0';
814
+ $wpdb->query( "SET @userId = $user_id" ); // phpcs:ignore
815
+ $result = $wpdb->get_results( $sql, ARRAY_A ); // phpcs:ignore
816
  $users_array = array();
817
  foreach ( $result as $item ) {
818
  $users_array[] = '"' . $item['user_login'] . '"';
824
  }
825
 
826
  /**
827
+ * Formats data as SQL query regex.
828
+ *
829
+ * @param array $data Data to format.
830
  *
831
  * @return string
832
  * @since 4.3.2
833
  */
834
+ protected function format_array_for_query_regex( $data ) {
835
  $result = array();
836
  foreach ( $data as $item ) {
837
+ array_push( $result, esc_sql( preg_quote( $item ) ) ); // phpcs:ignore
838
  }
839
 
840
  return "'" . implode( '|', $result ) . "'";
846
  *
847
  * @param WSAL_ReportArgs $report_args - Query conditions.
848
  *
849
+ * @return int Count of distinct values.
850
  */
851
+ public function check_match_report_criteria( $report_args ) {
852
  $query = $this->build_reporting_query( $report_args, true );
853
 
854
  return (int) $this->connection->get_var( $query );
870
 
871
  // Tables.
872
  $occurrence = new WSAL_Adapters_MySQL_Occurrence( $_wpdb );
873
+ $table_occ = $occurrence->get_table();
874
 
875
  // Get temp table `wsal_tmp_users`.
876
  $tmp_users = new WSAL_Adapters_MySQL_TmpUser( $_wpdb );
877
  // If the table exist.
878
+ if ( $tmp_users->is_installed() ) {
879
+ $table_users = $tmp_users->get_table();
880
+ $this->temp_users( $table_users );
881
  } else {
882
  $table_users = $wpdb->users;
883
  }
918
 
919
  $where_statement = $this->build_where_statement( $report_args );
920
 
921
+ $sql = '
922
+ SELECT ' . implode( ',', $select_fields ) . " FROM (
923
  SELECT occ.created_on, occ.site_id, occ.username, occ.client_ip
924
  FROM $table_occ AS occ
925
  {$where_statement}
933
  ) ip_logins
934
  GROUP BY " . implode( ',', $group_by_columns );
935
 
936
+ $orderby_parts = array_map(
937
+ function ( $item ) {
938
+ return 'period' === $item ? $item . ' DESC ' : $item . ' ASC ';
939
+ },
940
+ $group_by_columns
941
+ );
942
 
943
+ $sql .= ' ORDER BY ' . implode( ',', $orderby_parts );
944
 
945
  if ( ! empty( $limit ) ) {
946
  $sql .= " LIMIT {$limit}";
955
  }
956
 
957
  /**
958
+ * {@inheritDoc}
959
  */
960
+ public function is_installed() {
961
  $_wpdb = $this->connection;
962
+ $sql = "SHOW TABLES LIKE '" . $this->get_table() . "'";
963
 
964
  // Table transient.
965
+ $wsal_table_transient = 'wsal_' . strtolower( $this->get_table() ) . '_status';
966
  $wsal_db_table_status = get_transient( $wsal_table_transient );
967
 
968
  // If transient does not exist, then run SQL query.
969
  if ( ! $wsal_db_table_status ) {
970
+ $wsal_db_table_status = strtolower( $_wpdb->get_var( $sql ) ) === strtolower( $this->get_table() );
971
  set_transient( $wsal_table_transient, $wsal_db_table_status, DAY_IN_SECONDS );
972
  }
973
 
980
  *
981
  * @param string $table_users - Table name.
982
  */
983
+ private function temp_users( $table_users ) {
984
  $_wpdb = $this->connection;
985
  $sql = "DELETE FROM $table_users";
986
  $_wpdb->query( $sql );
1001
  /**
1002
  * Updates records in DB matching a query.
1003
  *
1004
+ * @param string $table Table name.
1005
  * @param array $data Data to update (in column => value pairs).
1006
  * Both $data columns and $data values should be "raw" (neither should be SQL
1007
  * escaped). Sending a null value will cause the column to be set to NULL - the
1015
  * @return int|false The number of rows updated, or false on error.
1016
  * @since 4.1.3
1017
  */
1018
+ public function update_query( $table, $data, $where ) {
1019
  return $this->connection->update( $table, $data, $where );
1020
  }
1021
  }
classes/Adapters/MySQL/MetaAdapter.php CHANGED
@@ -27,14 +27,14 @@ class WSAL_Adapters_MySQL_Meta extends WSAL_Adapters_MySQL_ActiveRecord implemen
27
  *
28
  * @var string
29
  */
30
- protected $_table = 'wsal_metadata';
31
 
32
  /**
33
  * Contains primary key column name, override as required.
34
  *
35
  * @var string
36
  */
37
- protected $_idkey = 'id';
38
 
39
  /**
40
  * Meta id.
@@ -72,13 +72,13 @@ class WSAL_Adapters_MySQL_Meta extends WSAL_Adapters_MySQL_ActiveRecord implemen
72
  public $value = array(); // Force mixed type.
73
 
74
  /**
75
- * @inheritDoc
76
  *
77
  * @return WSAL_Models_Meta
78
  */
79
- public function GetModel() {
80
  $result = new WSAL_Models_Meta();
81
- $result->setAdapter( $this );
82
 
83
  return $result;
84
  }
@@ -88,35 +88,35 @@ class WSAL_Adapters_MySQL_Meta extends WSAL_Adapters_MySQL_ActiveRecord implemen
88
  *
89
  * @return string
90
  */
91
- protected function GetTableOptions() {
92
- return parent::GetTableOptions() . ',' . PHP_EOL
93
  . ' KEY occurrence_name (occurrence_id,name)';
94
  }
95
 
96
  /**
97
- * @inheritDoc
98
  */
99
- public function DeleteByOccurrenceIds( $occurrence_ids ) {
100
  if ( ! empty( $occurrence_ids ) ) {
101
- $sql = 'DELETE FROM ' . $this->GetTable() . ' WHERE occurrence_id IN (' . implode( ',', $occurrence_ids ) . ')';
102
  // Execute query.
103
- parent::DeleteQuery( $sql );
104
  }
105
  }
106
 
107
  /**
108
- * @inheritDoc
109
  */
110
- public function LoadByNameAndOccurrenceId( $meta_name, $occurrence_id ) {
111
- // make sure to grab the migrated meta fields from the occurrence table
112
- if ( in_array( $meta_name, array_keys( WSAL_Models_Occurrence::$migrated_meta ) ) ) {
113
  $occurrence = new WSAL_Adapters_MySQL_Occurrence( $this->get_connection() );
114
  $column_name = WSAL_Models_Occurrence::$migrated_meta[ $meta_name ];
115
 
116
  return $occurrence->$column_name;
117
  }
118
 
119
- return $this->Load( 'occurrence_id = %d AND name = %s', array( $occurrence_id, $meta_name ) );
120
  }
121
 
122
  /**
@@ -126,13 +126,13 @@ class WSAL_Adapters_MySQL_Meta extends WSAL_Adapters_MySQL_ActiveRecord implemen
126
  $db_connection = $this->get_connection();
127
  // check if an index exists.
128
  $index_exists = false;
129
- if ( $db_connection->query( 'SELECT COUNT(1) IndexIsThere FROM INFORMATION_SCHEMA.STATISTICS WHERE table_schema=DATABASE() AND table_name="' . $this->GetTable() . '" AND index_name="name_value"' ) ) {
130
  // query succeeded, does index exist?
131
  $index_exists = ( isset( $db_connection->last_result[0]->IndexIsThere ) ) ? $db_connection->last_result[0]->IndexIsThere : false;
132
  }
133
  // if no index exists then make one.
134
  if ( ! $index_exists ) {
135
- $db_connection->query( 'CREATE INDEX name_value ON ' . $this->GetTable() . ' (name, value(64))' );
136
  }
137
  }
138
  }
27
  *
28
  * @var string
29
  */
30
+ protected $table = 'wsal_metadata';
31
 
32
  /**
33
  * Contains primary key column name, override as required.
34
  *
35
  * @var string
36
  */
37
+ protected $idkey = 'id';
38
 
39
  /**
40
  * Meta id.
72
  public $value = array(); // Force mixed type.
73
 
74
  /**
75
+ * {@inheritDoc}
76
  *
77
  * @return WSAL_Models_Meta
78
  */
79
+ public function get_model() {
80
  $result = new WSAL_Models_Meta();
81
+ $result->set_adapter( $this );
82
 
83
  return $result;
84
  }
88
  *
89
  * @return string
90
  */
91
+ protected function get_table_options() {
92
+ return parent::get_table_options() . ',' . PHP_EOL
93
  . ' KEY occurrence_name (occurrence_id,name)';
94
  }
95
 
96
  /**
97
+ * {@inheritDoc}
98
  */
99
+ public function delete_by_occurrence_ids( $occurrence_ids ) {
100
  if ( ! empty( $occurrence_ids ) ) {
101
+ $sql = 'DELETE FROM ' . $this->get_table() . ' WHERE occurrence_id IN (' . implode( ',', $occurrence_ids ) . ')';
102
  // Execute query.
103
+ parent::delete_query( $sql );
104
  }
105
  }
106
 
107
  /**
108
+ * {@inheritDoc}
109
  */
110
+ public function load_by_name_and_occurrence_id( $meta_name, $occurrence_id ) {
111
+ // Make sure to grab the migrated meta fields from the occurrence table.
112
+ if ( in_array( $meta_name, array_keys( WSAL_Models_Occurrence::$migrated_meta ), true ) ) {
113
  $occurrence = new WSAL_Adapters_MySQL_Occurrence( $this->get_connection() );
114
  $column_name = WSAL_Models_Occurrence::$migrated_meta[ $meta_name ];
115
 
116
  return $occurrence->$column_name;
117
  }
118
 
119
+ return $this->load( 'occurrence_id = %d AND name = %s', array( $occurrence_id, $meta_name ) );
120
  }
121
 
122
  /**
126
  $db_connection = $this->get_connection();
127
  // check if an index exists.
128
  $index_exists = false;
129
+ if ( $db_connection->query( 'SELECT COUNT(1) IndexIsThere FROM INFORMATION_SCHEMA.STATISTICS WHERE table_schema=DATABASE() AND table_name="' . $this->get_table() . '" AND index_name="name_value"' ) ) {
130
  // query succeeded, does index exist?
131
  $index_exists = ( isset( $db_connection->last_result[0]->IndexIsThere ) ) ? $db_connection->last_result[0]->IndexIsThere : false;
132
  }
133
  // if no index exists then make one.
134
  if ( ! $index_exists ) {
135
+ $db_connection->query( 'CREATE INDEX name_value ON ' . $this->get_table() . ' (name, value(64))' );
136
  }
137
  }
138
  }
classes/Adapters/MySQL/OccurrenceAdapter.php CHANGED
@@ -22,16 +22,18 @@ if ( ! defined( 'ABSPATH' ) ) {
22
  class WSAL_Adapters_MySQL_Occurrence extends WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_OccurrenceInterface {
23
 
24
  /**
25
- * @inheritDoc
 
 
26
  */
27
- protected $_table = 'wsal_occurrences';
28
 
29
  /**
30
  * Contains primary key column name, override as required.
31
  *
32
  * @var string
33
  */
34
- protected $_idkey = 'id';
35
 
36
  /**
37
  * Occurrence id.
@@ -158,90 +160,90 @@ class WSAL_Adapters_MySQL_Occurrence extends WSAL_Adapters_MySQL_ActiveRecord im
158
  public $post_id = 0;
159
 
160
  /**
161
- * @inheritDoc
162
  */
163
- protected function GetTableOptions() {
164
- return parent::GetTableOptions() . ',' . PHP_EOL
165
- . ' KEY site_alert_created (site_id,alert_id,created_on)';
166
  }
167
 
168
  /**
169
- * @inheritDoc
170
  *
171
  * @return WSAL_Models_Occurrence
172
  */
173
- public function GetModel() {
174
  $result = new WSAL_Models_Occurrence();
175
- $result->setAdapter( $this );
176
 
177
  return $result;
178
  }
179
 
180
  /**
181
- * @inheritDoc
182
  */
183
- public function GetMultiMeta( $occurrence ) {
184
  $meta = new WSAL_Adapters_MySQL_Meta( $this->connection );
185
 
186
- return $meta->LoadArray( 'occurrence_id = %d', array( $occurrence->id ) );
187
  }
188
 
189
  /**
190
- * @inheritDoc
191
  */
192
- public function GetNamedMeta( $occurrence, $name ) {
193
  $meta = new WSAL_Adapters_MySQL_Meta( $this->connection );
194
 
195
- return $meta->LoadByNameAndOccurrenceId( $name, $occurrence->id );
196
  }
197
 
198
  /**
199
- * @inheritDoc
200
  */
201
- public function GetFirstNamedMeta( $occurrence, $names ) {
202
  $meta = new WSAL_Adapters_MySQL_Meta( $this->connection );
203
  $query = '(' . str_repeat( 'name = %s OR ', count( $names ) ) . '0)';
204
  $query = 'occurrence_id = %d AND ' . $query . ' ORDER BY name DESC LIMIT 1';
205
  array_unshift( $names, $occurrence->id ); // Prepend args with occurrence id.
206
 
207
- return $meta->getModel()->LoadData( $meta->Load( $query, $names ) );
208
  }
209
 
210
  /**
211
- * @inheritDoc
212
  */
213
- public function CheckKnownUsers( $args = array() ) {
214
- return $this->LoadMultiQuery(
215
- "SELECT * FROM `{$this->GetTable()}` "
216
- . " WHERE client_ip = %s "
217
- . " AND username = %s "
218
- . " AND alert_id = %d "
219
- . " AND site_id = %d "
220
- . " AND ( created_on BETWEEN %d AND %d );",
221
  $args
222
  );
223
  }
224
 
225
  /**
226
- * @inheritDoc
227
  */
228
- public function CheckUnknownUsers( $args = array() ) {
229
- return $this->LoadMultiQuery(
230
- "SELECT * FROM `{$this->GetTable()}` "
231
- . " WHERE client_ip = %s "
232
- . " AND alert_id = %d "
233
- . " AND site_id = %d "
234
- . " AND ( created_on BETWEEN %d AND %d );",
235
  $args
236
  );
237
  }
238
 
239
  /**
240
- * @inheritDoc
241
  */
242
  public function check_alert_1003( $args = array() ) {
243
- return $this->LoadMultiQuery(
244
- 'SELECT * FROM `' . $this->GetTable() . '`
245
  WHERE (alert_id = %d)
246
  AND (site_id = %d)
247
  AND (created_on BETWEEN %d AND %d);',
@@ -250,13 +252,13 @@ class WSAL_Adapters_MySQL_Occurrence extends WSAL_Adapters_MySQL_ActiveRecord im
250
  }
251
 
252
  /**
253
- * @inheritDoc
254
  */
255
- public function GetByPostID( $post_id ) {
256
- return $this->LoadMultiQuery(
257
- "SELECT occurrence.* FROM `{$this->GetTable()}` "
258
- . " WHERE post_id = %d "
259
- . " ORDER BY created_on DESC;",
260
  array( $post_id )
261
  );
262
  }
@@ -268,34 +270,37 @@ class WSAL_Adapters_MySQL_Occurrence extends WSAL_Adapters_MySQL_ActiveRecord im
268
  $index_exists = false;
269
  $db_connection = $this->get_connection();
270
  // check if an index exists.
271
- if ( $db_connection->query( 'SELECT COUNT(1) IndexIsThere FROM INFORMATION_SCHEMA.STATISTICS WHERE table_schema=DATABASE() AND table_name="' . $this->GetTable() . '" AND index_name="created_on"' ) ) {
272
  // query succeeded, does index exist?
273
  $index_exists = ( isset( $db_connection->last_result[0]->IndexIsThere ) ) ? $db_connection->last_result[0]->IndexIsThere : false;
274
  }
275
  // if no index exists then make one.
276
  if ( ! $index_exists ) {
277
- $db_connection->query( 'CREATE INDEX created_on ON ' . $this->GetTable() . ' (created_on)' );
278
  }
279
  }
280
 
281
  /**
282
- * @inheritDoc
283
  */
284
  public function get_all_with_meta_to_migrate( $limit ) {
285
  $meta_adapter = new WSAL_Adapters_MySQL_Meta( $this->connection );
286
 
287
- $meta_keys = array_map( function ( $value ) {
288
- return '"' . $value . '"';
289
- }, array_keys( WSAL_Models_Occurrence::$migrated_meta ) );
290
-
291
- return $this->LoadMultiQuery(
292
- "SELECT o.* FROM `{$this->GetTable()}` o "
293
- . " INNER JOIN `{$meta_adapter->GetTable()}` m "
294
- . " ON m.occurrence_id = o.id "
295
- . " WHERE m.name IN (" . implode( ',', $meta_keys ) . ") "
296
- . " GROUP BY o.id "
297
- . " ORDER BY created_on DESC "
298
- . " LIMIT 0, %d;",
 
 
 
299
  array( $limit )
300
  );
301
  }
@@ -307,9 +312,9 @@ class WSAL_Adapters_MySQL_Occurrence extends WSAL_Adapters_MySQL_ActiveRecord im
307
  *
308
  * @return array - Distinct values of IPs.
309
  */
310
- public function GetMatchingIPs( $limit = null ) {
311
  $_wpdb = $this->connection;
312
- $sql = "SELECT DISTINCT client_ip FROM {$this->GetTable()}";
313
  if ( ! is_null( $limit ) ) {
314
  $sql .= ' LIMIT ' . $limit;
315
  }
@@ -326,51 +331,47 @@ class WSAL_Adapters_MySQL_Occurrence extends WSAL_Adapters_MySQL_ActiveRecord im
326
  }
327
 
328
  /**
329
- * @inheritDoc
330
  *
331
- * username and user_id columns have to be added manually because function get_object_vars doesn't return
332
  * uninitialised properties. These two cannot have the default value set because some database queries rely on
333
  * having null values in the database.
334
  *
335
  * @since 4.4.0
336
  */
337
- public function GetColumns() {
338
- if ( ! empty( $this->_column_cache ) ) {
339
- return $this->_column_cache;
340
  }
341
 
342
- $result = parent::GetColumns();
343
- foreach ( [ 'username', 'user_id' ] as $extra_column ) {
344
- if ( ! in_array( $extra_column, $result ) ) {
345
  array_push( $result, $extra_column );
346
  }
347
  }
348
 
349
- $this->_column_cache = $result;
350
 
351
  return $result;
352
  }
353
 
354
  /**
355
- * @inheritDoc
356
- *
357
- * @param WSAL_Models_Occurrence $copy
358
- *
359
- * @since 4.4.0
360
  */
361
- protected function _GetSqlColumnDefinition( $copy, $key ) {
362
  if ( 'username' === $key ) {
363
- return " username VARCHAR(255) NULL, ";
364
  }
365
 
366
  if ( 'user_id' === $key ) {
367
- return " user_id BIGINT NULL, ";
368
  }
369
 
370
  if ( is_string( $copy->$key ) ) {
371
  return $key . ' VARCHAR(255) NOT NULL,' . PHP_EOL;
372
  }
373
 
374
- return parent::_GetSqlColumnDefinition( $copy, $key );
375
  }
376
  }
22
  class WSAL_Adapters_MySQL_Occurrence extends WSAL_Adapters_MySQL_ActiveRecord implements WSAL_Adapters_OccurrenceInterface {
23
 
24
  /**
25
+ * Contains the table name
26
+ *
27
+ * @var string
28
  */
29
+ protected $table = 'wsal_occurrences';
30
 
31
  /**
32
  * Contains primary key column name, override as required.
33
  *
34
  * @var string
35
  */
36
+ protected $idkey = 'id';
37
 
38
  /**
39
  * Occurrence id.
160
  public $post_id = 0;
161
 
162
  /**
163
+ * {@inheritDoc}
164
  */
165
+ protected function get_table_options() {
166
+ return parent::get_table_options() . ',' . PHP_EOL
167
+ . ' KEY site_alert_created (site_id,alert_id,created_on)';
168
  }
169
 
170
  /**
171
+ * {@inheritDoc}
172
  *
173
  * @return WSAL_Models_Occurrence
174
  */
175
+ public function get_model() {
176
  $result = new WSAL_Models_Occurrence();
177
+ $result->set_adapter( $this );
178
 
179
  return $result;
180
  }
181
 
182
  /**
183
+ * {@inheritDoc}
184
  */
185
+ public function get_multi_meta( $occurrence ) {
186
  $meta = new WSAL_Adapters_MySQL_Meta( $this->connection );
187
 
188
+ return $meta->load_array( 'occurrence_id = %d', array( $occurrence->id ) );
189
  }
190
 
191
  /**
192
+ * {@inheritDoc}
193
  */
194
+ public function get_named_meta( $occurrence, $name ) {
195
  $meta = new WSAL_Adapters_MySQL_Meta( $this->connection );
196
 
197
+ return $meta->load_by_name_and_occurrence_id( $name, $occurrence->id );
198
  }
199
 
200
  /**
201
+ * {@inheritDoc}
202
  */
203
+ public function get_first_named_meta( $occurrence, $names ) {
204
  $meta = new WSAL_Adapters_MySQL_Meta( $this->connection );
205
  $query = '(' . str_repeat( 'name = %s OR ', count( $names ) ) . '0)';
206
  $query = 'occurrence_id = %d AND ' . $query . ' ORDER BY name DESC LIMIT 1';
207
  array_unshift( $names, $occurrence->id ); // Prepend args with occurrence id.
208
 
209
+ return $meta->get_model()->load_data( $meta->load( $query, $names ) );
210
  }
211
 
212
  /**
213
+ * {@inheritDoc}
214
  */
215
+ public function check_known_users( $args = array() ) {
216
+ return $this->load_multi_query(
217
+ "SELECT * FROM `{$this->get_table()}` "
218
+ . ' WHERE client_ip = %s '
219
+ . ' AND username = %s '
220
+ . ' AND alert_id = %d '
221
+ . ' AND site_id = %d '
222
+ . ' AND ( created_on BETWEEN %d AND %d );',
223
  $args
224
  );
225
  }
226
 
227
  /**
228
+ * {@inheritDoc}
229
  */
230
+ public function check_unknown_users( $args = array() ) {
231
+ return $this->load_multi_query(
232
+ "SELECT * FROM `{$this->get_table()}` "
233
+ . ' WHERE client_ip = %s '
234
+ . ' AND alert_id = %d '
235
+ . ' AND site_id = %d '
236
+ . ' AND ( created_on BETWEEN %d AND %d );',
237
  $args
238
  );
239
  }
240
 
241
  /**
242
+ * {@inheritDoc}
243
  */
244
  public function check_alert_1003( $args = array() ) {
245
+ return $this->load_multi_query(
246
+ 'SELECT * FROM `' . $this->get_table() . '`
247
  WHERE (alert_id = %d)
248
  AND (site_id = %d)
249
  AND (created_on BETWEEN %d AND %d);',
252
  }
253
 
254
  /**
255
+ * {@inheritDoc}
256
  */
257
+ public function get_by_post_id( $post_id ) {
258
+ return $this->load_multi_query(
259
+ "SELECT occurrence.* FROM `{$this->get_table()}` "
260
+ . ' WHERE post_id = %d '
261
+ . ' ORDER BY created_on DESC;',
262
  array( $post_id )
263
  );
264
  }
270
  $index_exists = false;
271
  $db_connection = $this->get_connection();
272
  // check if an index exists.
273
+ if ( $db_connection->query( 'SELECT COUNT(1) IndexIsThere FROM INFORMATION_SCHEMA.STATISTICS WHERE table_schema=DATABASE() AND table_name="' . $this->get_table() . '" AND index_name="created_on"' ) ) {
274
  // query succeeded, does index exist?
275
  $index_exists = ( isset( $db_connection->last_result[0]->IndexIsThere ) ) ? $db_connection->last_result[0]->IndexIsThere : false;
276
  }
277
  // if no index exists then make one.
278
  if ( ! $index_exists ) {
279
+ $db_connection->query( 'CREATE INDEX created_on ON ' . $this->get_table() . ' (created_on)' );
280
  }
281
  }
282
 
283
  /**
284
+ * {@inheritDoc}
285
  */
286
  public function get_all_with_meta_to_migrate( $limit ) {
287
  $meta_adapter = new WSAL_Adapters_MySQL_Meta( $this->connection );
288
 
289
+ $meta_keys = array_map(
290
+ function ( $value ) {
291
+ return '"' . $value . '"';
292
+ },
293
+ array_keys( WSAL_Models_Occurrence::$migrated_meta )
294
+ );
295
+
296
+ return $this->load_multi_query(
297
+ "SELECT o.* FROM `{$this->get_table()}` o "
298
+ . " INNER JOIN `{$meta_adapter->get_table()}` m "
299
+ . ' ON m.occurrence_id = o.id '
300
+ . ' WHERE m.name IN (' . implode( ',', $meta_keys ) . ') '
301
+ . ' GROUP BY o.id '
302
+ . ' ORDER BY created_on DESC '
303
+ . ' LIMIT 0, %d;',
304
  array( $limit )
305
  );
306
  }
312
  *
313
  * @return array - Distinct values of IPs.
314
  */
315
+ public function get_matching_ips( $limit = null ) {
316
  $_wpdb = $this->connection;
317
+ $sql = "SELECT DISTINCT client_ip FROM {$this->get_table()}";
318
  if ( ! is_null( $limit ) ) {
319
  $sql .= ' LIMIT ' . $limit;
320
  }
331
  }
332
 
333
  /**
334
+ * {@inheritDoc}
335
  *
336
+ * "username" and user_id columns have to be added manually because function get_object_vars doesn't return
337
  * uninitialised properties. These two cannot have the default value set because some database queries rely on
338
  * having null values in the database.
339
  *
340
  * @since 4.4.0
341
  */
342
+ public function get_columns() {
343
+ if ( ! empty( $this->column_cache ) ) {
344
+ return $this->column_cache;
345
  }
346
 
347
+ $result = parent::get_columns();
348
+ foreach ( array( 'username', 'user_id' ) as $extra_column ) {
349
+ if ( ! in_array( $extra_column, $result, true ) ) {
350
  array_push( $result, $extra_column );
351
  }
352
  }
353
 
354
+ $this->column_cache = $result;
355
 
356
  return $result;
357
  }
358
 
359
  /**
360
+ * {@inheritDoc}
 
 
 
 
361
  */
362
+ protected function get_sql_column_definition( $copy, $key ) {
363
  if ( 'username' === $key ) {
364
+ return ' username VARCHAR(255) NULL, ';
365
  }
366
 
367
  if ( 'user_id' === $key ) {
368
+ return ' user_id BIGINT NULL, ';
369
  }
370
 
371
  if ( is_string( $copy->$key ) ) {
372
  return $key . ' VARCHAR(255) NOT NULL,' . PHP_EOL;
373
  }
374
 
375
+ return parent::get_sql_column_definition( $copy, $key );
376
  }
377
  }
classes/Adapters/MySQL/QueryAdapter.php CHANGED
@@ -42,14 +42,15 @@ class WSAL_Adapters_MySQL_Query implements WSAL_Adapters_QueryInterface {
42
  /**
43
  * Get the SQL filled with the args.
44
  *
45
- * @param object $query - Query object.
46
- * @param array $args - Args of the query.
 
47
  * @return string Generated sql.
48
  */
49
- protected function GetSql( $query, &$args = array() ) {
50
- $conditions = $query->getConditions();
51
- $search_condition = $this->SearchCondition( $query );
52
- $s_where_clause = '';
53
  foreach ( $conditions as $field_name => $field_value ) {
54
  if ( empty( $s_where_clause ) ) {
55
  $s_where_clause .= ' WHERE ';
@@ -62,47 +63,48 @@ class WSAL_Adapters_MySQL_Query implements WSAL_Adapters_QueryInterface {
62
  foreach ( $field_value as $or_field_name => $or_field_value ) {
63
  if ( is_array( $or_field_value ) ) {
64
  foreach ( $or_field_value as $value ) {
65
- if ( '(' != $sub_where_clause ) {
66
  $sub_where_clause .= ' OR ';
67
  }
68
  $sub_where_clause .= $or_field_name;
69
- $args[] = $value;
70
  }
71
  } else {
72
- if ( '(' != $sub_where_clause ) {
73
  $sub_where_clause .= ' OR ';
74
  }
75
  $sub_where_clause .= $or_field_name;
76
- $args[] = $or_field_value;
77
  }
78
  }
79
  $sub_where_clause .= ')';
80
- $s_where_clause .= $sub_where_clause;
81
  } else {
82
  $s_where_clause .= $field_name;
83
- $args[] = $field_value;
84
  }
85
  }
86
 
87
- $from_data_sets = $query->getFrom();
88
- $columns = $query->getColumns();
89
- $order_bys = $query->getOrderBy();
90
 
91
  $s_limit_clause = '';
92
- if ( $query->getLimit() ) {
93
  $s_limit_clause .= ' LIMIT ';
94
- if ( $query->getOffset() ) {
95
- $s_limit_clause .= $query->getOffset() . ', ';
96
  }
97
- $s_limit_clause .= $query->getLimit();
98
  }
 
99
  $join_clause = '';
100
- if ( $query->hasMetaJoin() ) {
101
- $meta = new WSAL_Adapters_MySQL_Meta( $this->connection );
102
- $occurrence = new WSAL_Adapters_MySQL_Occurrence( $this->connection );
103
- $join_clause = ' LEFT JOIN ' . $meta->GetTable() . ' AS meta ON meta.occurrence_id = ' . $occurrence->GetTable() . '.id ';
104
  }
105
- $fields = (empty( $columns )) ? $from_data_sets[0] . '.*' : implode( ',', $columns );
106
  if ( ! empty( $search_condition ) ) {
107
  $args[] = $search_condition['args'];
108
  }
@@ -118,7 +120,7 @@ class WSAL_Adapters_MySQL_Query implements WSAL_Adapters_QueryInterface {
118
  . $s_where_clause
119
  . $search_statement
120
  // @todo GROUP BY goes here
121
- . ( ! empty( $order_bys ) ? (' ORDER BY ' . implode( ', ', array_keys( $order_bys ) ) . ' ' . implode( ', ', array_values( $order_bys ) )) : '')
122
  . $s_limit_clause;
123
  return $sql;
124
  }
@@ -128,46 +130,49 @@ class WSAL_Adapters_MySQL_Query implements WSAL_Adapters_QueryInterface {
128
  *
129
  * @return WSAL_Adapters_MySQL_ActiveRecord
130
  */
131
- protected function getActiveRecordAdapter() {
132
  return new WSAL_Adapters_MySQL_ActiveRecord( $this->connection );
133
  }
134
 
135
  /**
136
- * @inheritDoc
137
  */
138
- public function Execute( $query ) {
139
  $args = array();
140
- $sql = $this->GetSql( $query, $args );
141
 
142
- $args = array_filter( $args, function ( $item ) {
143
- return ( '' !== $item );
144
- } );
 
 
 
145
 
146
- $occurrence_adapter = $query->getConnector()->getAdapter( 'Occurrence' );
147
 
148
- if ( in_array( $occurrence_adapter->GetTable(), $query->getFrom() ) ) {
149
- return $occurrence_adapter->LoadMulti( $sql, $args );
150
  } else {
151
- return $this->getActiveRecordAdapter()->LoadMulti( $sql, $args );
152
  }
153
  }
154
 
155
  /**
156
- * @inheritDoc
157
  */
158
- public function Count( $query ) {
159
  // Back up columns, use COUNT as default column and generate sql.
160
- $cols = $query->getColumns();
161
- $query->clearColumns();
162
- $query->addColumn( 'COUNT(*)' );
163
 
164
  $args = array();
165
- $sql = $this->GetSql( $query, $args );
166
 
167
  // Restore columns.
168
- $query->setColumns( $cols );
169
  // Execute query and return result.
170
- return $this->getActiveRecordAdapter()->CountQuery( $sql, $args );
171
  }
172
 
173
  /**
@@ -176,61 +181,62 @@ class WSAL_Adapters_MySQL_Query implements WSAL_Adapters_QueryInterface {
176
  * @param object $query - Query object.
177
  * @return integer counting records.
178
  */
179
- public function CountDelete( $query ) {
180
- $result = $this->GetSqlDelete( $query, true );
181
  // Execute query and return result.
182
- return $this->getActiveRecordAdapter()->CountQuery( $result['sql'], $result['args'] );
183
  }
184
 
185
  /**
186
- * @inheritDoc
187
  */
188
- public function Delete( $query ) {
189
- $result = $this->GetSqlDelete( $query );
190
- $this->DeleteMetas( $query, $result['args'] );
191
- return $this->getActiveRecordAdapter()->DeleteQuery( $result['sql'], $result['args'] );
192
  }
193
 
194
  /**
195
  * Load occurrence IDs then delete Metadata by occurrence_id
196
  *
197
- * @param object $query - Query object.
198
- * @param array $args - Args of the query.
199
  */
200
- public function DeleteMetas( $query, $args ) {
201
  // Back up columns, use COUNT as default column and generate sql.
202
- $cols = $query->getColumns();
203
- $query->clearColumns();
204
- $query->addColumn( 'id' );
205
- $sql = $this->GetSql( $query );
206
  // Restore columns.
207
- $query->setColumns( $cols );
208
 
209
- $_wpdb = $this->connection;
210
  $occ_ids = array();
211
- $sql = ( ! empty( $args ) ? $_wpdb->prepare( $sql, $args ) : $sql);
212
  foreach ( $_wpdb->get_results( $sql, ARRAY_A ) as $data ) {
213
  $occ_ids[] = $data['id'];
214
  }
215
  $meta = new WSAL_Adapters_MySQL_Meta( $this->connection );
216
- $meta->DeleteByOccurrenceIds( $occ_ids );
217
  }
218
 
219
  /**
220
  * Get the DELETE query SQL filled with the args.
221
  *
222
- * @param object $query - Query object.
223
- * @param bool $get_count - Get count.
 
224
  * @return string - Generated sql.
225
  */
226
- public function GetSqlDelete( $query, $get_count = false ) {
227
  $result = array();
228
- $args = array();
229
  // Back up columns, remove them for DELETE and generate sql.
230
- $cols = $query->getColumns();
231
- $query->clearColumns();
232
 
233
- $conditions = $query->getConditions();
234
 
235
  $s_where_clause = '';
236
  foreach ( $conditions as $field_name => $field_value ) {
@@ -240,28 +246,28 @@ class WSAL_Adapters_MySQL_Query implements WSAL_Adapters_QueryInterface {
240
  $s_where_clause .= ' AND ';
241
  }
242
  $s_where_clause .= $field_name;
243
- $args[] = $field_value;
244
  }
245
 
246
- $from_data_sets = $query->getFrom();
247
- $order_bys = $query->getOrderBy();
248
 
249
  $s_limit_clause = '';
250
- if ( $query->getLimit() ) {
251
  $s_limit_clause .= ' LIMIT ';
252
- if ( $query->getOffset() ) {
253
- $s_limit_clause .= $query->getOffset() . ', ';
254
  }
255
- $s_limit_clause .= $query->getLimit();
256
  }
257
- $result['sql'] = ($get_count ? 'SELECT COUNT(*) FROM ' : 'DELETE FROM ')
258
  . implode( ',', $from_data_sets )
259
  . $s_where_clause
260
- . ( ! empty( $order_bys ) ? (' ORDER BY ' . implode( ', ', array_keys( $order_bys ) ) . ' ' . implode( ', ', array_values( $order_bys ) )) : '')
261
  . $s_limit_clause;
262
  $result['args'] = $args;
263
  // Restore columns.
264
- $query->setColumns( $cols );
265
 
266
  return $result;
267
  }
@@ -269,22 +275,23 @@ class WSAL_Adapters_MySQL_Query implements WSAL_Adapters_QueryInterface {
269
  /**
270
  * Search by alert code OR by Metadata value.
271
  *
272
- * @param object $query - Query object.
273
  */
274
- public function SearchCondition( $query ) {
275
- $condition = $query->getSearchCondition();
276
  if ( empty( $condition ) ) {
277
  return null;
278
  }
 
279
  $search_conditions = array();
280
- $meta = new WSAL_Adapters_MySQL_Meta( $this->connection );
281
- $occurrence = new WSAL_Adapters_MySQL_Occurrence( $this->connection );
282
- if ( is_numeric( $condition ) && strlen( $condition ) == 4 ) {
283
- $search_conditions['sql'] = $occurrence->GetTable() . '.alert_id LIKE %s';
284
  } else {
285
- $search_conditions['sql'] = $occurrence->GetTable() . '.id IN (
286
  SELECT DISTINCT occurrence_id
287
- FROM ' . $meta->GetTable() . '
288
  WHERE TRIM(BOTH "\"" FROM value) LIKE %s
289
  )';
290
  }
@@ -293,9 +300,16 @@ class WSAL_Adapters_MySQL_Query implements WSAL_Adapters_QueryInterface {
293
  }
294
 
295
  /**
296
- * @inheritDoc
297
  */
298
- public function IsConnected() {
299
  return ( $this->connection && $this->connection->has_connected );
300
  }
 
 
 
 
 
 
 
301
  }
42
  /**
43
  * Get the SQL filled with the args.
44
  *
45
+ * @param WSAL_Models_Query $query - Query object.
46
+ * @param array $args - Args of the query.
47
+ *
48
  * @return string Generated sql.
49
  */
50
+ protected function get_sql( $query, &$args = array() ) {
51
+ $conditions = $query->get_conditions();
52
+ $search_condition = $this->search_condition( $query );
53
+ $s_where_clause = '';
54
  foreach ( $conditions as $field_name => $field_value ) {
55
  if ( empty( $s_where_clause ) ) {
56
  $s_where_clause .= ' WHERE ';
63
  foreach ( $field_value as $or_field_name => $or_field_value ) {
64
  if ( is_array( $or_field_value ) ) {
65
  foreach ( $or_field_value as $value ) {
66
+ if ( '(' != $sub_where_clause ) { // phpcs:ignore
67
  $sub_where_clause .= ' OR ';
68
  }
69
  $sub_where_clause .= $or_field_name;
70
+ $args[] = $value;
71
  }
72
  } else {
73
+ if ( '(' != $sub_where_clause ) { // phpcs:ignore
74
  $sub_where_clause .= ' OR ';
75
  }
76
  $sub_where_clause .= $or_field_name;
77
+ $args[] = $or_field_value;
78
  }
79
  }
80
  $sub_where_clause .= ')';
81
+ $s_where_clause .= $sub_where_clause;
82
  } else {
83
  $s_where_clause .= $field_name;
84
+ $args[] = $field_value;
85
  }
86
  }
87
 
88
+ $from_data_sets = $query->get_from();
89
+ $columns = $query->get_columns();
90
+ $order_bys = $query->get_order_by();
91
 
92
  $s_limit_clause = '';
93
+ if ( $query->get_limit() ) {
94
  $s_limit_clause .= ' LIMIT ';
95
+ if ( $query->get_offset() ) {
96
+ $s_limit_clause .= $query->get_offset() . ', ';
97
  }
98
+ $s_limit_clause .= $query->get_limit();
99
  }
100
+
101
  $join_clause = '';
102
+ if ( $query->has_meta_join() ) {
103
+ $meta = new WSAL_Adapters_MySQL_Meta( $this->connection );
104
+ $occurrence = new WSAL_Adapters_MySQL_Occurrence( $this->connection );
105
+ $join_clause = ' LEFT JOIN ' . $meta->get_table() . ' AS meta ON meta.occurrence_id = ' . $occurrence->get_table() . '.id ';
106
  }
107
+ $fields = ( empty( $columns ) ) ? $from_data_sets[0] . '.*' : implode( ',', $columns );
108
  if ( ! empty( $search_condition ) ) {
109
  $args[] = $search_condition['args'];
110
  }
120
  . $s_where_clause
121
  . $search_statement
122
  // @todo GROUP BY goes here
123
+ . ( ! empty( $order_bys ) ? ( ' ORDER BY ' . implode( ', ', array_keys( $order_bys ) ) . ' ' . implode( ', ', array_values( $order_bys ) ) ) : '' )
124
  . $s_limit_clause;
125
  return $sql;
126
  }
130
  *
131
  * @return WSAL_Adapters_MySQL_ActiveRecord
132
  */
133
+ protected function get_active_record_adapter() {
134
  return new WSAL_Adapters_MySQL_ActiveRecord( $this->connection );
135
  }
136
 
137
  /**
138
+ * {@inheritDoc}
139
  */
140
+ public function execute_query( $query ) {
141
  $args = array();
142
+ $sql = $this->get_sql( $query, $args );
143
 
144
+ $args = array_filter(
145
+ $args,
146
+ function ( $item ) {
147
+ return ( '' !== $item );
148
+ }
149
+ );
150
 
151
+ $occurrence_adapter = $query->get_connector()->get_adapter( 'Occurrence' );
152
 
153
+ if ( in_array( $occurrence_adapter->get_table(), $query->get_from(), true ) ) {
154
+ return $occurrence_adapter->load_multi( $sql, $args );
155
  } else {
156
+ return $this->get_active_record_adapter()->load_multi( $sql, $args );
157
  }
158
  }
159
 
160
  /**
161
+ * {@inheritDoc}
162
  */
163
+ public function count( $query ) {
164
  // Back up columns, use COUNT as default column and generate sql.
165
+ $cols = $query->get_columns();
166
+ $query->clear_columns();
167
+ $query->add_column( 'COUNT(*)' );
168
 
169
  $args = array();
170
+ $sql = $this->get_sql( $query, $args );
171
 
172
  // Restore columns.
173
+ $query->set_columns( $cols );
174
  // Execute query and return result.
175
+ return $this->get_active_record_adapter()->count_query( $sql, $args );
176
  }
177
 
178
  /**
181
  * @param object $query - Query object.
182
  * @return integer counting records.
183
  */
184
+ public function count_delete( $query ) {
185
+ $result = $this->get_sql_delete( $query, true );
186
  // Execute query and return result.
187
+ return $this->get_active_record_adapter()->count_query( $result['sql'], $result['args'] );
188
  }
189
 
190
  /**
191
+ * {@inheritDoc}
192
  */
193
+ public function delete( $query ) {
194
+ $result = $this->get_sql_delete( $query );
195
+ $this->delete_metas( $query, $result['args'] );
196
+ return $this->get_active_record_adapter()->delete_query( $result['sql'], $result['args'] );
197
  }
198
 
199
  /**
200
  * Load occurrence IDs then delete Metadata by occurrence_id
201
  *
202
+ * @param WSAL_Models_Query $query - Query object.
203
+ * @param array $args - Args of the query.
204
  */
205
+ public function delete_metas( $query, $args ) {
206
  // Back up columns, use COUNT as default column and generate sql.
207
+ $cols = $query->get_columns();
208
+ $query->clear_columns();
209
+ $query->add_column( 'id' );
210
+ $sql = $this->get_sql( $query );
211
  // Restore columns.
212
+ $query->set_columns( $cols );
213
 
214
+ $_wpdb = $this->connection;
215
  $occ_ids = array();
216
+ $sql = ( ! empty( $args ) ? $_wpdb->prepare( $sql, $args ) : $sql );
217
  foreach ( $_wpdb->get_results( $sql, ARRAY_A ) as $data ) {
218
  $occ_ids[] = $data['id'];
219
  }
220
  $meta = new WSAL_Adapters_MySQL_Meta( $this->connection );
221
+ $meta->delete_by_occurrence_ids( $occ_ids );
222
  }
223
 
224
  /**
225
  * Get the DELETE query SQL filled with the args.
226
  *
227
+ * @param WSAL_Models_Query $query - Query object.
228
+ * @param bool $get_count - Get count.
229
+ *
230
  * @return string - Generated sql.
231
  */
232
+ public function get_sql_delete( $query, $get_count = false ) {
233
  $result = array();
234
+ $args = array();
235
  // Back up columns, remove them for DELETE and generate sql.
236
+ $cols = $query->get_columns();
237
+ $query->clear_columns();
238
 
239
+ $conditions = $query->get_conditions();
240
 
241
  $s_where_clause = '';
242
  foreach ( $conditions as $field_name => $field_value ) {
246
  $s_where_clause .= ' AND ';
247
  }
248
  $s_where_clause .= $field_name;
249
+ $args[] = $field_value;
250
  }
251
 
252
+ $from_data_sets = $query->get_from();
253
+ $order_bys = $query->get_order_by();
254
 
255
  $s_limit_clause = '';
256
+ if ( $query->get_limit() ) {
257
  $s_limit_clause .= ' LIMIT ';
258
+ if ( $query->get_offset() ) {
259
+ $s_limit_clause .= $query->get_offset() . ', ';
260
  }
261
+ $s_limit_clause .= $query->get_limit();
262
  }
263
+ $result['sql'] = ( $get_count ? 'SELECT COUNT(*) FROM ' : 'DELETE FROM ' )
264
  . implode( ',', $from_data_sets )
265
  . $s_where_clause
266
+ . ( ! empty( $order_bys ) ? ( ' ORDER BY ' . implode( ', ', array_keys( $order_bys ) ) . ' ' . implode( ', ', array_values( $order_bys ) ) ) : '' )
267
  . $s_limit_clause;
268
  $result['args'] = $args;
269
  // Restore columns.
270
+ $query->set_columns( $cols );
271
 
272
  return $result;
273
  }
275
  /**
276
  * Search by alert code OR by Metadata value.
277
  *
278
+ * @param WSAL_Models_Query $query - Query object.
279
  */
280
+ public function search_condition( $query ) {
281
+ $condition = $query->get_search_condition();
282
  if ( empty( $condition ) ) {
283
  return null;
284
  }
285
+
286
  $search_conditions = array();
287
+ $meta = new WSAL_Adapters_MySQL_Meta( $this->connection );
288
+ $occurrence = new WSAL_Adapters_MySQL_Occurrence( $this->connection );
289
+ if ( is_numeric( $condition ) && 4 === strlen( $condition ) ) {
290
+ $search_conditions['sql'] = $occurrence->get_table() . '.alert_id LIKE %s';
291
  } else {
292
+ $search_conditions['sql'] = $occurrence->get_table() . '.id IN (
293
  SELECT DISTINCT occurrence_id
294
+ FROM ' . $meta->get_table() . '
295
  WHERE TRIM(BOTH "\"" FROM value) LIKE %s
296
  )';
297
  }
300
  }
301
 
302
  /**
303
+ * {@inheritDoc}
304
  */
305
+ public function is_connected() {
306
  return ( $this->connection && $this->connection->has_connected );
307
  }
308
+
309
+ /**
310
+ * {@inheritDoc}
311
+ */
312
+ public function Execute( $query ) {
313
+ return $this->execute_query( $query );
314
+ }
315
  }
classes/Adapters/MySQL/TmpUserAdapter.php CHANGED
@@ -29,28 +29,28 @@ class WSAL_Adapters_MySQL_TmpUser extends WSAL_Adapters_MySQL_ActiveRecord {
29
  *
30
  * @var string
31
  */
32
- protected $_table = 'wsal_tmp_users';
33
 
34
  /**
35
- * @inheritDoc
36
  *
37
  * @return WSAL_Models_TmpUser
38
  */
39
- public function GetModel() {
40
  return new WSAL_Models_TmpUser();
41
  }
42
 
43
  /**
44
- * @inheritDoc
45
  */
46
- protected function _GetInstallQuery( $prefix = false ) {
47
  $_wpdb = $this->connection;
48
- $table_name = ( $prefix ) ? $this->GetWPTable() : $this->GetTable();
49
  $sql = 'CREATE TABLE IF NOT EXISTS ' . $table_name . ' (' . PHP_EOL;
50
- $sql .= 'ID BIGINT NOT NULL,' . PHP_EOL;
51
- $sql .= 'user_login VARCHAR(60) NOT NULL,' . PHP_EOL;
52
- $sql .= 'INDEX (ID)' . PHP_EOL;
53
- $sql .= ') ' . $_wpdb->get_charset_collate();
54
 
55
  return $sql;
56
  }
29
  *
30
  * @var string
31
  */
32
+ protected $table = 'wsal_tmp_users';
33
 
34
  /**
35
+ * {@inheritDoc}
36
  *
37
  * @return WSAL_Models_TmpUser
38
  */
39
+ public function get_model() {
40
  return new WSAL_Models_TmpUser();
41
  }
42
 
43
  /**
44
+ * {@inheritDoc}
45
  */
46
+ protected function get_install_query( $prefix = false ) {
47
  $_wpdb = $this->connection;
48
+ $table_name = ( $prefix ) ? $this->get_wp_table() : $this->get_table();
49
  $sql = 'CREATE TABLE IF NOT EXISTS ' . $table_name . ' (' . PHP_EOL;
50
+ $sql .= 'ID BIGINT NOT NULL,' . PHP_EOL;
51
+ $sql .= 'user_login VARCHAR(60) NOT NULL,' . PHP_EOL;
52
+ $sql .= 'INDEX (ID)' . PHP_EOL;
53
+ $sql .= ') ' . $_wpdb->get_charset_collate();
54
 
55
  return $sql;
56
  }
classes/Adapters/OccurrenceInterface.php CHANGED
@@ -25,9 +25,9 @@ interface WSAL_Adapters_OccurrenceInterface {
25
  * @param WSAL_Models_Occurrence $occurrence - Occurrence model instance.
26
  *
27
  * @return WSAL_Models_Meta[]
28
- * @see WSAL_Adapters_MySQL_ActiveRecord::LoadArray()
29
  */
30
- public function GetMultiMeta( $occurrence );
31
 
32
  /**
33
  * Loads a meta item given its name.
@@ -36,9 +36,9 @@ interface WSAL_Adapters_OccurrenceInterface {
36
  * @param string $name - Meta name.
37
  *
38
  * @return WSAL_Models_Meta The meta item, be sure to check if it was loaded successfully.
39
- * @see WSAL_Adapters_MySQL_ActiveRecord::Load()
40
  */
41
- public function GetNamedMeta( $occurrence, $name );
42
 
43
  /**
44
  * Returns the first meta value from a given set of names.
@@ -46,11 +46,11 @@ interface WSAL_Adapters_OccurrenceInterface {
46
  * a particular detail.
47
  *
48
  * @param object $occurrence - Occurrence model instance.
49
- * @param array $names - List of meta names.
50
  *
51
  * @return WSAL_Models_Meta The first meta item that exists.
52
  */
53
- public function GetFirstNamedMeta( $occurrence, $names );
54
 
55
  /**
56
  * Gets occurrences of the same type by IP and Username within specified time frame.
@@ -59,7 +59,7 @@ interface WSAL_Adapters_OccurrenceInterface {
59
  *
60
  * @return WSAL_Models_Occurrence[]
61
  */
62
- public function CheckKnownUsers( $args = array() );
63
 
64
  /**
65
  * Gets occurrences of the same type by IP within specified time frame.
@@ -68,7 +68,7 @@ interface WSAL_Adapters_OccurrenceInterface {
68
  *
69
  * @return WSAL_Models_Occurrence[]
70
  */
71
- public function CheckUnknownUsers( $args = array() );
72
 
73
  /**
74
  * Gets occurrence by Post_id.
@@ -77,7 +77,7 @@ interface WSAL_Adapters_OccurrenceInterface {
77
  *
78
  * @return WSAL_Models_Occurrence[]
79
  */
80
- public function GetByPostID( $post_id );
81
 
82
  /**
83
  * Gets occurrences of the alert 1003.
@@ -92,7 +92,7 @@ interface WSAL_Adapters_OccurrenceInterface {
92
  * Retrieves occurrences that have metadata that needs to be migrated to the occurrences table. This relates to the
93
  * database schema change done in version 4.4.0.
94
  *
95
- * @param int $limit
96
  *
97
  * @return WSAL_Models_Occurrence[]
98
  * @since 4.4.0
25
  * @param WSAL_Models_Occurrence $occurrence - Occurrence model instance.
26
  *
27
  * @return WSAL_Models_Meta[]
28
+ * @see WSAL_Adapters_MySQL_ActiveRecord::load_array()
29
  */
30
+ public function get_multi_meta( $occurrence );
31
 
32
  /**
33
  * Loads a meta item given its name.
36
  * @param string $name - Meta name.
37
  *
38
  * @return WSAL_Models_Meta The meta item, be sure to check if it was loaded successfully.
39
+ * @see WSAL_Adapters_MySQL_ActiveRecord::load()
40
  */
41
+ public function get_named_meta( $occurrence, $name );
42
 
43
  /**
44
  * Returns the first meta value from a given set of names.
46
  * a particular detail.
47
  *
48
  * @param object $occurrence - Occurrence model instance.
49
+ * @param array $names - List of meta names.
50
  *
51
  * @return WSAL_Models_Meta The first meta item that exists.
52
  */
53
+ public function get_first_named_meta( $occurrence, $names );
54
 
55
  /**
56
  * Gets occurrences of the same type by IP and Username within specified time frame.
59
  *
60
  * @return WSAL_Models_Occurrence[]
61
  */
62
+ public function check_known_users( $args = array() );
63
 
64
  /**
65
  * Gets occurrences of the same type by IP within specified time frame.
68
  *
69
  * @return WSAL_Models_Occurrence[]
70
  */
71
+ public function check_unknown_users( $args = array() );
72
 
73
  /**
74
  * Gets occurrence by Post_id.
77
  *
78
  * @return WSAL_Models_Occurrence[]
79
  */
80
+ public function get_by_post_id( $post_id );
81
 
82
  /**
83
  * Gets occurrences of the alert 1003.
92
  * Retrieves occurrences that have metadata that needs to be migrated to the occurrences table. This relates to the
93
  * database schema change done in version 4.4.0.
94
  *
95
+ * @param int $limit Limits the number of results.
96
  *
97
  * @return WSAL_Models_Occurrence[]
98
  * @since 4.4.0
classes/Adapters/QueryInterface.php CHANGED
@@ -22,23 +22,23 @@ interface WSAL_Adapters_QueryInterface {
22
  /**
23
  * Execute query and return data as $ar_cls objects.
24
  *
25
- * @param object $query - Query object.
26
  */
27
- public function Execute( $query );
28
 
29
  /**
30
  * Count query.
31
  *
32
- * @param object $query - Query object.
33
  */
34
- public function Count( $query );
35
 
36
  /**
37
  * Query for deleting records.
38
  *
39
- * @param object $query - Query object.
40
  */
41
- public function Delete( $query );
42
 
43
  /**
44
  * Checks if the adapter is successfully connected.
@@ -46,5 +46,16 @@ interface WSAL_Adapters_QueryInterface {
46
  * @return bool True if the adapter is connected. False otherwise.
47
  * @since 4.3.2
48
  */
49
- public function IsConnected();
 
 
 
 
 
 
 
 
 
 
 
50
  }
22
  /**
23
  * Execute query and return data as $ar_cls objects.
24
  *
25
+ * @param WSAL_Models_Query $query - Query object.
26
  */
27
+ public function execute_query( $query );
28
 
29
  /**
30
  * Count query.
31
  *
32
+ * @param WSAL_Models_Query $query - Query object.
33
  */
34
+ public function count( $query );
35
 
36
  /**
37
  * Query for deleting records.
38
  *
39
+ * @param WSAL_Models_Query $query - Query object.
40
  */
41
+ public function delete( $query );
42
 
43
  /**
44
  * Checks if the adapter is successfully connected.
46
  * @return bool True if the adapter is connected. False otherwise.
47
  * @since 4.3.2
48
  */
49
+ public function is_connected();
50
+
51
+ /**
52
+ * Deprecated placeholder function.
53
+ *
54
+ * @param WSAL_Models_Query $query - Query object.
55
+ *
56
+ * @see WSAL_Adapters_QueryInterface::execute_query()
57
+ *
58
+ * @deprecated 4.4.1 Replaced by function execute_query.
59
+ */
60
+ public function Execute( $query );
61
  }
classes/Alert.php CHANGED
@@ -1,4 +1,14 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
2
 
3
  /**
4
  * WSAL_Alert Object class.
@@ -69,7 +79,7 @@ final class WSAL_Alert {
69
  * @var array
70
  * @since 4.2.1
71
  */
72
- public $metadata = [];
73
 
74
  /**
75
  * List of metadata items containing metadata key and a label to be displayed.
@@ -77,23 +87,23 @@ final class WSAL_Alert {
77
  * @var string[]
78
  * @since 4.2.1
79
  */
80
- public $links = [];
81
 
82
  /**
83
  * Constructor.
84
  *
85
  * @param integer $type - Type of alert.
86
  * @param integer $code - Code of alert.
87
- * @param string $catg - Category of alert.
88
- * @param string $subcatg - Subcategory of alert.
89
- * @param string $desc - Description.
90
- * @param string $mesg - Alert message.
91
- * @param array $metadata - List of metadata items containing metadata key and a label to be displayed.
92
- * @param string $links - This should be a list of links in form of dynamic placeholders or a metadata names.
93
- * @param string $object - Event object.
94
- * @param string $event_type - Event type.
95
  */
96
- public function __construct( $type = 0, $code = 0, $catg = '', $subcatg = '', $desc = '', $mesg = '', $metadata = [], $links = '', $object = '', $event_type = '' ) {
97
  $this->code = $type;
98
  $this->severity = $code;
99
  $this->catg = $catg;
@@ -111,46 +121,45 @@ final class WSAL_Alert {
111
  *
112
  * Note: not to be used to display any messages. Use WSAL_Models_Occurrence::GetMessage() instead.
113
  *
114
- * @param array $meta_data - (Optional) Meta data relevant to message.
115
- * @param string|null $message - (Optional) Override message template to use.
116
- * @param integer $occurrence_id - (Optional) Event occurrence ID.
117
  * @param string|false $context - Context in which the message will be used/displayed.
118
  *
119
  * @return string Fully formatted message.
120
- * @throws Freemius_Exception
121
- * @see WSAL_Models_Occurrence::GetMessage()
122
  */
123
- public function GetMessage( $meta_data = array(), $message = null, $occurrence_id = 0, $context = false ) {
124
- return $this->GetFormattedMesg( is_null( $message ) ? $this->mesg : $message, $meta_data, $occurrence_id, $context );
125
  }
126
 
127
  /**
128
  * Expands a message with variables by replacing variables with meta data values.
129
  *
130
- * @param string $original_message - The original message.
131
- * @param array $meta_data - (Optional) Meta data relevant to message.
132
- * @param integer $occurrence_id - (Optional) Event occurrence ID.
133
  * @param string|false $context - Context in which the message will be used/displayed.
134
  *
135
  * @return string The expanded message.
136
- * @throws Freemius_Exception
137
  */
138
- protected function GetFormattedMesg( $original_message, $meta_data = array(), $occurrence_id = 0, $context = false ) {
139
 
140
  $result = '';
141
 
142
- // fallback on the default context
143
  if ( false === $context ) {
144
  $context = 'default';
145
  }
146
 
147
- // get the alert formatter for given context
148
- $formatter = WSAL_AlertFormatterFactory::getFormatter( $context );
149
 
150
  // Tokenize message with regex.
151
  $message_parts = preg_split( '/(%.*?%)/', (string) $original_message, - 1, PREG_SPLIT_DELIM_CAPTURE );
152
  if ( ! is_array( $message_parts ) ) {
153
- // use the message as is
154
  $result = (string) $original_message;
155
  } else {
156
  // Handle tokenized message.
@@ -160,11 +169,11 @@ final class WSAL_Alert {
160
  continue;
161
  }
162
  // Handle escaped percent sign.
163
- if ( '%%' == $token ) {
164
  $message_parts[ $i ] = '%';
165
- } elseif ( substr( $token, 0, 1 ) == '%' && substr( $token, - 1, 1 ) == '%' ) {
166
  // Handle complex expressions.
167
- $message_parts[ $i ] = $this->GetMetaExprValue( substr( $token, 1, - 1 ), $meta_data );
168
  $message_parts[ $i ] = $formatter->format_meta_expression( $token, $message_parts[ $i ], $occurrence_id );
169
  if ( ! empty( $message_parts[ $i ] ) ) {
170
  $message_parts[ $i ] = $formatter->wrap_in_hightlight_markup( $message_parts[ $i ] );
@@ -172,12 +181,12 @@ final class WSAL_Alert {
172
  }
173
  }
174
 
175
- // Compact message
176
  $result = implode( '', $message_parts );
177
  }
178
  }
179
 
180
- // process message to make sure it any HTML tags are handled correctly
181
  $result = $formatter->process_html_tags_in_message( $result );
182
 
183
  $end_of_line = $formatter->get_end_of_line();
@@ -214,7 +223,7 @@ final class WSAL_Alert {
214
  *
215
  * @return mixed The value nearest to the expression.
216
  */
217
- protected function GetMetaExprValue( $expr, $meta_data = array() ) {
218
  $expr = preg_replace( '/%/', '', $expr );
219
  if ( 'IPAddress' === $expr ) {
220
  if ( array_key_exists( 'IPAddress', $meta_data ) ) {
@@ -235,7 +244,7 @@ final class WSAL_Alert {
235
  $meta = is_array( $meta ) && array_key_exists( $part, $meta ) ? $meta[ $part ] : ( isset( $meta->$part ) ? $meta->$part : 'NULL' );
236
  }
237
 
238
- return is_scalar( $meta ) ? (string) $meta : var_export( $meta, true );
239
  }
240
 
241
  /**
@@ -246,7 +255,6 @@ final class WSAL_Alert {
246
  * @param int $occurrence_id Occurrence ID.
247
  *
248
  * @return string
249
- * @throws Freemius_Exception
250
  * @since 4.2.1
251
  */
252
  public function get_formatted_metadata( $formatter, $meta_data, $occurrence_id ) {
@@ -276,7 +284,6 @@ final class WSAL_Alert {
276
  * @param int $occurrence_id Occurrence ID.
277
  *
278
  * @return array
279
- * @throws Freemius_Exception
280
  * @since 4.2.1
281
  */
282
  public function get_metadata_as_array( $formatter, $meta_data, $occurrence_id ) {
@@ -288,7 +295,7 @@ final class WSAL_Alert {
288
  }
289
 
290
  // Pure alert meta lookup based on meta token.
291
- $meta_expression = $this->GetMetaExprValue( $meta_token, $meta_data );
292
 
293
  // Additional alert meta processing - handles derived or decorated alert data.
294
  $meta_expression = $formatter->format_meta_expression( $meta_token, $meta_expression, $occurrence_id );
@@ -303,24 +310,25 @@ final class WSAL_Alert {
303
  }
304
 
305
  /**
306
- * @param WSAL_AlertFormatter $formatter
307
- * @param array $meta_data
308
- * @param int $occurrence_id
 
 
309
  *
310
  * @return string
311
- * @throws Freemius_Exception
312
  * @since 4.2.1
313
  */
314
  public function get_formatted_hyperlinks( $formatter, $meta_data, $occurrence_id ) {
315
  $result = '';
316
  $hyperlinks_as_array = $this->get_hyperlinks_as_array( $formatter, $meta_data, $occurrence_id );
317
  if ( ! empty( $hyperlinks_as_array ) ) {
318
- $links_result_parts = [];
319
  foreach ( $hyperlinks_as_array as $link_data ) {
320
- $link_label = $link_data['label'];
321
- $link_url = $link_data['url'];
322
  $needs_formatting = $link_data['needs_formatting'];
323
- $formatted_link = $needs_formatting ? $formatter->format_link( $link_url, $link_label ) : $link_url;
324
  array_push( $links_result_parts, $formatted_link );
325
  }
326
 
@@ -333,16 +341,21 @@ final class WSAL_Alert {
333
  }
334
 
335
  /**
336
- * @param WSAL_AlertFormatter $formatter
337
- * @param array $meta_data
338
- * @param int $occurrence_id
339
- * @param bool $exclude_links_not_needing_formatting If true, links that don't need formatting will be excluded. For example special links that contain onclick attribute already from the meta formatter.
 
 
 
 
 
340
  *
341
  * @return string
342
  * @since 4.2.1
343
  */
344
  public function get_hyperlinks_as_array( $formatter, $meta_data, $occurrence_id, $exclude_links_not_needing_formatting = false ) {
345
- $result = [];
346
  if ( ! empty( $this->links ) ) {
347
  foreach ( $this->links as $link_label => $link_data ) {
348
 
@@ -360,27 +373,29 @@ final class WSAL_Alert {
360
  $link_title = $link_data['label'];
361
  }
362
 
363
- // link url can be:
364
- // - an actual URL
365
- // - placeholder for an existing meta data field that contains a URL (or the full HTML A tag markup)
366
- // -- before 4.2.1 the CommentLink meta would contain the full HTML markup for the link, now it contains only the URL
367
- // - other placeholder for a dynamic or JS infused link that will be processed by the meta formatter
 
 
368
  $needs_formatting = true;
369
  if ( ! WSAL_Utilities_RequestUtils::is_valid_url( $link_url ) ) {
370
 
371
- $meta_expression = $this->GetMetaExprValue( $link_url, $meta_data );
372
  $meta_expression = $formatter->format_meta_expression( $link_url, $meta_expression, $occurrence_id, $meta_data );
373
  if ( ! empty( $meta_expression ) ) {
374
  if ( WSAL_Utilities_RequestUtils::is_valid_url( $meta_expression ) ) {
375
 
376
  $link_url = $meta_expression;
377
- } else if ( preg_match( '/onclick=/', $meta_expression ) ) {
378
  $link_url = $meta_expression;
379
  $needs_formatting = false;
380
  } else {
381
 
382
  preg_match( '/href=["\']https?:\/\/([^"\']+)["\']/', $meta_expression, $url_matches );
383
- if ( count( $url_matches ) == 2 ) {
384
  $link_url = $url_matches[1];
385
  }
386
  }
@@ -394,12 +409,12 @@ final class WSAL_Alert {
394
  }
395
 
396
  if ( ! empty( $link_url ) ) {
397
- $result[ $link_label ] = [
398
  'url' => $link_url,
399
  'needs_formatting' => $needs_formatting,
400
  'title' => $link_title,
401
- 'label' => $link_label
402
- ];
403
  }
404
  }
405
  }
1
  <?php
2
+ /**
3
+ * WSAL_Alert class.
4
+ *
5
+ * @package wsal
6
+ */
7
+
8
+ // Exit if accessed directly.
9
+ if ( ! defined( 'ABSPATH' ) ) {
10
+ exit;
11
+ }
12
 
13
  /**
14
  * WSAL_Alert Object class.
79
  * @var array
80
  * @since 4.2.1
81
  */
82
+ public $metadata = array();
83
 
84
  /**
85
  * List of metadata items containing metadata key and a label to be displayed.
87
  * @var string[]
88
  * @since 4.2.1
89
  */
90
+ public $links = array();
91
 
92
  /**
93
  * Constructor.
94
  *
95
  * @param integer $type - Type of alert.
96
  * @param integer $code - Code of alert.
97
+ * @param string $catg - Category of alert.
98
+ * @param string $subcatg - Subcategory of alert.
99
+ * @param string $desc - Description.
100
+ * @param string $mesg - Alert message.
101
+ * @param array $metadata - List of metadata items containing metadata key and a label to be displayed.
102
+ * @param string $links - This should be a list of links in form of dynamic placeholders or a metadata names.
103
+ * @param string $object - Event object.
104
+ * @param string $event_type - Event type.
105
  */
106
+ public function __construct( $type = 0, $code = 0, $catg = '', $subcatg = '', $desc = '', $mesg = '', $metadata = array(), $links = '', $object = '', $event_type = '' ) {
107
  $this->code = $type;
108
  $this->severity = $code;
109
  $this->catg = $catg;
121
  *
122
  * Note: not to be used to display any messages. Use WSAL_Models_Occurrence::GetMessage() instead.
123
  *
124
+ * @param array $meta_data - (Optional) Meta data relevant to message.
125
+ * @param string|null $message - (Optional) Override message template to use.
126
+ * @param integer $occurrence_id - (Optional) Event occurrence ID.
127
  * @param string|false $context - Context in which the message will be used/displayed.
128
  *
129
  * @return string Fully formatted message.
130
+ *
131
+ * @see WSAL_Models_Occurrence::get_message()
132
  */
133
+ public function get_message( $meta_data = array(), $message = null, $occurrence_id = 0, $context = false ) {
134
+ return $this->get_formatted_message( is_null( $message ) ? $this->mesg : $message, $meta_data, $occurrence_id, $context );
135
  }
136
 
137
  /**
138
  * Expands a message with variables by replacing variables with meta data values.
139
  *
140
+ * @param string $original_message - The original message.
141
+ * @param array $meta_data - (Optional) Meta data relevant to message.
142
+ * @param integer $occurrence_id - (Optional) Event occurrence ID.
143
  * @param string|false $context - Context in which the message will be used/displayed.
144
  *
145
  * @return string The expanded message.
 
146
  */
147
+ protected function get_formatted_message( $original_message, $meta_data = array(), $occurrence_id = 0, $context = false ) {
148
 
149
  $result = '';
150
 
151
+ // Fallback on the default context.
152
  if ( false === $context ) {
153
  $context = 'default';
154
  }
155
 
156
+ // Get the alert formatter for given context.
157
+ $formatter = WSAL_AlertFormatterFactory::get_formatter( $context );
158
 
159
  // Tokenize message with regex.
160
  $message_parts = preg_split( '/(%.*?%)/', (string) $original_message, - 1, PREG_SPLIT_DELIM_CAPTURE );
161
  if ( ! is_array( $message_parts ) ) {
162
+ // Use the message as is.
163
  $result = (string) $original_message;
164
  } else {
165
  // Handle tokenized message.
169
  continue;
170
  }
171
  // Handle escaped percent sign.
172
+ if ( '%%' === $token ) {
173
  $message_parts[ $i ] = '%';
174
+ } elseif ( substr( $token, 0, 1 ) === '%' && substr( $token, - 1, 1 ) === '%' ) {
175
  // Handle complex expressions.
176
+ $message_parts[ $i ] = $this->get_meta_expression_value( substr( $token, 1, - 1 ), $meta_data );
177
  $message_parts[ $i ] = $formatter->format_meta_expression( $token, $message_parts[ $i ], $occurrence_id );
178
  if ( ! empty( $message_parts[ $i ] ) ) {
179
  $message_parts[ $i ] = $formatter->wrap_in_hightlight_markup( $message_parts[ $i ] );
181
  }
182
  }
183
 
184
+ // Compact message.
185
  $result = implode( '', $message_parts );
186
  }
187
  }
188
 
189
+ // Process message to make sure it any HTML tags are handled correctly.
190
  $result = $formatter->process_html_tags_in_message( $result );
191
 
192
  $end_of_line = $formatter->get_end_of_line();
223
  *
224
  * @return mixed The value nearest to the expression.
225
  */
226
+ protected function get_meta_expression_value( $expr, $meta_data = array() ) {
227
  $expr = preg_replace( '/%/', '', $expr );
228
  if ( 'IPAddress' === $expr ) {
229
  if ( array_key_exists( 'IPAddress', $meta_data ) ) {
244
  $meta = is_array( $meta ) && array_key_exists( $part, $meta ) ? $meta[ $part ] : ( isset( $meta->$part ) ? $meta->$part : 'NULL' );
245
  }
246
 
247
+ return is_scalar( $meta ) ? (string) $meta : var_export( $meta, true ); // phpcs:ignore
248
  }
249
 
250
  /**
255
  * @param int $occurrence_id Occurrence ID.
256
  *
257
  * @return string
 
258
  * @since 4.2.1
259
  */
260
  public function get_formatted_metadata( $formatter, $meta_data, $occurrence_id ) {
284
  * @param int $occurrence_id Occurrence ID.
285
  *
286
  * @return array
 
287
  * @since 4.2.1
288
  */
289
  public function get_metadata_as_array( $formatter, $meta_data, $occurrence_id ) {
295
  }
296
 
297
  // Pure alert meta lookup based on meta token.
298
+ $meta_expression = $this->get_meta_expression_value( $meta_token, $meta_data );
299
 
300
  // Additional alert meta processing - handles derived or decorated alert data.
301
  $meta_expression = $formatter->format_meta_expression( $meta_token, $meta_expression, $occurrence_id );
310
  }
311
 
312
  /**
313
+ * Get formatter hyperlinks.
314
+ *
315
+ * @param WSAL_AlertFormatter $formatter Alert formatter.
316
+ * @param array $meta_data Meta data.
317
+ * @param int $occurrence_id Occurrence ID.
318
  *
319
  * @return string
 
320
  * @since 4.2.1
321
  */
322
  public function get_formatted_hyperlinks( $formatter, $meta_data, $occurrence_id ) {
323
  $result = '';
324
  $hyperlinks_as_array = $this->get_hyperlinks_as_array( $formatter, $meta_data, $occurrence_id );
325
  if ( ! empty( $hyperlinks_as_array ) ) {
326
+ $links_result_parts = array();
327
  foreach ( $hyperlinks_as_array as $link_data ) {
328
+ $link_label = $link_data['label'];
329
+ $link_url = $link_data['url'];
330
  $needs_formatting = $link_data['needs_formatting'];
331
+ $formatted_link = $needs_formatting ? $formatter->format_link( $link_url, $link_label ) : $link_url;
332
  array_push( $links_result_parts, $formatted_link );
333
  }
334
 
341
  }
342
 
343
  /**
344
+ * Retrieves hyperlinks as an array.
345
+ *
346
+ * @param WSAL_AlertFormatter $formatter Alert formatter.
347
+ * @param array $meta_data Meta data.
348
+ * @param int $occurrence_id Occurrence ID.
349
+ * @param bool $exclude_links_not_needing_formatting If true, links that don't need formatting will
350
+ * be excluded. For example special links that
351
+ * contain onclick attribute already from the meta
352
+ * formatter.
353
  *
354
  * @return string
355
  * @since 4.2.1
356
  */
357
  public function get_hyperlinks_as_array( $formatter, $meta_data, $occurrence_id, $exclude_links_not_needing_formatting = false ) {
358
+ $result = array();
359
  if ( ! empty( $this->links ) ) {
360
  foreach ( $this->links as $link_label => $link_data ) {
361
 
373
  $link_title = $link_data['label'];
374
  }
375
 
376
+ /**
377
+ * Link url can be:
378
+ * - an actual URL
379
+ * - placeholder for an existing metadata field that contains a URL (or the full HTML A tag markup)
380
+ * -- before 4.2.1 the CommentLink meta would contain the full HTML markup for the link, now it contains only the URL
381
+ * - other placeholder for a dynamic or JS infused link that will be processed by the meta formatter.
382
+ */
383
  $needs_formatting = true;
384
  if ( ! WSAL_Utilities_RequestUtils::is_valid_url( $link_url ) ) {
385
 
386
+ $meta_expression = $this->get_meta_expression_value( $link_url, $meta_data );
387
  $meta_expression = $formatter->format_meta_expression( $link_url, $meta_expression, $occurrence_id, $meta_data );
388
  if ( ! empty( $meta_expression ) ) {
389
  if ( WSAL_Utilities_RequestUtils::is_valid_url( $meta_expression ) ) {
390
 
391
  $link_url = $meta_expression;
392
+ } elseif ( preg_match( '/onclick=/', $meta_expression ) ) {
393
  $link_url = $meta_expression;
394
  $needs_formatting = false;
395
  } else {
396
 
397
  preg_match( '/href=["\']https?:\/\/([^"\']+)["\']/', $meta_expression, $url_matches );
398
+ if ( count( $url_matches ) === 2 ) {
399
  $link_url = $url_matches[1];
400
  }
401
  }
409
  }
410
 
411
  if ( ! empty( $link_url ) ) {
412
+ $result[ $link_label ] = array(
413
  'url' => $link_url,
414
  'needs_formatting' => $needs_formatting,
415
  'title' => $link_title,
416
+ 'label' => $link_label,
417
+ );
418
  }
419
  }
420
  }
classes/AlertFormatter.php CHANGED
@@ -4,7 +4,7 @@
4
  *
5
  * Class file for alert formatter.
6
  *
7
- * @since 4.2.1
8
  * @package wsal
9
  */
10
 
@@ -26,44 +26,70 @@ if ( ! defined( 'ABSPATH' ) ) {
26
  final class WSAL_AlertFormatter {
27
 
28
  /**
29
- * @var WpSecurityAuditLog Plugin instance.
 
 
30
  */
31
  protected $plugin;
32
 
33
- /** @var WSAL_AlertFormatterConfiguration */
 
 
 
 
34
  private $configuration;
35
 
 
 
 
 
 
 
36
  public function __construct( $plugin, $configuration ) {
37
  $this->plugin = $plugin;
38
  $this->configuration = $configuration;
39
  }
40
 
 
 
 
 
 
41
  public function get_end_of_line() {
42
- return $this->configuration->getEndOfLine();
43
  }
44
 
45
- public function set_end_of_line($value) {
46
- return $this->configuration->setEndOfLine($value);
 
 
 
 
 
 
 
47
  }
48
 
49
  /**
50
- * @param string $expression Meta expression including the surrounding percentage chars.
51
- * @param string $value Meta value.
 
 
52
  * @param int|null $occurrence_id Occurrence ID. Only present if the event was already written to the database.
 
53
  *
54
  * @return false|mixed|string|void|WP_Error
55
- * @throws Freemius_Exception
56
  *
57
  * @since 4.2.1
58
  */
59
- public function format_meta_expression( $expression, $value, $occurrence_id = null, $metadata = [] ) {
60
  switch ( true ) {
61
- case '%Message%' == $expression:
62
  return esc_html( $value );
63
 
64
- case '%MetaLink%' == $expression:
65
- // NULL value check is here because events related to user meta fields didn't have the MetaLink meta prior to version 4.3.2
66
- if ( $this->configuration->isJsInLinksAllowed() && 'NULL' !== $value ) {
67
  $label = __( 'Exclude custom field from the monitoring', 'wp-security-audit-log' );
68
  $result = "<a href=\"#\" data-object-type='{$metadata['Object']}' data-disable-custom-nonce='" . wp_create_nonce( 'disable-custom-nonce' . $value ) . "' onclick=\"return WsalDisableCustom(this, '" . $value . "');\"> {$label}</a>";
69
 
@@ -72,32 +98,36 @@ final class WSAL_AlertFormatter {
72
 
73
  return '';
74
 
75
- case in_array( $expression, array( '%path%', '%old_path%', '%FilePath%' ) ):
76
- // concatenate directory and file paths
77
  $max_length = 50;
78
- if ( $this->configuration->isJsInLinksAllowed() && strlen( $value ) > $max_length ) {
79
- $result = '<span>' . substr( $value, 0, $max_length ) . '</span>';
80
- $result .= "<a href=\"#\" data-shortened-text='{$value}'>" . $this->configuration->getEllipsesSequence() . "</a>";
81
 
82
  return $result;
83
  }
84
 
85
  return $value;
86
 
87
- case in_array( $expression, array( '%MetaValue%', '%MetaValueOld%', '%MetaValueNew%' ) ):
88
- // trim the meta value to the maximum length and append configured ellipses sequence
89
- $result = mb_strlen( $value ) > $this->configuration->getMaxMetaValueLength() ? ( mb_substr( $value, 0, 50 ) . $this->configuration->getEllipsesSequence() ) : $value;
90
 
91
  return $this->wrap_in_hightlight_markup( esc_html( $result ) );
92
 
93
- case '%ClientIP%' == $expression:
94
- case '%IPAddress%' == $expression:
95
  if ( is_string( $value ) ) {
96
- $sanitized_ips = str_replace( array(
97
- '"',
98
- '[',
99
- ']'
100
- ), '', $value );
 
 
 
 
101
 
102
  return $this->wrap_in_hightlight_markup( $sanitized_ips );
103
  } else {
@@ -112,7 +142,7 @@ final class WSAL_AlertFormatter {
112
  $post_id = $this->get_occurrence_meta_item( $occurrence_id, 'PostID' );
113
  }
114
 
115
- $occ_post = $post_id !== null ? get_post( $post_id ) : null;
116
  if ( null !== $occ_post && 'publish' === $occ_post->post_status ) {
117
  return get_permalink( $occ_post->ID );
118
  }
@@ -121,7 +151,7 @@ final class WSAL_AlertFormatter {
121
 
122
  case '%MenuUrl%' === $expression:
123
  $menu_id = null;
124
- if ( $occurrence_id === 0 && is_array( $metadata ) && array_key_exists( 'MenuID', $metadata ) ) {
125
  $menu_id = $metadata['MenuID'];
126
  } else {
127
  $menu_id = $this->get_occurrence_meta_item( $occurrence_id, 'MenuID' );
@@ -147,7 +177,7 @@ final class WSAL_AlertFormatter {
147
  }
148
 
149
  case '%LogFileText%' === $expression: // Failed login file text.
150
- if ( $this->configuration->isJsInLinksAllowed() ) {
151
  $result = '<a href="javascript:;" onclick="download_failed_login_log( this )" data-download-nonce="' . esc_attr( wp_create_nonce( 'wsal-download-failed-logins' ) ) . '" title="' . esc_html__( 'Download the log file.', 'wp-security-audit-log' ) . '">' . esc_html__( 'Download the log file.', 'wp-security-audit-log' ) . '</a>';
152
 
153
  return $this->wrap_in_hightlight_markup( $result );
@@ -161,7 +191,7 @@ final class WSAL_AlertFormatter {
161
  return $this->wrap_in_hightlight_markup( esc_html( $result ) );
162
 
163
  case '%multisite_text%' === $expression:
164
- if ( $this->plugin->IsMultisite() && $value ) {
165
  $site_info = get_blog_details( $value, true );
166
  if ( $site_info ) {
167
  $site_url = $site_info->siteurl;
@@ -182,7 +212,7 @@ final class WSAL_AlertFormatter {
182
  return $this->wrap_in_hightlight_markup( esc_html( $value ) );
183
 
184
  case '%LineBreak%' === $expression:
185
- return $this->configuration->getEndOfLine();
186
 
187
  case '%PluginFile%' === $expression:
188
  return $this->wrap_in_hightlight_markup( dirname( $value ) );
@@ -195,12 +225,16 @@ final class WSAL_AlertFormatter {
195
  * @param string $value Meta value.
196
  *
197
  * @deprecated 4.3.0 Use 'wsal_format_custom_meta' instead.
198
- *
199
  */
200
- $result = apply_filters_deprecated( 'wsal_meta_formatter_custom_formatter', array(
201
- $value,
202
- $expression
203
- ), 'WSAL 4.3.0', 'wsal_format_custom_meta' );
 
 
 
 
 
204
 
205
  /**
206
  * Allows meta formatting via filter if no match was found. Runs after the legacy filter 'wsal_meta_formatter_custom_formatter' that is kept for backwards compatibility.
@@ -211,7 +245,6 @@ final class WSAL_AlertFormatter {
211
  * @param int|null $occurrence_id Occurrence ID. Only present if the event was already written to the database. Default null.
212
  *
213
  * @since 4.3.0
214
- *
215
  */
216
  return apply_filters( 'wsal_format_custom_meta', $result, $expression, $this, $occurrence_id );
217
  }
@@ -222,12 +255,12 @@ final class WSAL_AlertFormatter {
222
  *
223
  * For example meta values displayed as <strong>{meta value}</strong> in the WP admin UI.
224
  *
225
- * @param string $value
226
  *
227
  * @return string
228
  */
229
  public function wrap_in_hightlight_markup( $value ) {
230
- return $this->configuration->getHighlightStartTag() . $value . $this->configuration->getHighlightEndTag();
231
  }
232
 
233
  /**
@@ -235,32 +268,32 @@ final class WSAL_AlertFormatter {
235
  *
236
  * For example an unknown IP address is displayed as <i>unknown</i> in the WP admin UI.
237
  *
238
- * @param string $value
239
  *
240
  * @return string
241
  */
242
  public function wrap_in_emphasis_markup( $value ) {
243
- return $this->configuration->getEmphasisStartTag() . $value . $this->configuration->getEmphasisEndTag();
244
  }
245
 
246
  /**
247
  * Helper function to get meta value from an occurrence.
248
  *
249
- * @param int $occurrence_id
250
- * @param string $meta_key
251
  *
252
  * @return mixed|null Meta value if exists. Otherwise null
253
  * @since 4.2.1
254
  */
255
  private function get_occurrence_meta_item( $occurrence_id, $meta_key ) {
256
  // get connection.
257
- $db_config = WSAL_Connector_ConnectorFactory::GetConfig(); // Get DB connector configuration.
258
- $connector = $this->plugin->getConnector( $db_config ); // Get connector for DB.
259
- $wsal_db = $connector->getConnection(); // Get DB connection.
260
 
261
  // get values needed.
262
  $meta_adapter = new WSAL_Adapters_MySQL_Meta( $wsal_db );
263
- $meta_result = $meta_adapter->LoadByNameAndOccurrenceId( $meta_key, $occurrence_id );
264
 
265
  return isset( $meta_result['value'] ) ? $meta_result['value'] : null;
266
  }
@@ -273,17 +306,16 @@ final class WSAL_AlertFormatter {
273
  * - check if the link is disabled
274
  * - optional URL processing
275
  *
276
- * @param string $url
277
- * @param string $label
278
- * @param string $title
279
- * @param string $target
280
  *
281
  * @return string
282
  * @see process_url())
283
- *
284
  */
285
- public final function format_link( $url, $label, $title = '', $target = '_blank' ) {
286
- // check for empty values
287
  if ( null === $url || empty( $url ) ) {
288
  return '';
289
  }
@@ -301,7 +333,7 @@ final class WSAL_AlertFormatter {
301
  *
302
  * Default implementation returns URL as is.
303
  *
304
- * @param string $url
305
  *
306
  * @return string
307
  */
@@ -316,16 +348,16 @@ final class WSAL_AlertFormatter {
316
  * we moved to a different implementation. Introducing another link markup would require adding link format with
317
  * placeholders to the formatter configuration.
318
  *
319
- * @param string $url
320
- * @param string $label
321
- * @param string $title
322
- * @param string $target
323
  *
324
  * @return string
325
  */
326
  protected function build_link_markup( $url, $label, $title = '', $target = '_blank' ) {
327
  $title = empty( $title ) ? $label : $title;
328
- if ( $this->configuration->canUseHtmlMarkupForLinks() ) {
329
  return '<a href="' . esc_url( $url ) . '" title="' . $title . '" target="' . $target . '">' . $label . '</a>';
330
  }
331
 
@@ -333,17 +365,21 @@ final class WSAL_AlertFormatter {
333
  }
334
 
335
  /**
336
- * @return bool True if the formatter supports hyperlinks as part of the alert message.
 
 
337
  */
338
  public function supports_hyperlinks() {
339
- return $this->configuration->isSupportsHyperlinks();
340
  }
341
 
342
  /**
343
- * @return bool True if the formatter supports metadata as part of the alert message.
 
 
344
  */
345
  public function supports_metadata() {
346
- return $this->configuration->isSupportsMetadata();
347
  }
348
 
349
  /**
@@ -353,17 +389,17 @@ final class WSAL_AlertFormatter {
353
  *
354
  * It also strips any additional HTML tags apart from hyperlink and an end of line to support legacy messages.
355
  *
356
- * @param string $message
357
  *
358
  * @return string
359
  */
360
  public function process_html_tags_in_message( $message ) {
361
  $result = preg_replace(
362
- [ '/<strong>/', '/<\/strong>/' ],
363
- [ $this->configuration->getHighlightStartTag(), $this->configuration->getHighlightEndTag() ],
364
  $message
365
  );
366
 
367
- return strip_tags( $result, $this->configuration->getTagsAllowedInMessage() );
368
  }
369
  }
4
  *
5
  * Class file for alert formatter.
6
  *
7
+ * @since 4.2.1
8
  * @package wsal
9
  */
10
 
26
  final class WSAL_AlertFormatter {
27
 
28
  /**
29
+ * Plugin instance.
30
+ *
31
+ * @var WpSecurityAuditLog
32
  */
33
  protected $plugin;
34
 
35
+ /**
36
+ * Alert formatter configuration.
37
+ *
38
+ * @var WSAL_AlertFormatterConfiguration
39
+ */
40
  private $configuration;
41
 
42
+ /**
43
+ * Constructor.
44
+ *
45
+ * @param WpSecurityAuditLog $plugin Plugin instance.
46
+ * @param WSAL_AlertFormatterConfiguration $configuration Alert formatter configuration.
47
+ */
48
  public function __construct( $plugin, $configuration ) {
49
  $this->plugin = $plugin;
50
  $this->configuration = $configuration;
51
  }
52
 
53
+ /**
54
+ * Gets the end of line character sequence.
55
+ *
56
+ * @return string End of line character sequence.
57
+ */
58
  public function get_end_of_line() {
59
+ return $this->configuration->get_end_of_line();
60
  }
61
 
62
+ /**
63
+ * Updates the end of line character sequence.
64
+ *
65
+ * @param string $value End of line character sequence.
66
+ *
67
+ * @return WSAL_AlertFormatterConfiguration
68
+ */
69
+ public function set_end_of_line( $value ) {
70
+ return $this->configuration->set_end_of_line( $value );
71
  }
72
 
73
  /**
74
+ * Formats given meta expression.
75
+ *
76
+ * @param string $expression Meta expression including the surrounding percentage chars.
77
+ * @param string $value Meta value.
78
  * @param int|null $occurrence_id Occurrence ID. Only present if the event was already written to the database.
79
+ * @param array $metadata Meta data.
80
  *
81
  * @return false|mixed|string|void|WP_Error
 
82
  *
83
  * @since 4.2.1
84
  */
85
+ public function format_meta_expression( $expression, $value, $occurrence_id = null, $metadata = array() ) {
86
  switch ( true ) {
87
+ case '%Message%' === $expression:
88
  return esc_html( $value );
89
 
90
+ case '%MetaLink%' === $expression:
91
+ // NULL value check is here because events related to user meta fields didn't have the MetaLink meta prior to version 4.3.2.
92
+ if ( $this->configuration->is_js_in_links_allowed() && 'NULL' !== $value ) {
93
  $label = __( 'Exclude custom field from the monitoring', 'wp-security-audit-log' );
94
  $result = "<a href=\"#\" data-object-type='{$metadata['Object']}' data-disable-custom-nonce='" . wp_create_nonce( 'disable-custom-nonce' . $value ) . "' onclick=\"return WsalDisableCustom(this, '" . $value . "');\"> {$label}</a>";
95
 
98
 
99
  return '';
100
 
101
+ case in_array( $expression, array( '%path%', '%old_path%', '%FilePath%' ), true ):
102
+ // Concatenate directory and file paths.
103
  $max_length = 50;
104
+ if ( $this->configuration->is_js_in_links_allowed() && strlen( $value ) > $max_length ) {
105
+ $result = '<span>' . substr( $value, 0, $max_length ) . '</span>'; // phpcs:ignore
106
+ $result .= "<a href=\"#\" data-shortened-text='{$value}'>" . $this->configuration->get_ellipses_sequence() . "</a>"; // phpcs:ignore
107
 
108
  return $result;
109
  }
110
 
111
  return $value;
112
 
113
+ case in_array( $expression, array( '%MetaValue%', '%MetaValueOld%', '%MetaValueNew%' ), true ):
114
+ // Trim the meta value to the maximum length and append configured ellipses sequence.
115
+ $result = mb_strlen( $value ) > $this->configuration->get_max_meta_value_length() ? ( mb_substr( $value, 0, 50 ) . $this->configuration->get_ellipses_sequence() ) : $value;
116
 
117
  return $this->wrap_in_hightlight_markup( esc_html( $result ) );
118
 
119
+ case '%ClientIP%' === $expression:
120
+ case '%IPAddress%' === $expression:
121
  if ( is_string( $value ) ) {
122
+ $sanitized_ips = str_replace(
123
+ array(
124
+ '"',
125
+ '[',
126
+ ']',
127
+ ),
128
+ '',
129
+ $value
130
+ );
131
 
132
  return $this->wrap_in_hightlight_markup( $sanitized_ips );
133
  } else {
142
  $post_id = $this->get_occurrence_meta_item( $occurrence_id, 'PostID' );
143
  }
144
 
145
+ $occ_post = ! is_null( $post_id ) ? get_post( $post_id ) : null;
146
  if ( null !== $occ_post && 'publish' === $occ_post->post_status ) {
147
  return get_permalink( $occ_post->ID );
148
  }
151
 
152
  case '%MenuUrl%' === $expression:
153
  $menu_id = null;
154
+ if ( 0 === $occurrence_id && is_array( $metadata ) && array_key_exists( 'MenuID', $metadata ) ) {
155
  $menu_id = $metadata['MenuID'];
156
  } else {
157
  $menu_id = $this->get_occurrence_meta_item( $occurrence_id, 'MenuID' );
177
  }
178
 
179
  case '%LogFileText%' === $expression: // Failed login file text.
180
+ if ( $this->configuration->is_js_in_links_allowed() ) {
181
  $result = '<a href="javascript:;" onclick="download_failed_login_log( this )" data-download-nonce="' . esc_attr( wp_create_nonce( 'wsal-download-failed-logins' ) ) . '" title="' . esc_html__( 'Download the log file.', 'wp-security-audit-log' ) . '">' . esc_html__( 'Download the log file.', 'wp-security-audit-log' ) . '</a>';
182
 
183
  return $this->wrap_in_hightlight_markup( $result );
191
  return $this->wrap_in_hightlight_markup( esc_html( $result ) );
192
 
193
  case '%multisite_text%' === $expression:
194
+ if ( $this->plugin->is_multisite() && $value ) {
195
  $site_info = get_blog_details( $value, true );
196
  if ( $site_info ) {
197
  $site_url = $site_info->siteurl;
212
  return $this->wrap_in_hightlight_markup( esc_html( $value ) );
213
 
214
  case '%LineBreak%' === $expression:
215
+ return $this->configuration->get_end_of_line();
216
 
217
  case '%PluginFile%' === $expression:
218
  return $this->wrap_in_hightlight_markup( dirname( $value ) );
225
  * @param string $value Meta value.
226
  *
227
  * @deprecated 4.3.0 Use 'wsal_format_custom_meta' instead.
 
228
  */
229
+ $result = apply_filters_deprecated(
230
+ 'wsal_meta_formatter_custom_formatter',
231
+ array(
232
+ $value,
233
+ $expression,
234
+ ),
235
+ 'WSAL 4.3.0',
236
+ 'wsal_format_custom_meta'
237
+ );
238
 
239
  /**
240
  * Allows meta formatting via filter if no match was found. Runs after the legacy filter 'wsal_meta_formatter_custom_formatter' that is kept for backwards compatibility.
245
  * @param int|null $occurrence_id Occurrence ID. Only present if the event was already written to the database. Default null.
246
  *
247
  * @since 4.3.0
 
248
  */
249
  return apply_filters( 'wsal_format_custom_meta', $result, $expression, $this, $occurrence_id );
250
  }
255
  *
256
  * For example meta values displayed as <strong>{meta value}</strong> in the WP admin UI.
257
  *
258
+ * @param string $value Value.
259
  *
260
  * @return string
261
  */
262
  public function wrap_in_hightlight_markup( $value ) {
263
+ return $this->configuration->get_highlight_start_tag() . $value . $this->configuration->get_highlight_end_tag();
264
  }
265
 
266
  /**
268
  *
269
  * For example an unknown IP address is displayed as <i>unknown</i> in the WP admin UI.
270
  *
271
+ * @param string $value Value.
272
  *
273
  * @return string
274
  */
275
  public function wrap_in_emphasis_markup( $value ) {
276
+ return $this->configuration->get_emphasis_start_tag() . $value . $this->configuration->get_emphasis_end_tag();
277
  }
278
 
279
  /**
280
  * Helper function to get meta value from an occurrence.
281
  *
282
+ * @param int $occurrence_id Occurrence ID.
283
+ * @param string $meta_key Meta key.
284
  *
285
  * @return mixed|null Meta value if exists. Otherwise null
286
  * @since 4.2.1
287
  */
288
  private function get_occurrence_meta_item( $occurrence_id, $meta_key ) {
289
  // get connection.
290
+ $db_config = WSAL_Connector_ConnectorFactory::get_config(); // Get DB connector configuration.
291
+ $connector = $this->plugin->get_connector( $db_config ); // Get connector for DB.
292
+ $wsal_db = $connector->get_connection(); // Get DB connection.
293
 
294
  // get values needed.
295
  $meta_adapter = new WSAL_Adapters_MySQL_Meta( $wsal_db );
296
+ $meta_result = $meta_adapter->load_by_name_and_occurrence_id( $meta_key, $occurrence_id );
297
 
298
  return isset( $meta_result['value'] ) ? $meta_result['value'] : null;
299
  }
306
  * - check if the link is disabled
307
  * - optional URL processing
308
  *
309
+ * @param string $url URL.
310
+ * @param string $label Label.
311
+ * @param string $title Title.
312
+ * @param string $target Target attribute.
313
  *
314
  * @return string
315
  * @see process_url())
 
316
  */
317
+ public function format_link( $url, $label, $title = '', $target = '_blank' ) {
318
+ // Check for empty values.
319
  if ( null === $url || empty( $url ) ) {
320
  return '';
321
  }
333
  *
334
  * Default implementation returns URL as is.
335
  *
336
+ * @param string $url URL.
337
  *
338
  * @return string
339
  */
348
  * we moved to a different implementation. Introducing another link markup would require adding link format with
349
  * placeholders to the formatter configuration.
350
  *
351
+ * @param string $url URL.
352
+ * @param string $label Label.
353
+ * @param string $title Title.
354
+ * @param string $target Target attribute.
355
  *
356
  * @return string
357
  */
358
  protected function build_link_markup( $url, $label, $title = '', $target = '_blank' ) {
359
  $title = empty( $title ) ? $label : $title;
360
+ if ( $this->configuration->can_use_html_markup_for_links() ) {
361
  return '<a href="' . esc_url( $url ) . '" title="' . $title . '" target="' . $target . '">' . $label . '</a>';
362
  }
363
 
365
  }
366
 
367
  /**
368
+ * Checks if formatter supports hyperlinks.
369
+ *
370
+ * @return bool True if formatter supports hyperlinks.
371
  */
372
  public function supports_hyperlinks() {
373
+ return $this->configuration->is_supports_hyperlinks();
374
  }
375
 
376
  /**
377
+ * Checks if the formatter supports metadata.
378
+ *
379
+ * @return bool True if formatter supports metadata.
380
  */
381
  public function supports_metadata() {
382
+ return $this->configuration->is_supports_metadata();
383
  }
384
 
385
  /**
389
  *
390
  * It also strips any additional HTML tags apart from hyperlink and an end of line to support legacy messages.
391
  *
392
+ * @param string $message Message text.
393
  *
394
  * @return string
395
  */
396
  public function process_html_tags_in_message( $message ) {
397
  $result = preg_replace(
398
+ array( '/<strong>/', '/<\/strong>/' ),
399
+ array( $this->configuration->get_highlight_start_tag(), $this->configuration->get_highlight_end_tag() ),
400
  $message
401
  );
402
 
403
+ return strip_tags( $result, $this->configuration->get_tags_allowed_in_message() );
404
  }
405
  }
classes/AlertFormatterConfiguration.php CHANGED
@@ -1,4 +1,10 @@
1
  <?php
 
 
 
 
 
 
2
 
3
  // Exit if accessed directly.
4
  if ( ! defined( 'ABSPATH' ) ) {
@@ -15,7 +21,7 @@ if ( ! defined( 'ABSPATH' ) ) {
15
  * All setter methods are fluent to allow for method chaining.
16
  *
17
  * @package wsal
18
- * @since 4.3.0
19
  */
20
  class WSAL_AlertFormatterConfiguration {
21
 
@@ -27,56 +33,78 @@ class WSAL_AlertFormatterConfiguration {
27
  protected $tags_allowed_in_message = '';
28
 
29
  /**
 
 
30
  * @var bool
31
  */
32
  protected $is_js_in_links_allowed = false;
33
 
34
  /**
 
 
35
  * @var string
36
  */
37
  protected $highlight_end_tag = '';
38
 
39
  /**
 
 
40
  * @var bool
41
  */
42
  protected $supports_hyperlinks = false;
43
 
44
  /**
 
 
45
  * @var bool
46
  */
47
  protected $supports_metadata = false;
48
 
49
  /**
 
 
50
  * @var int
51
  */
52
  protected $max_meta_value_length = 50;
53
 
54
  /**
 
 
55
  * @var string
56
  */
57
  protected $emphasis_start_tag = '';
58
 
59
  /**
 
 
60
  * @var string
61
  */
62
  protected $end_of_line = ' ';
63
 
64
  /**
 
 
65
  * @var string
66
  */
67
  protected $highlight_start_tag = '';
68
 
69
  /**
 
 
70
  * @var string
71
  */
72
  protected $emphasis_end_tag = '';
73
 
74
  /**
 
 
75
  * @var string
76
  */
77
  protected $ellipses_sequence = '...';
78
 
79
  /**
 
 
80
  * @var bool
81
  * @since 4.3.2
82
  */
@@ -96,9 +124,8 @@ class WSAL_AlertFormatterConfiguration {
96
  *
97
  * @return WSAL_AlertFormatterConfiguration
98
  */
99
- public static function buildPlainTextConfiguration() {
100
  return new WSAL_AlertFormatterConfiguration();
101
-
102
  }
103
 
104
  /**
@@ -106,234 +133,282 @@ class WSAL_AlertFormatterConfiguration {
106
  *
107
  * @return WSAL_AlertFormatterConfiguration
108
  */
109
- public static function buildHtmlConfiguration() {
110
  return ( new WSAL_AlertFormatterConfiguration() )
111
- ->setTagsAllowedInMessage( '<strong><br><a>' )
112
- ->setIsJsInLinksAllowed( true )
113
- ->setSupportsMetadata( true )
114
- ->setSupportsHyperlinks( true )
115
- ->setEmphasisStartTag( '<i>' )
116
- ->setEmphasisEndTag( '</i>' )
117
- ->setHighlightStartTag( '<strong>' )
118
- ->setHighlightEndTag( '</strong>' )
119
- ->setEndOfLine( '<br />' )
120
- ->setEllipsesSequence( '&hellip;' );
121
  }
122
 
123
  /**
124
- * @param bool $is_js_in_links_allowed
 
 
125
  *
126
  * @return WSAL_AlertFormatterConfiguration
127
  */
128
- public function setIsJsInLinksAllowed( $is_js_in_links_allowed ) {
129
  $this->is_js_in_links_allowed = $is_js_in_links_allowed;
130
 
131
  return $this;
132
  }
133
 
134
  /**
135
- * @return bool
 
 
136
  * @since 4.3.2
137
  */
138
- public function canUseHtmlMarkupForLinks(): bool {
139
  return $this->use_html_markup_for_links;
140
  }
141
 
142
  /**
143
- * @param bool $use_html_markup_for_links
 
 
144
  *
145
  * @return WSAL_AlertFormatterConfiguration
146
  * @since 4.3.2
147
- *
148
  */
149
- public function setUseHtmlMarkupForLinks( bool $use_html_markup_for_links ): WSAL_AlertFormatterConfiguration {
150
  $this->use_html_markup_for_links = $use_html_markup_for_links;
151
 
152
  return $this;
153
  }
154
 
155
  /**
156
- * @return string
 
 
157
  */
158
- public function getTagsAllowedInMessage() {
159
  return $this->tags_allowed_in_message;
160
  }
161
 
162
  /**
163
- * @param string $tags_allowed_in_message
 
 
164
  *
165
  * @return WSAL_AlertFormatterConfiguration
166
  */
167
- public function setTagsAllowedInMessage( $tags_allowed_in_message ) {
168
  $this->tags_allowed_in_message = $tags_allowed_in_message;
169
 
170
  return $this;
171
  }
172
 
173
  /**
174
- * @return bool
 
 
175
  */
176
- public function isJsInLinksAllowed() {
177
  return $this->is_js_in_links_allowed;
178
  }
179
 
180
  /**
181
- * @return string
 
 
182
  */
183
- public function getHighlightEndTag() {
184
  return $this->highlight_end_tag;
185
  }
186
 
187
  /**
188
- * @param string $highlight_end_tag
 
 
 
189
  *
190
  * @return WSAL_AlertFormatterConfiguration
191
  */
192
- public function setHighlightEndTag( $highlight_end_tag ) {
193
  $this->highlight_end_tag = $highlight_end_tag;
194
 
195
  return $this;
196
  }
197
 
198
  /**
199
- * @return bool
 
 
200
  */
201
- public function isSupportsHyperlinks() {
202
  return $this->supports_hyperlinks;
203
  }
204
 
205
  /**
206
- * @param bool $supports_hyperlinks
 
 
207
  *
208
  * @return WSAL_AlertFormatterConfiguration
209
  */
210
- public function setSupportsHyperlinks( $supports_hyperlinks ) {
211
  $this->supports_hyperlinks = $supports_hyperlinks;
212
 
213
  return $this;
214
  }
215
 
216
  /**
217
- * @return bool
 
 
218
  */
219
- public function isSupportsMetadata() {
220
  return $this->supports_metadata;
221
  }
222
 
223
  /**
224
- * @param bool $supports_metadata
 
 
225
  *
226
  * @return WSAL_AlertFormatterConfiguration
227
  */
228
- public function setSupportsMetadata( $supports_metadata ) {
229
  $this->supports_metadata = $supports_metadata;
230
 
231
  return $this;
232
  }
233
 
234
  /**
235
- * @return int
 
 
236
  */
237
- public function getMaxMetaValueLength() {
238
  return $this->max_meta_value_length;
239
  }
240
 
241
  /**
242
- * @param int $max_meta_value_length
 
 
243
  *
244
  * @return WSAL_AlertFormatterConfiguration
245
  */
246
- public function setMaxMetaValueLength( $max_meta_value_length ) {
247
  $this->max_meta_value_length = $max_meta_value_length;
248
 
249
  return $this;
250
  }
251
 
252
  /**
253
- * @return string
 
 
254
  */
255
- public function getEmphasisStartTag() {
256
  return $this->emphasis_start_tag;
257
  }
258
 
259
  /**
260
- * @param string $emphasis_start_tag
 
 
261
  *
262
  * @return WSAL_AlertFormatterConfiguration
263
  */
264
- public function setEmphasisStartTag( $emphasis_start_tag ) {
265
  $this->emphasis_start_tag = $emphasis_start_tag;
266
 
267
  return $this;
268
  }
269
 
270
  /**
271
- * @return string
 
 
272
  */
273
- public function getEndOfLine() {
274
  return $this->end_of_line;
275
  }
276
 
277
  /**
278
- * @param string $end_of_line
 
 
279
  *
280
  * @return WSAL_AlertFormatterConfiguration
281
  */
282
- public function setEndOfLine( $end_of_line ) {
283
  $this->end_of_line = $end_of_line;
284
 
285
  return $this;
286
  }
287
 
288
  /**
289
- * @return string
 
 
290
  */
291
- public function getHighlightStartTag() {
292
  return $this->highlight_start_tag;
293
  }
294
 
295
  /**
296
- * @param string $highlight_start_tag
 
 
297
  *
298
  * @return WSAL_AlertFormatterConfiguration
299
  */
300
- public function setHighlightStartTag( $highlight_start_tag ) {
301
  $this->highlight_start_tag = $highlight_start_tag;
302
 
303
  return $this;
304
  }
305
 
306
  /**
307
- * @return string
 
 
308
  */
309
- public function getEmphasisEndTag() {
310
  return $this->emphasis_end_tag;
311
  }
312
 
313
  /**
314
- * @param string $emphasis_end_tag
 
 
315
  *
316
  * @return WSAL_AlertFormatterConfiguration
317
  */
318
- public function setEmphasisEndTag( $emphasis_end_tag ) {
319
  $this->emphasis_end_tag = $emphasis_end_tag;
320
 
321
  return $this;
322
  }
323
 
324
  /**
325
- * @return string
 
 
326
  */
327
- public function getEllipsesSequence() {
328
  return $this->ellipses_sequence;
329
  }
330
 
331
  /**
332
- * @param string $ellipses_sequence
 
 
333
  *
334
  * @return WSAL_AlertFormatterConfiguration
335
  */
336
- public function setEllipsesSequence( $ellipses_sequence ) {
337
  $this->ellipses_sequence = $ellipses_sequence;
338
 
339
  return $this;
1
  <?php
2
+ /**
3
+ * Alert formatter configuration class.
4
+ *
5
+ * @package wsal
6
+ * @since 4.3.0
7
+ */
8
 
9
  // Exit if accessed directly.
10
  if ( ! defined( 'ABSPATH' ) ) {
21
  * All setter methods are fluent to allow for method chaining.
22
  *
23
  * @package wsal
24
+ * @since 4.3.0
25
  */
26
  class WSAL_AlertFormatterConfiguration {
27
 
33
  protected $tags_allowed_in_message = '';
34
 
35
  /**
36
+ * True if JS is allowed in the links.
37
+ *
38
  * @var bool
39
  */
40
  protected $is_js_in_links_allowed = false;
41
 
42
  /**
43
+ * Ending tag of highlighted section.
44
+ *
45
  * @var string
46
  */
47
  protected $highlight_end_tag = '';
48
 
49
  /**
50
+ * True if formatter supports hyperlinks.
51
+ *
52
  * @var bool
53
  */
54
  protected $supports_hyperlinks = false;
55
 
56
  /**
57
+ * True if formatter supports metadata.
58
+ *
59
  * @var bool
60
  */
61
  protected $supports_metadata = false;
62
 
63
  /**
64
+ * Maximum length of metadata value to display.
65
+ *
66
  * @var int
67
  */
68
  protected $max_meta_value_length = 50;
69
 
70
  /**
71
+ * Starting tag of emphasised section.
72
+ *
73
  * @var string
74
  */
75
  protected $emphasis_start_tag = '';
76
 
77
  /**
78
+ * End of line character sequence.
79
+ *
80
  * @var string
81
  */
82
  protected $end_of_line = ' ';
83
 
84
  /**
85
+ * Starting tag of highlighted section.
86
+ *
87
  * @var string
88
  */
89
  protected $highlight_start_tag = '';
90
 
91
  /**
92
+ * Ending tag of emphasised section.
93
+ *
94
  * @var string
95
  */
96
  protected $emphasis_end_tag = '';
97
 
98
  /**
99
+ * Ellipses character sequence.
100
+ *
101
  * @var string
102
  */
103
  protected $ellipses_sequence = '...';
104
 
105
  /**
106
+ * True if formatter uses HTML markup for links.
107
+ *
108
  * @var bool
109
  * @since 4.3.2
110
  */
124
  *
125
  * @return WSAL_AlertFormatterConfiguration
126
  */
127
+ public static function build_plain_text_configuration() {
128
  return new WSAL_AlertFormatterConfiguration();
 
129
  }
130
 
131
  /**
133
  *
134
  * @return WSAL_AlertFormatterConfiguration
135
  */
136
+ public static function build_html_configuration() {
137
  return ( new WSAL_AlertFormatterConfiguration() )
138
+ ->set_tags_allowed_in_message( '<strong><br><a>' )
139
+ ->set_is_js_in_links_allowed( true )
140
+ ->set_supports_metadata( true )
141
+ ->set_supports_hyperlinks( true )
142
+ ->set_emphasis_start_tag( '<i>' )
143
+ ->set_emphasis_end_tag( '</i>' )
144
+ ->set_highlight_start_tag( '<strong>' )
145
+ ->set_highlight_end_tag( '</strong>' )
146
+ ->set_end_of_line( '<br />' )
147
+ ->set_ellipses_sequence( '&hellip;' );
148
  }
149
 
150
  /**
151
+ * Sets the JS allowed in links settings.
152
+ *
153
+ * @param bool $is_js_in_links_allowed True if JS is supposed to allowed in the links.
154
  *
155
  * @return WSAL_AlertFormatterConfiguration
156
  */
157
+ public function set_is_js_in_links_allowed( $is_js_in_links_allowed ) {
158
  $this->is_js_in_links_allowed = $is_js_in_links_allowed;
159
 
160
  return $this;
161
  }
162
 
163
  /**
164
+ * Checks if HTML markup can be used for links.
165
+ *
166
+ * @return bool True if HTML markup can be used for links.
167
  * @since 4.3.2
168
  */
169
+ public function can_use_html_markup_for_links(): bool {
170
  return $this->use_html_markup_for_links;
171
  }
172
 
173
  /**
174
+ * Sets the "HTML markup can be used for links" option.
175
+ *
176
+ * @param bool $use_html_markup_for_links If true, HTML markup can be used for links.
177
  *
178
  * @return WSAL_AlertFormatterConfiguration
179
  * @since 4.3.2
 
180
  */
181
+ public function set_use_html_markup_for_links( bool $use_html_markup_for_links ) {
182
  $this->use_html_markup_for_links = $use_html_markup_for_links;
183
 
184
  return $this;
185
  }
186
 
187
  /**
188
+ * Returns a list of tags that are allowed in the message in format digestible by function strip_tags.
189
+ *
190
+ * @return string List of tags that are allowed in the message.
191
  */
192
+ public function get_tags_allowed_in_message() {
193
  return $this->tags_allowed_in_message;
194
  }
195
 
196
  /**
197
+ * Sets the tags allowed in the message in format digestible by function strip_tags.
198
+ *
199
+ * @param string $tags_allowed_in_message List of tags that are allowed in the message.
200
  *
201
  * @return WSAL_AlertFormatterConfiguration
202
  */
203
+ public function set_tags_allowed_in_message( $tags_allowed_in_message ) {
204
  $this->tags_allowed_in_message = $tags_allowed_in_message;
205
 
206
  return $this;
207
  }
208
 
209
  /**
210
+ * Sets the "JS is allowed in the links" option.
211
+ *
212
+ * @return bool True if JS is supposed to be allowed in the links.
213
  */
214
+ public function is_js_in_links_allowed() {
215
  return $this->is_js_in_links_allowed;
216
  }
217
 
218
  /**
219
+ * Gets the ending tag of highlighted section.
220
+ *
221
+ * @return string Ending tag of highlighted section.
222
  */
223
+ public function get_highlight_end_tag() {
224
  return $this->highlight_end_tag;
225
  }
226
 
227
  /**
228
+ *
229
+ * Sets the ending tag of highlighted section.
230
+ *
231
+ * @param string $highlight_end_tag Ending tag of highlighted section.
232
  *
233
  * @return WSAL_AlertFormatterConfiguration
234
  */
235
+ public function set_highlight_end_tag( $highlight_end_tag ) {
236
  $this->highlight_end_tag = $highlight_end_tag;
237
 
238
  return $this;
239
  }
240
 
241
  /**
242
+ * Checks if formatter supports hyperlinks.
243
+ *
244
+ * @return bool True if formatter supports hyperlinks.
245
  */
246
+ public function is_supports_hyperlinks() {
247
  return $this->supports_hyperlinks;
248
  }
249
 
250
  /**
251
+ * Sets the "formatter supports hyperlinks" setting.
252
+ *
253
+ * @param bool $supports_hyperlinks True if formatter should support hyperlinks.
254
  *
255
  * @return WSAL_AlertFormatterConfiguration
256
  */
257
+ public function set_supports_hyperlinks( $supports_hyperlinks ) {
258
  $this->supports_hyperlinks = $supports_hyperlinks;
259
 
260
  return $this;
261
  }
262
 
263
  /**
264
+ * Checks if the formatter supports metadata.
265
+ *
266
+ * @return bool True if formatter supports metadata.
267
  */
268
+ public function is_supports_metadata() {
269
  return $this->supports_metadata;
270
  }
271
 
272
  /**
273
+ * Updates the "formatter supports metadata" setting.
274
+ *
275
+ * @param bool $supports_metadata True if formatter should support metadata.
276
  *
277
  * @return WSAL_AlertFormatterConfiguration
278
  */
279
+ public function set_supports_metadata( $supports_metadata ) {
280
  $this->supports_metadata = $supports_metadata;
281
 
282
  return $this;
283
  }
284
 
285
  /**
286
+ * Gets the maximum length of metadata value to display.
287
+ *
288
+ * @return int Maximum length of metadata value to display.
289
  */
290
+ public function get_max_meta_value_length() {
291
  return $this->max_meta_value_length;
292
  }
293
 
294
  /**
295
+ * Sets the maximum length of metadata value to display.
296
+ *
297
+ * @param int $max_meta_value_length Maximum length of metadata value to display.
298
  *
299
  * @return WSAL_AlertFormatterConfiguration
300
  */
301
+ public function set_max_meta_value_length( $max_meta_value_length ) {
302
  $this->max_meta_value_length = $max_meta_value_length;
303
 
304
  return $this;
305
  }
306
 
307
  /**
308
+ * Gets the starting tag of emphasised section.
309
+ *
310
+ * @return string Starting tag of emphasised section.
311
  */
312
+ public function get_emphasis_start_tag() {
313
  return $this->emphasis_start_tag;
314
  }
315
 
316
  /**
317
+ * Updates the starting tag of emphasised section.
318
+ *
319
+ * @param string $emphasis_start_tag Starting tag of emphasised section.
320
  *
321
  * @return WSAL_AlertFormatterConfiguration
322
  */
323
+ public function set_emphasis_start_tag( $emphasis_start_tag ) {
324
  $this->emphasis_start_tag = $emphasis_start_tag;
325
 
326
  return $this;
327
  }
328
 
329
  /**
330
+ * Gets the end of line character sequence.
331
+ *
332
+ * @return string End of line character sequence.
333
  */
334
+ public function get_end_of_line() {
335
  return $this->end_of_line;
336
  }
337
 
338
  /**
339
+ * Updates the end of line character sequence.
340
+ *
341
+ * @param string $end_of_line End of line character sequence.
342
  *
343
  * @return WSAL_AlertFormatterConfiguration
344
  */
345
+ public function set_end_of_line( $end_of_line ) {
346
  $this->end_of_line = $end_of_line;
347
 
348
  return $this;
349
  }
350
 
351
  /**
352
+ * Gets the starting tag of highlighted section.
353
+ *
354
+ * @return string Starting tag of highlighted section.
355
  */
356
+ public function get_highlight_start_tag() {
357
  return $this->highlight_start_tag;
358
  }
359
 
360
  /**
361
+ * Sets the starting tag of highlighted section.
362
+ *
363
+ * @param string $highlight_start_tag Starting tag of highlighted section.
364
  *
365
  * @return WSAL_AlertFormatterConfiguration
366
  */
367
+ public function set_highlight_start_tag( $highlight_start_tag ) {
368
  $this->highlight_start_tag = $highlight_start_tag;
369
 
370
  return $this;
371
  }
372
 
373
  /**
374
+ * Ending tag of emphasised section.
375
+ *
376
+ * @return string Ending tag of emphasised section.
377
  */
378
+ public function get_emphasis_end_tag() {
379
  return $this->emphasis_end_tag;
380
  }
381
 
382
  /**
383
+ * Sets the ending tag of emphasised section.
384
+ *
385
+ * @param string $emphasis_end_tag Ending tag of emphasised section.
386
  *
387
  * @return WSAL_AlertFormatterConfiguration
388
  */
389
+ public function set_emphasis_end_tag( $emphasis_end_tag ) {
390
  $this->emphasis_end_tag = $emphasis_end_tag;
391
 
392
  return $this;
393
  }
394
 
395
  /**
396
+ * Gets the ellipses character sequence.
397
+ *
398
+ * @return string Ellipses character sequence.
399
  */
400
+ public function get_ellipses_sequence() {
401
  return $this->ellipses_sequence;
402
  }
403
 
404
  /**
405
+ * Sets the ellipses character sequence.
406
+ *
407
+ * @param string $ellipses_sequence Ellipses character sequence.
408
  *
409
  * @return WSAL_AlertFormatterConfiguration
410
  */
411
+ public function set_ellipses_sequence( $ellipses_sequence ) {
412
  $this->ellipses_sequence = $ellipses_sequence;
413
 
414
  return $this;
classes/AlertFormatterFactory.php CHANGED
@@ -23,28 +23,38 @@ if ( ! defined( 'ABSPATH' ) ) {
23
  class WSAL_AlertFormatterFactory {
24
 
25
  /**
 
 
26
  * @var WSAL_AlertFormatter[]
27
  */
28
- private static $formatter_instances = [];
29
 
30
  /**
 
 
31
  * @var WSAL_AlertFormatterConfiguration[]
32
  */
33
- private static $configurations = [];
34
 
 
 
 
35
  public static function bootstrap() {
36
 
37
- $html_configuration = WSAL_AlertFormatterConfiguration::buildHtmlConfiguration();
38
  $dashboard_widget_configuration = ( clone $html_configuration )
39
- ->setIsJsInLinksAllowed( false )
40
- ->setSupportsMetadata( false )
41
- ->setSupportsHyperlinks( false );
42
 
43
- // let extensions register custom alert formatters
44
- $formatters = apply_filters( 'wsal_alert_formatters', [
45
- 'default' => $html_configuration,
46
- 'dashboard-widget' => $dashboard_widget_configuration
47
- ] );
 
 
 
48
 
49
  if ( ! empty( $formatters ) ) {
50
  foreach ( $formatters as $context => $formatter_configuration ) {
@@ -54,37 +64,41 @@ class WSAL_AlertFormatterFactory {
54
  }
55
 
56
  /**
57
- * @param string $context
 
 
58
  *
59
  * @return WSAL_AlertFormatter
60
  */
61
- public static function getFormatter( $context = 'default' ) {
62
  try {
63
- // @todo we could allow late formatter registration using a filter here to improve performance in some cases
64
- // (for example SMS formatter would only be registered if the 'sms' context will be used to display alert message)
65
  if ( array_key_exists( $context, self::$formatter_instances ) ) {
66
  return self::$formatter_instances[ $context ];
67
  }
68
 
69
  if ( array_key_exists( $context, self::$configurations ) ) {
70
- $formatter = new WSAL_AlertFormatter( WpSecurityAuditLog::GetInstance(), self::$configurations[ $context ] );
71
 
72
  self::$formatter_instances[ $context ] = $formatter;
73
 
74
  return self::$formatter_instances[ $context ];
75
  }
76
  } catch ( Exception $exception ) {
77
- return self::createDefaultFormatter();
78
  }
79
 
80
- return self::createDefaultFormatter();
81
  }
82
 
83
  /**
84
- * @return WSAL_AlertFormatter Default formatter using full featured HTML configuration.
 
 
85
  * @since 4.3.0
86
  */
87
- private static function createDefaultFormatter() {
88
- return new WSAL_AlertFormatter( WpSecurityAuditLog::GetInstance(), WSAL_AlertFormatterConfiguration::buildHtmlConfiguration() );
89
  }
90
  }
23
  class WSAL_AlertFormatterFactory {
24
 
25
  /**
26
+ * Alert formatter instances.
27
+ *
28
  * @var WSAL_AlertFormatter[]
29
  */
30
+ private static $formatter_instances = array();
31
 
32
  /**
33
+ * Alert formatter configuration.
34
+ *
35
  * @var WSAL_AlertFormatterConfiguration[]
36
  */
37
+ private static $configurations = array();
38
 
39
+ /**
40
+ * Boostraps the factory.
41
+ */
42
  public static function bootstrap() {
43
 
44
+ $html_configuration = WSAL_AlertFormatterConfiguration::build_html_configuration();
45
  $dashboard_widget_configuration = ( clone $html_configuration )
46
+ ->set_is_js_in_links_allowed( false )
47
+ ->set_supports_metadata( false )
48
+ ->set_supports_hyperlinks( false );
49
 
50
+ // Let extensions register custom alert formatters.
51
+ $formatters = apply_filters(
52
+ 'wsal_alert_formatters',
53
+ array(
54
+ 'default' => $html_configuration,
55
+ 'dashboard-widget' => $dashboard_widget_configuration,
56
+ )
57
+ );
58
 
59
  if ( ! empty( $formatters ) ) {
60
  foreach ( $formatters as $context => $formatter_configuration ) {
64
  }
65
 
66
  /**
67
+ * Gets alert formatter for given context.
68
+ *
69
+ * @param string $context Context.
70
  *
71
  * @return WSAL_AlertFormatter
72
  */
73
+ public static function get_formatter( $context = 'default' ) {
74
  try {
75
+ // @todo we could allow late formatter registration using a filter here to improve performance in some cases
76
+ // (for example SMS formatter would only be registered if the 'sms' context will be used to display alert message)
77
  if ( array_key_exists( $context, self::$formatter_instances ) ) {
78
  return self::$formatter_instances[ $context ];
79
  }
80
 
81
  if ( array_key_exists( $context, self::$configurations ) ) {
82
+ $formatter = new WSAL_AlertFormatter( WpSecurityAuditLog::get_instance(), self::$configurations[ $context ] );
83
 
84
  self::$formatter_instances[ $context ] = $formatter;
85
 
86
  return self::$formatter_instances[ $context ];
87
  }
88
  } catch ( Exception $exception ) {
89
+ return self::create_default_formatter();
90
  }
91
 
92
+ return self::create_default_formatter();
93
  }
94
 
95
  /**
96
+ * Creates default formatter (HTML).
97
+ *
98
+ * @return WSAL_AlertFormatter Default formatter using full-featured HTML configuration.
99
  * @since 4.3.0
100
  */
101
+ private static function create_default_formatter() {
102
+ return new WSAL_AlertFormatter( WpSecurityAuditLog::get_instance(), WSAL_AlertFormatterConfiguration::build_html_configuration() );
103
  }
104
  }
classes/AlertManager.php CHANGED
@@ -27,7 +27,7 @@ final class WSAL_AlertManager {
27
  *
28
  * @var WSAL_Alert[]
29
  */
30
- protected $_alerts = array();
31
 
32
  /**
33
  * Array of Deprecated Events
@@ -43,7 +43,7 @@ final class WSAL_AlertManager {
43
  *
44
  * @var WSAL_AbstractLogger[]
45
  */
46
- protected $_loggers = array();
47
 
48
  /**
49
  * Instance of WpSecurityAuditLog.
@@ -57,14 +57,14 @@ final class WSAL_AlertManager {
57
  *
58
  * @var array
59
  */
60
- protected $_pipeline = array();
61
 
62
  /**
63
  * Contains an array of alerts that have been triggered for this request.
64
  *
65
  * @var int[]
66
  */
67
- protected $_triggered_types = array();
68
 
69
  /**
70
  * WP Users
@@ -105,10 +105,10 @@ final class WSAL_AlertManager {
105
  public function __construct( WpSecurityAuditLog $plugin ) {
106
  $this->plugin = $plugin;
107
  foreach ( WSAL_Utilities_FileSystemUtils::read_files_in_folder( dirname( __FILE__ ) . '/Loggers', '*.php' ) as $file ) {
108
- $this->AddFromFile( $file );
109
  }
110
 
111
- add_action( 'shutdown', array( $this, '_CommitPipeline' ), 8 );
112
 
113
  /**
114
  * Filter: `wsal_deprecated_event_ids`
@@ -129,13 +129,13 @@ final class WSAL_AlertManager {
129
  * @param array $ignored_cpts - Array of custom post types.
130
  *
131
  * @since 3.3.1
132
- *
133
  */
134
  $this->ignored_cpts = apply_filters(
135
  'wsal_ignored_custom_post_types',
136
  array_unique(
137
  array_merge(
138
- $this->get_disabled_post_types(), array(
 
139
  'attachment', // Attachment CPT.
140
  'revision', // Revision CPT.
141
  'nav_menu_item', // Nav menu item CPT.
@@ -146,8 +146,8 @@ final class WSAL_AlertManager {
146
  )
147
  );
148
 
149
- $this->date_format = $this->plugin->settings()->GetDateFormat();
150
- $this->sanitized_date_format = $this->plugin->settings()->GetDateFormat( true );
151
  }
152
 
153
  /**
@@ -155,9 +155,9 @@ final class WSAL_AlertManager {
155
  *
156
  * @param string $file Path to file.
157
  */
158
- public function AddFromFile( $file ) {
159
  $file = basename( $file, '.php' );
160
- $this->AddFromClass( WSAL_CLASS_PREFIX . 'Loggers_' . $file );
161
  }
162
 
163
  /**
@@ -165,8 +165,8 @@ final class WSAL_AlertManager {
165
  *
166
  * @param string $class Class name.
167
  */
168
- public function AddFromClass( $class ) {
169
- $this->AddInstance( new $class( $this->plugin ) );
170
  }
171
 
172
  /**
@@ -174,8 +174,8 @@ final class WSAL_AlertManager {
174
  *
175
  * @param WSAL_AbstractLogger $logger The new logger.
176
  */
177
- public function AddInstance( WSAL_AbstractLogger $logger ) {
178
- $this->_loggers[] = $logger;
179
  }
180
 
181
  /**
@@ -185,16 +185,15 @@ final class WSAL_AlertManager {
185
  * @param array $data - Alert data.
186
  * @param mixed $delayed - False if delayed, function if not.
187
  */
188
- public function Trigger( $type, $data = array(), $delayed = false ) {
189
- // figure out the username
190
  $username = wp_get_current_user()->user_login;
191
 
192
- // if user switching plugin class exists and filter is set to disable then try get the old user.
193
  if ( apply_filters( 'wsal_disable_user_switching_plugin_tracking', false ) && class_exists( 'user_switching' ) ) {
194
  $old_user = user_switching::get_old_user();
195
  if ( isset( $old_user->user_login ) ) {
196
- // looks like this is a switched user so setup original user
197
- // values for use when logging.
198
  $username = $old_user->user_login;
199
  $data['Username'] = $old_user->user_login;
200
  $data['CurrentUserID'] = $old_user->ID;
@@ -216,14 +215,14 @@ final class WSAL_AlertManager {
216
  $data['CurrentUserRoles'] = $roles;
217
  } else {
218
  // not a switched user so get the current user roles.
219
- $roles = $this->plugin->settings()->GetCurrentUserRoles();
220
  }
221
  if ( empty( $roles ) && ! empty( $data['CurrentUserRoles'] ) ) {
222
  $roles = $data['CurrentUserRoles'];
223
  }
224
 
225
  // Check if IP is disabled.
226
- if ( $this->IsDisabledIP() ) {
227
  return;
228
  }
229
 
@@ -235,14 +234,14 @@ final class WSAL_AlertManager {
235
  }
236
  }
237
 
238
- // If user or user role is enable then go ahead.
239
- if ( $this->CheckEnableUserRoles( $username, $roles ) ) {
240
 
241
  $data['Timestamp'] = ( isset( $data['Timestamp'] ) && ! empty( $data['Timestamp'] ) ) ? $data['Timestamp'] : current_time( 'U.u', 'true' );
242
  if ( $delayed ) {
243
- $this->TriggerIf( $type, $data, null );
244
  } else {
245
- $this->_CommitItem( $type, $data, null );
246
  }
247
  }
248
  }
@@ -255,15 +254,15 @@ final class WSAL_AlertManager {
255
  *
256
  * @return boolean - True if enable false otherwise.
257
  */
258
- public function CheckEnableUserRoles( $user, $roles ) {
259
- $is_enable = true;
260
- if ( '' != $user && $this->IsDisabledUser( $user ) ) {
261
- $is_enable = false;
262
  }
263
- if ( '' != $roles && $this->IsDisabledRole( $roles ) ) {
264
- $is_enable = false;
 
265
  }
266
- return $is_enable;
267
  }
268
 
269
  /**
@@ -273,7 +272,7 @@ final class WSAL_AlertManager {
273
  * @param array $data - Alert data.
274
  * @param callable $cond - A future condition callback (receives an object of type WSAL_AlertManager as parameter).
275
  */
276
- public function TriggerIf( $type, $data, $cond = null ) {
277
  $username = null;
278
 
279
  // if user switching plugin class exists and filter is set to disable then try get the old user.
@@ -288,12 +287,12 @@ final class WSAL_AlertManager {
288
  }
289
  }
290
 
291
- $roles = [];
292
  if ( 1000 === $type ) {
293
- // when event 1000 is triggered, the user is not logged in
294
- // we need to extract the username and user roles from the event data
295
  $username = array_key_exists( 'Username', $data ) ? $data['Username'] : null;
296
- $roles = array_key_exists( 'CurrentUserRoles', $data ) ? $data['CurrentUserRoles'] : [];
297
  } elseif ( class_exists( 'user_switching' ) && isset( $old_user ) && false !== $old_user ) {
298
  // looks like this is a switched user so setup original user
299
  // roles and values for later user.
@@ -304,11 +303,11 @@ final class WSAL_AlertManager {
304
  $data['CurrentUserRoles'] = $roles;
305
  } else {
306
  $username = wp_get_current_user()->user_login;
307
- $roles = $this->plugin->settings()->GetCurrentUserRoles();
308
  }
309
 
310
  // Check if IP is disabled.
311
- if ( $this->IsDisabledIP() ) {
312
  return;
313
  }
314
 
@@ -320,11 +319,11 @@ final class WSAL_AlertManager {
320
  }
321
  }
322
 
323
- if ( $this->CheckEnableUserRoles( $username, $roles ) ) {
324
  if ( ! array_key_exists( 'Timestamp', $data ) ) {
325
  $data['Timestamp'] = current_time( 'U.u', 'true' );
326
  }
327
- $this->_pipeline[] = array(
328
  'type' => $type,
329
  'data' => $data,
330
  'cond' => $cond,
@@ -343,19 +342,19 @@ final class WSAL_AlertManager {
343
  * @return mixed
344
  * @internal
345
  */
346
- protected function _CommitItem( $type, $data, $cond, $_retry = true ) {
347
  // Double NOT operation here is intentional. Same as ! ( bool ) [ $value ]
348
  // NOTE: return false on a true condition to compensate.
349
  if ( ! $cond || ! ! call_user_func( $cond, $this ) ) {
350
- if ( $this->IsEnabled( $type ) ) {
351
- if ( isset( $this->_alerts[ $type ] ) ) {
352
  // Ok, convert alert to a log entry.
353
- $this->_triggered_types[] = $type;
354
- $this->Log( $type, $data );
355
  } elseif ( $_retry ) {
356
  // This is the last attempt at loading alerts from default file.
357
  $this->plugin->load_defaults();
358
- return $this->_CommitItem( $type, $data, $cond, false );
359
  } else {
360
  // In general this shouldn't happen, but it could, so we handle it here.
361
  /* translators: Event ID */
@@ -371,25 +370,26 @@ final class WSAL_AlertManager {
371
  *
372
  * @internal
373
  */
374
- public function _CommitPipeline() {
375
- foreach ( $this->_pipeline as $item ) {
376
- $this->_CommitItem( $item['type'], $item['data'], $item['cond'] );
377
  }
378
  }
379
 
380
  /**
381
  * Method: True if at the end of request an alert of this type will be triggered.
382
  *
383
- * @param integer $type - Alert type ID.
384
- * @param int $count - A minimum number of event occurrences.
 
385
  * @return boolean
386
  */
387
- public function WillTrigger( $type, $count = 1 ) {
388
  $number_found = 0;
389
- foreach ( $this->_pipeline as $item ) {
390
- if ( $item['type'] == $type ) {
391
  $number_found++;
392
- if ($count == 1 || $number_found == $count) {
393
  return true;
394
  }
395
  }
@@ -404,8 +404,8 @@ final class WSAL_AlertManager {
404
  * @param int $count - A minimum number of event occurrences.
405
  * @return boolean
406
  */
407
- public function WillOrHasTriggered( $type, $count = 1 ) {
408
- return in_array( $type, $this->_triggered_types ) || $this->WillTrigger( $type, $count );
409
  }
410
 
411
  /**
@@ -415,7 +415,7 @@ final class WSAL_AlertManager {
415
  * @param string $subcategory Subcategory name.
416
  * @param array $info Event information from defaults.php.
417
  */
418
- public function Register( $category, $subcategory, $info ) {
419
 
420
  // Default for optional fields.
421
  $metadata = array();
@@ -439,7 +439,7 @@ final class WSAL_AlertManager {
439
  $links = array( $links );
440
  }
441
 
442
- if ( isset( $this->_alerts[ $code ] ) ) {
443
  add_action( 'admin_notices', array( $this, 'duplicate_event_notice' ) );
444
  /* Translators: Event ID */
445
  $error_message = sprintf( esc_html__( 'Event %s already registered with WP Activity Log.', 'wp-security-audit-log' ), $code );
@@ -451,7 +451,7 @@ final class WSAL_AlertManager {
451
  /**
452
  * WSAL Filter: `wsal_event_metadata_definition`
453
  *
454
- * Filters event meta data definition before registering specific event with the alert manager. This is the
455
  * preferred way to change metadata definition of built-in events.
456
  *
457
  * @param array $metadata - Event data.
@@ -461,7 +461,7 @@ final class WSAL_AlertManager {
461
  */
462
  $metadata = apply_filters( 'wsal_event_metadata_definition', $metadata, $code );
463
 
464
- $this->_alerts[ $code ] = new WSAL_Alert( $code, $severity, $category, $subcategory, $desc, $message, $metadata, $links, $object, $event_type );
465
  }
466
 
467
  /**
@@ -470,11 +470,11 @@ final class WSAL_AlertManager {
470
  * @param array $groups - An array with group name as the index and an array of group items as the value.
471
  * Item values is an array of [type, code, description, message, object, event type] respectively.
472
  */
473
- public function RegisterGroup( $groups ) {
474
  foreach ( $groups as $name => $group ) {
475
  foreach ( $group as $subname => $subgroup ) {
476
  foreach ( $subgroup as $item ) {
477
- $this->Register( $name, $subname, $item );
478
  }
479
  }
480
  }
@@ -504,36 +504,18 @@ final class WSAL_AlertManager {
504
  * @param integer $type Alert type.
505
  * @return boolean True if enabled, false otherwise.
506
  */
507
- public function IsEnabled( $type ) {
508
- $disabled_events = $this->GetDisabledAlerts();
509
  return ! in_array( $type, $disabled_events, true );
510
  }
511
 
512
- /**
513
- * Disables a set of alerts by type.
514
- *
515
- * @param int[] $types Alert type codes to be disabled.
516
- */
517
- public function SetDisabledAlerts( $types ) {
518
- $this->plugin->settings()->SetDisabledAlerts( $types );
519
- }
520
-
521
- /**
522
- * Method: Returns an array of disabled alerts' type code.
523
- *
524
- * @return int[]
525
- */
526
- public function GetDisabledAlerts() {
527
- return $this->plugin->settings()->GetDisabledAlerts();
528
- }
529
-
530
  /**
531
  * Method: Returns an array of loaded loggers.
532
  *
533
  * @return WSAL_AbstractLogger[]
534
  */
535
- public function GetLoggers() {
536
- return $this->_loggers;
537
  }
538
 
539
  /**
@@ -543,22 +525,22 @@ final class WSAL_AlertManager {
543
  * @param integer $event_id - Alert type.
544
  * @param array $event_data - Misc alert data.
545
  */
546
- protected function Log( $event_id, $event_data = array() ) {
547
  if ( ! isset( $event_data['ClientIP'] ) ) {
548
- $client_ip = $this->plugin->settings()->GetMainClientIP();
549
  if ( ! empty( $client_ip ) ) {
550
  $event_data['ClientIP'] = $client_ip;
551
  }
552
  }
553
- if ( ! isset( $event_data['OtherIPs'] ) && $this->plugin->settings()->IsMainIPFromProxy() ) {
554
- $other_ips = $this->plugin->settings()->GetClientIPs();
555
  if ( ! empty( $other_ips ) ) {
556
  $event_data['OtherIPs'] = $other_ips;
557
  }
558
  }
559
  if ( ! isset( $event_data['UserAgent'] ) ) {
560
  if ( isset( $_SERVER['HTTP_USER_AGENT'] ) ) {
561
- $event_data['UserAgent'] = $_SERVER['HTTP_USER_AGENT'];
562
  }
563
  }
564
  if ( ! isset( $event_data['Username'] ) && ! isset( $event_data['CurrentUserID'] ) ) {
@@ -567,26 +549,26 @@ final class WSAL_AlertManager {
567
  }
568
  }
569
  if ( ! isset( $event_data['CurrentUserRoles'] ) && function_exists( 'is_user_logged_in' ) && is_user_logged_in() ) {
570
- $current_user_roles = $this->plugin->settings()->GetCurrentUserRoles();
571
  if ( ! empty( $current_user_roles ) ) {
572
  $event_data['CurrentUserRoles'] = $current_user_roles;
573
  }
574
  }
575
 
576
- // If the user sessions plugin is loaded try attach the SessionID.
577
  if ( ! isset( $event_data['SessionID'] ) && class_exists( 'WSAL_UserSessions_Helpers' ) ) {
578
- // try get the session id generated from logged in cookie.
579
  $session_id = WSAL_UserSessions_Helpers::get_session_id_from_logged_in_user_cookie();
580
- // if we have a SessionID then add it to event_data.
581
  if ( ! empty( $session_id ) ) {
582
  $event_data['SessionID'] = $session_id;
583
  }
584
  }
585
 
586
  // Get event severity.
587
- $alert_obj = $this->GetAlert( $event_id );
588
  $alert_code = $alert_obj ? $alert_obj->severity : 0;
589
- $severity = $this->plugin->constants->GetConstantBy( 'value', $alert_code );
590
 
591
  /**
592
  * Events Severity.
@@ -603,13 +585,13 @@ final class WSAL_AlertManager {
603
  */
604
  if ( is_object( $severity ) && property_exists( $severity, 'name' ) ) {
605
  if ( 'E_CRITICAL' === $severity->name ) {
606
- // CRITICAL (500): Critical conditions.
607
  $event_data['Severity'] = 500;
608
  } elseif ( 'E_WARNING' === $severity->name ) {
609
- // WARNING (300): Exceptional occurrences that are not errors.
610
  $event_data['Severity'] = 300;
611
  } elseif ( 'E_NOTICE' === $severity->name ) {
612
- // DEBUG (100): Detailed debug information.
613
  $event_data['Severity'] = 100;
614
  } elseif ( property_exists( $severity, 'value' ) ) {
615
  $event_data['Severity'] = $severity->value;
@@ -623,8 +605,8 @@ final class WSAL_AlertManager {
623
  * @since 4.3.0
624
  */
625
  if ( ! isset( $event_data['Severity'] ) ) {
626
- // assuming this is a misclassified item and using info code.
627
- // INFO (200): Interesting events.
628
  $event_data['Severity'] = 200;
629
  }
630
 
@@ -639,7 +621,7 @@ final class WSAL_AlertManager {
639
  }
640
 
641
  // Append further details if in multisite.
642
- if ( $this->plugin->IsMultisite() ) {
643
  $event_data['SiteID'] = get_current_blog_id();
644
  $event_data['SiteURL'] = get_site_url( $event_data['SiteID'] );
645
  }
@@ -668,8 +650,8 @@ final class WSAL_AlertManager {
668
  */
669
  $event_data = apply_filters( 'wsal_event_data_before_log', $event_data, $event_id );
670
 
671
- foreach ( $this->_loggers as $logger ) {
672
- $logger->Log( $event_id, $event_data );
673
  }
674
  }
675
 
@@ -680,9 +662,9 @@ final class WSAL_AlertManager {
680
  * @param mixed $default - Returned if alert is not found.
681
  * @return WSAL_Alert
682
  */
683
- public function GetAlert( $type, $default = null ) {
684
- if ( isset( $this->_alerts[ $type ] ) ) {
685
- return $this->_alerts[ $type ];
686
  }
687
  return $default;
688
  }
@@ -692,8 +674,8 @@ final class WSAL_AlertManager {
692
  *
693
  * @return WSAL_Alert[]
694
  */
695
- public function GetAlerts() {
696
- return $this->_alerts;
697
  }
698
 
699
  /**
@@ -716,7 +698,7 @@ final class WSAL_AlertManager {
716
  public function get_alerts_by_category( $category ) {
717
  // Categorized alerts array.
718
  $alerts = array();
719
- foreach ( $this->_alerts as $alert ) {
720
  if ( $category === $alert->catg ) {
721
  $alerts[ $alert->code ] = $alert;
722
  }
@@ -733,7 +715,7 @@ final class WSAL_AlertManager {
733
  public function get_alerts_by_sub_category( $sub_category ) {
734
  // Sub-categorized alerts array.
735
  $alerts = array();
736
- foreach ( $this->_alerts as $alert ) {
737
  if ( $sub_category === $alert->subcatg ) {
738
  $alerts[ $alert->code ] = $alert;
739
  }
@@ -747,9 +729,9 @@ final class WSAL_AlertManager {
747
  * @param bool $sorted – Sort the alerts array or not.
748
  * @return array
749
  */
750
- public function GetCategorizedAlerts( $sorted = true ) {
751
  $result = array();
752
- foreach ( $this->_alerts as $alert ) {
753
  if ( ! isset( $result[ $alert->catg ] ) ) {
754
  $result[ $alert->catg ] = array();
755
  }
@@ -771,8 +753,8 @@ final class WSAL_AlertManager {
771
  * @param string $user - Username.
772
  * @return boolean True if disabled, false otherwise.
773
  */
774
- public function IsDisabledUser( $user ) {
775
- return ( in_array( $user, $this->GetDisabledUsers() ) ) ? true : false;
776
  }
777
 
778
  /**
@@ -780,8 +762,8 @@ final class WSAL_AlertManager {
780
  *
781
  * @return array.
782
  */
783
- public function GetDisabledUsers() {
784
- return $this->plugin->settings()->GetExcludedMonitoringUsers();
785
  }
786
 
787
  /**
@@ -790,10 +772,10 @@ final class WSAL_AlertManager {
790
  * @param array $roles - User roles.
791
  * @return boolean True if disabled, false otherwise.
792
  */
793
- public function IsDisabledRole( $roles ) {
794
  $is_disabled = false;
795
  foreach ( $roles as $role ) {
796
- if ( in_array( $role, $this->GetDisabledRoles() ) ) {
797
  $is_disabled = true;
798
  }
799
  }
@@ -805,8 +787,8 @@ final class WSAL_AlertManager {
805
  *
806
  * @return array
807
  */
808
- public function GetDisabledRoles() {
809
- return $this->plugin->settings()->GetExcludedMonitoringRoles();
810
  }
811
 
812
  /**
@@ -817,7 +799,7 @@ final class WSAL_AlertManager {
817
  * @since 2.6.7
818
  */
819
  public function is_disabled_post_type( $post_type ) {
820
- return ( in_array( $post_type, $this->get_disabled_post_types() ) ) ? true : false;
821
  }
822
 
823
  /**
@@ -832,11 +814,13 @@ final class WSAL_AlertManager {
832
 
833
  /**
834
  * Method: Returns if IP is disabled or not.
 
 
835
  */
836
- private function IsDisabledIP() {
837
  $is_disabled = false;
838
- $ip = $this->plugin->settings()->GetMainClientIP();
839
- $excluded_ips = $this->plugin->settings()->GetExcludedMonitoringIP();
840
 
841
  if ( ! empty( $excluded_ips ) ) {
842
  foreach ( $excluded_ips as $excluded_ip ) {
@@ -920,26 +904,26 @@ final class WSAL_AlertManager {
920
  * @since 3.2.4
921
  *
922
  * @param integer $limit – Number of events.
923
- * @return array|boolean
924
  */
925
  public function get_latest_events( $limit = 1 ) {
926
  // Occurrence query.
927
  $occ_query = new WSAL_Models_OccurrenceQuery();
928
- if ( ! $occ_query->getAdapter()->IsConnected() ) {
929
- // connection problem while using external database (if local database is used, we would see WordPress's
930
- // "Error Establishing a Database Connection" screen
931
  return false;
932
  }
933
 
934
  // Get site id.
935
  $site_id = (int) $this->plugin->settings()->get_view_site_id();
936
  if ( $site_id ) {
937
- $occ_query->addCondition( 'site_id = %d ', $site_id );
938
  }
939
 
940
- $occ_query->addOrderBy( 'created_on', true ); // Set order for latest events.
941
- $occ_query->setLimit( $limit ); // Set limit.
942
- $events = $occ_query->getAdapter()->Execute( $occ_query );
943
 
944
  if ( ! empty( $events ) && is_array( $events ) ) {
945
  return $events;
@@ -960,8 +944,8 @@ final class WSAL_AlertManager {
960
  $event_transient = 'wsal_admin_bar_event';
961
 
962
  // Check for multisite.
963
- $get_fn = $this->plugin->IsMultisite() ? 'get_site_transient' : 'get_transient';
964
- $set_fn = $this->plugin->IsMultisite() ? 'set_site_transient' : 'set_transient';
965
 
966
  $admin_bar_event = $get_fn( $event_transient );
967
  if ( false === $admin_bar_event || false !== $from_db ) {
@@ -1003,29 +987,30 @@ final class WSAL_AlertManager {
1003
  */
1004
  public function get_event_objects_data( $object = '' ) {
1005
  $objects = array(
1006
- 'user' => __( 'User', 'wp-security-audit-log' ),
1007
- 'system' => __( 'System', 'wp-security-audit-log' ),
1008
- 'plugin' => __( 'Plugin', 'wp-security-audit-log' ),
1009
- 'database' => __( 'Database', 'wp-security-audit-log' ),
1010
- 'post' => __( 'Post', 'wp-security-audit-log' ),
1011
- 'file' => __( 'File', 'wp-security-audit-log' ),
1012
- 'tag' => __( 'Tag', 'wp-security-audit-log' ),
1013
- 'comment' => __( 'Comment', 'wp-security-audit-log' ),
1014
- 'setting' => __( 'Setting', 'wp-security-audit-log' ),
1015
- 'file' => __( 'File', 'wp-security-audit-log' ),
1016
- 'system-setting' => __( 'System Setting', 'wp-security-audit-log' ),
1017
- 'mainwp-network' => __( 'MainWP Network', 'wp-security-audit-log' ),
1018
- 'mainwp' => __( 'MainWP', 'wp-security-audit-log' ),
1019
- 'category' => __( 'Category', 'wp-security-audit-log' ),
1020
- 'custom-field' => __( 'Custom Field', 'wp-security-audit-log' ),
1021
- 'widget' => __( 'Widget', 'wp-security-audit-log' ),
1022
- 'menu' => __( 'Menu', 'wp-security-audit-log' ),
1023
- 'theme' => __( 'Theme', 'wp-security-audit-log' ),
1024
- 'activity-log' => __( 'Activity log', 'wp-security-audit-log' ),
1025
- 'wp-activity-log' => __( 'WP Activity Log', 'wp-security-audit-log' ),
1026
- 'multisite-network' => __( 'Multisite Network', 'wp-security-audit-log' ),
1027
- 'ip-address' => __( 'IP Address', 'wp-security-audit-log' ),
1028
  );
 
1029
  asort( $objects );
1030
  $objects = apply_filters(
1031
  'wsal_event_objects',
@@ -1077,36 +1062,36 @@ final class WSAL_AlertManager {
1077
  */
1078
  public function get_event_type_data( $type = '' ) {
1079
  $types = array(
1080
- 'login' => __( 'Login', 'wp-security-audit-log' ),
1081
- 'logout' => __( 'Logout', 'wp-security-audit-log' ),
1082
- 'installed' => __( 'Installed', 'wp-security-audit-log' ),
1083
- 'activated' => __( 'Activated', 'wp-security-audit-log' ),
1084
- 'deactivated' => __( 'Deactivated', 'wp-security-audit-log' ),
1085
- 'uninstalled' => __( 'Uninstalled', 'wp-security-audit-log' ),
1086
- 'updated' => __( 'Updated', 'wp-security-audit-log' ),
1087
- 'created' => __( 'Created', 'wp-security-audit-log' ),
1088
- 'modified' => __( 'Modified', 'wp-security-audit-log' ),
1089
- 'deleted' => __( 'Deleted', 'wp-security-audit-log' ),
1090
- 'published' => __( 'Published', 'wp-security-audit-log' ),
1091
- 'approved' => __( 'Approved', 'wp-security-audit-log' ),
1092
- 'unapproved' => __( 'Unapproved', 'wp-security-audit-log' ),
1093
- 'enabled' => __( 'Enabled', 'wp-security-audit-log' ),
1094
- 'disabled' => __( 'Disabled', 'wp-security-audit-log' ),
1095
- 'added' => __( 'Added', 'wp-security-audit-log' ),
1096
- 'failed-login' => __( 'Failed Login', 'wp-security-audit-log' ),
1097
- 'blocked' => __( 'Blocked', 'wp-security-audit-log' ),
1098
- 'uploaded' => __( 'Uploaded', 'wp-security-audit-log' ),
1099
- 'restored' => __( 'Restored', 'wp-security-audit-log' ),
1100
- 'opened' => __( 'Opened', 'wp-security-audit-log' ),
1101
- 'viewed' => __( 'Viewed', 'wp-security-audit-log' ),
1102
- 'started' => __( 'Started', 'wp-security-audit-log' ),
1103
- 'stopped' => __( 'Stopped', 'wp-security-audit-log' ),
1104
- 'removed' => __( 'Removed', 'wp-security-audit-log' ),
1105
- 'unblocked' => __( 'Unblocked', 'wp-security-audit-log' ),
1106
- 'renamed' => __( 'Renamed', 'wp-security-audit-log' ),
1107
- 'duplicated' => __( 'Duplicated', 'wp-security-audit-log' ),
1108
- 'submitted' => __( 'Submitted', 'wp-security-audit-log' ),
1109
- 'revoked' => __( 'Revoked', 'wp-security-audit-log' ),
1110
  );
1111
  // sort the types alphabetically.
1112
  asort( $types );
@@ -1148,27 +1133,17 @@ final class WSAL_AlertManager {
1148
  * @return string
1149
  */
1150
  public function get_display_event_type_text( $event_type ) {
1151
- // Try get string from the companion data method.
1152
  return get_event_type_data( $event_type );
1153
  }
1154
 
1155
- /**
1156
- * Modify post name values to include MySQL wildcards.
1157
- *
1158
- * @param string $search_value – Searched post name.
1159
- * @return string
1160
- */
1161
- private function add_string_wildcards( $search_value ) {
1162
- return '%' . $search_value . '%';
1163
- }
1164
-
1165
  /**
1166
  * Return sub-categorized events of WSAL.
1167
  *
1168
  * @return array
1169
  */
1170
  public function get_sub_categorized_events() {
1171
- $cg_alerts = $this->GetCategorizedAlerts();
1172
  $events = array();
1173
 
1174
  foreach ( $cg_alerts as $group ) {
@@ -1220,7 +1195,7 @@ final class WSAL_AlertManager {
1220
  }
1221
 
1222
  // Get MainWP dashboard user ids.
1223
- $result = $wpdb->get_results( $sql, ARRAY_A );
1224
 
1225
  $users = array();
1226
  if ( ! empty( $result ) ) {
@@ -1314,7 +1289,6 @@ final class WSAL_AlertManager {
1314
  * @param string $context Display context.
1315
  *
1316
  * @return array|false Alert details.
1317
- * @throws Exception
1318
  */
1319
  public function get_alert_details( $entry, $context = 'default' ) {
1320
  $entry_id = $entry->id;
@@ -1338,16 +1312,16 @@ final class WSAL_AlertManager {
1338
  $user_id = ( ! is_numeric( $user_id ) && null !== $user_id ) ? WSAL_Utilities_UsersUtils::swap_login_for_id( $user_id ) : $user_id;
1339
 
1340
  // Get alert details.
1341
- $code = $this->GetAlert( $alert_id );
1342
  $code = $code ? $code->severity : 0;
1343
  $const = (object) array(
1344
  'name' => 'E_UNKNOWN',
1345
  'value' => 0,
1346
  'description' => __( 'Unknown error code.', 'wp-security-audit-log' ),
1347
  );
1348
- $const = $this->plugin->constants->GetConstantBy( 'value', $code, $const );
1349
 
1350
- $blog_info = WSAL_AlertManager::get_blog_info( $this->plugin, $site_id );
1351
 
1352
  // Get the alert message - properly.
1353
  $occurrence->id = $entry_id;
@@ -1362,18 +1336,18 @@ final class WSAL_AlertManager {
1362
  $occurrence->post_id = $entry->post_id;
1363
  $occurrence->post_type = $entry->post_type;
1364
  $occurrence->post_status = $entry->post_status;
1365
- $occurrence->SetUserRoles( $roles );
1366
 
1367
- $event_metadata = $occurrence->GetMetaArray();
1368
- if ( ! $occurrence->_cachedMessage ) {
1369
- $occurrence->_cachedMessage = $occurrence->GetAlert()->GetMessage( $event_metadata, null, $entry_id, $context );
1370
  }
1371
 
1372
  if ( ! $user_id ) {
1373
  $username = __( 'System', 'wp-security-audit-log' );
1374
  $roles = '';
1375
  } else {
1376
- $username = WSAL_Utilities_UsersUtils::GetUsername( $event_metadata );
1377
  }
1378
 
1379
  // Meta details.
@@ -1382,13 +1356,13 @@ final class WSAL_AlertManager {
1382
  'blog_name' => $blog_info['name'],
1383
  'blog_url' => $blog_info['url'],
1384
  'alert_id' => $alert_id,
1385
- 'date' => WSAL_Utilities_DateTimeFormatter::instance()->getFormattedDateTime( $created_on ),
1386
  // We need to keep the timestamp to be able to group entries by dates etc. The "date" field is not suitable
1387
  // as it is already translated, thus difficult to parse and process.
1388
  'timestamp' => $created_on,
1389
  'code' => $const->name,
1390
  // Fill variables in message.
1391
- 'message' => $occurrence->GetMessage( $event_metadata, $context ),
1392
  'user_id' => $user_id,
1393
  'user_name' => $username,
1394
  'user_data' => $user_id ? $this->get_event_user_data( $username ) : false,
@@ -1412,7 +1386,7 @@ final class WSAL_AlertManager {
1412
  */
1413
  public static function get_blog_info( $plugin, $site_id ) {
1414
  // Blog details.
1415
- if ( $plugin->IsMultisite() ) {
1416
  $blog_info = get_blog_details( $site_id, true );
1417
  $blog_name = esc_html__( 'Unknown Site', 'wp-security-audit-log' );
1418
  $blog_url = '';
@@ -1449,4 +1423,72 @@ final class WSAL_AlertManager {
1449
  public function get_wp_users(): array {
1450
  return $this->wp_users;
1451
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1452
  }
27
  *
28
  * @var WSAL_Alert[]
29
  */
30
+ protected $alerts = array();
31
 
32
  /**
33
  * Array of Deprecated Events
43
  *
44
  * @var WSAL_AbstractLogger[]
45
  */
46
+ protected $loggers = array();
47
 
48
  /**
49
  * Instance of WpSecurityAuditLog.
57
  *
58
  * @var array
59
  */
60
+ protected $pipeline = array();
61
 
62
  /**
63
  * Contains an array of alerts that have been triggered for this request.
64
  *
65
  * @var int[]
66
  */
67
+ protected $triggered_types = array();
68
 
69
  /**
70
  * WP Users
105
  public function __construct( WpSecurityAuditLog $plugin ) {
106
  $this->plugin = $plugin;
107
  foreach ( WSAL_Utilities_FileSystemUtils::read_files_in_folder( dirname( __FILE__ ) . '/Loggers', '*.php' ) as $file ) {
108
+ $this->add_logger_from_file( $file );
109
  }
110
 
111
+ add_action( 'shutdown', array( $this, 'commit_pipeline' ), 8 );
112
 
113
  /**
114
  * Filter: `wsal_deprecated_event_ids`
129
  * @param array $ignored_cpts - Array of custom post types.
130
  *
131
  * @since 3.3.1
 
132
  */
133
  $this->ignored_cpts = apply_filters(
134
  'wsal_ignored_custom_post_types',
135
  array_unique(
136
  array_merge(
137
+ $this->get_disabled_post_types(),
138
+ array(
139
  'attachment', // Attachment CPT.
140
  'revision', // Revision CPT.
141
  'nav_menu_item', // Nav menu item CPT.
146
  )
147
  );
148
 
149
+ $this->date_format = $this->plugin->settings()->get_date_format();
150
+ $this->sanitized_date_format = $this->plugin->settings()->get_date_format( true );
151
  }
152
 
153
  /**
155
  *
156
  * @param string $file Path to file.
157
  */
158
+ public function add_logger_from_file( $file ) {
159
  $file = basename( $file, '.php' );
160
+ $this->add_logger_from_class( WSAL_CLASS_PREFIX . 'Loggers_' . $file );
161
  }
162
 
163
  /**
165
  *
166
  * @param string $class Class name.
167
  */
168
+ public function add_logger_from_class( $class ) {
169
+ $this->add_logger_instance( new $class( $this->plugin ) );
170
  }
171
 
172
  /**
174
  *
175
  * @param WSAL_AbstractLogger $logger The new logger.
176
  */
177
+ public function add_logger_instance( WSAL_AbstractLogger $logger ) {
178
+ $this->loggers[] = $logger;
179
  }
180
 
181
  /**
185
  * @param array $data - Alert data.
186
  * @param mixed $delayed - False if delayed, function if not.
187
  */
188
+ public function trigger_event( $type, $data = array(), $delayed = false ) {
189
+ // Figure out the username.
190
  $username = wp_get_current_user()->user_login;
191
 
192
+ // If user switching plugin class exists and filter is set to disable then try to get the old user.
193
  if ( apply_filters( 'wsal_disable_user_switching_plugin_tracking', false ) && class_exists( 'user_switching' ) ) {
194
  $old_user = user_switching::get_old_user();
195
  if ( isset( $old_user->user_login ) ) {
196
+ // Looks like this is a switched user so setup original user values for use when logging.
 
197
  $username = $old_user->user_login;
198
  $data['Username'] = $old_user->user_login;
199
  $data['CurrentUserID'] = $old_user->ID;
215
  $data['CurrentUserRoles'] = $roles;
216
  } else {
217
  // not a switched user so get the current user roles.
218
+ $roles = $this->plugin->settings()->get_current_user_roles();
219
  }
220
  if ( empty( $roles ) && ! empty( $data['CurrentUserRoles'] ) ) {
221
  $roles = $data['CurrentUserRoles'];
222
  }
223
 
224
  // Check if IP is disabled.
225
+ if ( $this->is_ip_address_disabled() ) {
226
  return;
227
  }
228
 
234
  }
235
  }
236
 
237
+ // If user or user role is enabled then go ahead.
238
+ if ( $this->check_enable_user_roles( $username, $roles ) ) {
239
 
240
  $data['Timestamp'] = ( isset( $data['Timestamp'] ) && ! empty( $data['Timestamp'] ) ) ? $data['Timestamp'] : current_time( 'U.u', 'true' );
241
  if ( $delayed ) {
242
+ $this->trigger_event_if( $type, $data, null );
243
  } else {
244
+ $this->commit_item( $type, $data, null );
245
  }
246
  }
247
  }
254
  *
255
  * @return boolean - True if enable false otherwise.
256
  */
257
+ public function check_enable_user_roles( $user, $roles ) {
258
+ if ( '' != $user && $this->is_disabled_user( $user ) ) { // phpcs:ignore
259
+ return false;
 
260
  }
261
+
262
+ if ( '' != $roles && $this->is_disabled_role( $roles ) ) { // phpcs:ignore
263
+ return false;
264
  }
265
+ return true;
266
  }
267
 
268
  /**
272
  * @param array $data - Alert data.
273
  * @param callable $cond - A future condition callback (receives an object of type WSAL_AlertManager as parameter).
274
  */
275
+ public function trigger_event_if( $type, $data, $cond = null ) {
276
  $username = null;
277
 
278
  // if user switching plugin class exists and filter is set to disable then try get the old user.
287
  }
288
  }
289
 
290
+ $roles = array();
291
  if ( 1000 === $type ) {
292
+ // When event 1000 is triggered, the user is not logged in.
293
+ // We need to extract the username and user roles from the event data.
294
  $username = array_key_exists( 'Username', $data ) ? $data['Username'] : null;
295
+ $roles = array_key_exists( 'CurrentUserRoles', $data ) ? $data['CurrentUserRoles'] : array();
296
  } elseif ( class_exists( 'user_switching' ) && isset( $old_user ) && false !== $old_user ) {
297
  // looks like this is a switched user so setup original user
298
  // roles and values for later user.
303
  $data['CurrentUserRoles'] = $roles;
304
  } else {
305
  $username = wp_get_current_user()->user_login;
306
+ $roles = $this->plugin->settings()->get_current_user_roles();
307
  }
308
 
309
  // Check if IP is disabled.
310
+ if ( $this->is_ip_address_disabled() ) {
311
  return;
312
  }
313
 
319
  }
320
  }
321
 
322
+ if ( $this->check_enable_user_roles( $username, $roles ) ) {
323
  if ( ! array_key_exists( 'Timestamp', $data ) ) {
324
  $data['Timestamp'] = current_time( 'U.u', 'true' );
325
  }
326
+ $this->pipeline[] = array(
327
  'type' => $type,
328
  'data' => $data,
329
  'cond' => $cond,
342
  * @return mixed
343
  * @internal
344
  */
345
+ protected function commit_item( $type, $data, $cond, $_retry = true ) {
346
  // Double NOT operation here is intentional. Same as ! ( bool ) [ $value ]
347
  // NOTE: return false on a true condition to compensate.
348
  if ( ! $cond || ! ! call_user_func( $cond, $this ) ) {
349
+ if ( $this->is_enabled( $type ) ) {
350
+ if ( isset( $this->alerts[ $type ] ) ) {
351
  // Ok, convert alert to a log entry.
352
+ $this->triggered_types[] = $type;
353
+ $this->log( $type, $data );
354
  } elseif ( $_retry ) {
355
  // This is the last attempt at loading alerts from default file.
356
  $this->plugin->load_defaults();
357
+ return $this->commit_item( $type, $data, $cond, false );
358
  } else {
359
  // In general this shouldn't happen, but it could, so we handle it here.
360
  /* translators: Event ID */
370
  *
371
  * @internal
372
  */
373
+ public function commit_pipeline() {
374
+ foreach ( $this->pipeline as $item ) {
375
+ $this->commit_item( $item['type'], $item['data'], $item['cond'] );
376
  }
377
  }
378
 
379
  /**
380
  * Method: True if at the end of request an alert of this type will be triggered.
381
  *
382
+ * @param integer $type - Alert type ID.
383
+ * @param int $count - A minimum number of event occurrences.
384
+ *
385
  * @return boolean
386
  */
387
+ public function will_trigger( $type, $count = 1 ) {
388
  $number_found = 0;
389
+ foreach ( $this->pipeline as $item ) {
390
+ if ( $item['type'] == $type ) { // phpcs:ignore
391
  $number_found++;
392
+ if ($count == 1 || $number_found == $count) { // phpcs:ignore
393
  return true;
394
  }
395
  }
404
  * @param int $count - A minimum number of event occurrences.
405
  * @return boolean
406
  */
407
+ public function will_or_has_triggered( $type, $count = 1 ) {
408
+ return in_array( $type, $this->triggered_types ) || $this->will_trigger( $type, $count ); // phpcs:ignore
409
  }
410
 
411
  /**
415
  * @param string $subcategory Subcategory name.
416
  * @param array $info Event information from defaults.php.
417
  */
418
+ public function register( $category, $subcategory, $info ) {
419
 
420
  // Default for optional fields.
421
  $metadata = array();
439
  $links = array( $links );
440
  }
441
 
442
+ if ( isset( $this->alerts[ $code ] ) ) {
443
  add_action( 'admin_notices', array( $this, 'duplicate_event_notice' ) );
444
  /* Translators: Event ID */
445
  $error_message = sprintf( esc_html__( 'Event %s already registered with WP Activity Log.', 'wp-security-audit-log' ), $code );
451
  /**
452
  * WSAL Filter: `wsal_event_metadata_definition`
453
  *
454
+ * Filters event metadata definition before registering specific event with the alert manager. This is the
455
  * preferred way to change metadata definition of built-in events.
456
  *
457
  * @param array $metadata - Event data.
461
  */
462
  $metadata = apply_filters( 'wsal_event_metadata_definition', $metadata, $code );
463
 
464
+ $this->alerts[ $code ] = new WSAL_Alert( $code, $severity, $category, $subcategory, $desc, $message, $metadata, $links, $object, $event_type );
465
  }
466
 
467
  /**
470
  * @param array $groups - An array with group name as the index and an array of group items as the value.
471
  * Item values is an array of [type, code, description, message, object, event type] respectively.
472
  */
473
+ public function register_group( $groups ) {
474
  foreach ( $groups as $name => $group ) {
475
  foreach ( $group as $subname => $subgroup ) {
476
  foreach ( $subgroup as $item ) {
477
+ $this->register( $name, $subname, $item );
478
  }
479
  }
480
  }
504
  * @param integer $type Alert type.
505
  * @return boolean True if enabled, false otherwise.
506
  */
507
+ public function is_enabled( $type ) {
508
+ $disabled_events = $this->plugin->settings()->get_disabled_alerts();
509
  return ! in_array( $type, $disabled_events, true );
510
  }
511
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
512
  /**
513
  * Method: Returns an array of loaded loggers.
514
  *
515
  * @return WSAL_AbstractLogger[]
516
  */
517
+ public function get_loggers() {
518
+ return $this->loggers;
519
  }
520
 
521
  /**
525
  * @param integer $event_id - Alert type.
526
  * @param array $event_data - Misc alert data.
527
  */
528
+ protected function log( $event_id, $event_data = array() ) {
529
  if ( ! isset( $event_data['ClientIP'] ) ) {
530
+ $client_ip = $this->plugin->settings()->get_main_client_ip();
531
  if ( ! empty( $client_ip ) ) {
532
  $event_data['ClientIP'] = $client_ip;
533
  }
534
  }
535
+ if ( ! isset( $event_data['OtherIPs'] ) && $this->plugin->settings()->is_main_ip_from_proxy() ) {
536
+ $other_ips = $this->plugin->settings()->get_client_ips();
537
  if ( ! empty( $other_ips ) ) {
538
  $event_data['OtherIPs'] = $other_ips;
539
  }
540
  }
541
  if ( ! isset( $event_data['UserAgent'] ) ) {
542
  if ( isset( $_SERVER['HTTP_USER_AGENT'] ) ) {
543
+ $event_data['UserAgent'] = $_SERVER['HTTP_USER_AGENT']; // phpcs:ignore
544
  }
545
  }
546
  if ( ! isset( $event_data['Username'] ) && ! isset( $event_data['CurrentUserID'] ) ) {
549
  }
550
  }
551
  if ( ! isset( $event_data['CurrentUserRoles'] ) && function_exists( 'is_user_logged_in' ) && is_user_logged_in() ) {
552
+ $current_user_roles = $this->plugin->settings()->get_current_user_roles();
553
  if ( ! empty( $current_user_roles ) ) {
554
  $event_data['CurrentUserRoles'] = $current_user_roles;
555
  }
556
  }
557
 
558
+ // If the user sessions plugin is loaded try to attach the SessionID.
559
  if ( ! isset( $event_data['SessionID'] ) && class_exists( 'WSAL_UserSessions_Helpers' ) ) {
560
+ // Try to get the session id generated from logged in cookie.
561
  $session_id = WSAL_UserSessions_Helpers::get_session_id_from_logged_in_user_cookie();
562
+ // If we have a SessionID then add it to event_data.
563
  if ( ! empty( $session_id ) ) {
564
  $event_data['SessionID'] = $session_id;
565
  }
566
  }
567
 
568
  // Get event severity.
569
+ $alert_obj = $this->get_alert( $event_id );
570
  $alert_code = $alert_obj ? $alert_obj->severity : 0;
571
+ $severity = $this->plugin->constants->get_constant_by( 'value', $alert_code );
572
 
573
  /**
574
  * Events Severity.
585
  */
586
  if ( is_object( $severity ) && property_exists( $severity, 'name' ) ) {
587
  if ( 'E_CRITICAL' === $severity->name ) {
588
+ // CRITICAL (500): Critical conditions.
589
  $event_data['Severity'] = 500;
590
  } elseif ( 'E_WARNING' === $severity->name ) {
591
+ // WARNING (300): Exceptional occurrences that are not errors.
592
  $event_data['Severity'] = 300;
593
  } elseif ( 'E_NOTICE' === $severity->name ) {
594
+ // DEBUG (100): Detailed debug information.
595
  $event_data['Severity'] = 100;
596
  } elseif ( property_exists( $severity, 'value' ) ) {
597
  $event_data['Severity'] = $severity->value;
605
  * @since 4.3.0
606
  */
607
  if ( ! isset( $event_data['Severity'] ) ) {
608
+ // Assuming this is a misclassified item and using info code.
609
+ // INFO (200): Interesting events.
610
  $event_data['Severity'] = 200;
611
  }
612
 
621
  }
622
 
623
  // Append further details if in multisite.
624
+ if ( $this->plugin->is_multisite() ) {
625
  $event_data['SiteID'] = get_current_blog_id();
626
  $event_data['SiteURL'] = get_site_url( $event_data['SiteID'] );
627
  }
650
  */
651
  $event_data = apply_filters( 'wsal_event_data_before_log', $event_data, $event_id );
652
 
653
+ foreach ( $this->loggers as $logger ) {
654
+ $logger->log( $event_id, $event_data );
655
  }
656
  }
657
 
662
  * @param mixed $default - Returned if alert is not found.
663
  * @return WSAL_Alert
664
  */
665
+ public function get_alert( $type, $default = null ) {
666
+ if ( isset( $this->alerts[ $type ] ) ) {
667
+ return $this->alerts[ $type ];
668
  }
669
  return $default;
670
  }
674
  *
675
  * @return WSAL_Alert[]
676
  */
677
+ public function get_alerts() {
678
+ return $this->alerts;
679
  }
680
 
681
  /**
698
  public function get_alerts_by_category( $category ) {
699
  // Categorized alerts array.
700
  $alerts = array();
701
+ foreach ( $this->alerts as $alert ) {
702
  if ( $category === $alert->catg ) {
703
  $alerts[ $alert->code ] = $alert;
704
  }
715
  public function get_alerts_by_sub_category( $sub_category ) {
716
  // Sub-categorized alerts array.
717
  $alerts = array();
718
+ foreach ( $this->alerts as $alert ) {
719
  if ( $sub_category === $alert->subcatg ) {
720
  $alerts[ $alert->code ] = $alert;
721
  }
729
  * @param bool $sorted – Sort the alerts array or not.
730
  * @return array
731
  */
732
+ public function get_categorized_alerts( $sorted = true ) {
733
  $result = array();
734
+ foreach ( $this->alerts as $alert ) {
735
  if ( ! isset( $result[ $alert->catg ] ) ) {
736
  $result[ $alert->catg ] = array();
737
  }
753
  * @param string $user - Username.
754
  * @return boolean True if disabled, false otherwise.
755
  */
756
+ public function is_disabled_user( $user ) {
757
+ return in_array( $user, $this->get_disabled_users() ); // phpcs:ignore
758
  }
759
 
760
  /**
762
  *
763
  * @return array.
764
  */
765
+ public function get_disabled_users() {
766
+ return $this->plugin->settings()->get_excluded_monitoring_users();
767
  }
768
 
769
  /**
772
  * @param array $roles - User roles.
773
  * @return boolean True if disabled, false otherwise.
774
  */
775
+ public function is_disabled_role( $roles ) {
776
  $is_disabled = false;
777
  foreach ( $roles as $role ) {
778
+ if ( in_array( $role, $this->get_disabled_roles() ) ) { // phpcs:ignore
779
  $is_disabled = true;
780
  }
781
  }
787
  *
788
  * @return array
789
  */
790
+ public function get_disabled_roles() {
791
+ return $this->plugin->settings()->get_excluded_monitoring_roles();
792
  }
793
 
794
  /**
799
  * @since 2.6.7
800
  */
801
  public function is_disabled_post_type( $post_type ) {
802
+ return in_array( $post_type, $this->get_disabled_post_types(), true );
803
  }
804
 
805
  /**
814
 
815
  /**
816
  * Method: Returns if IP is disabled or not.
817
+ *
818
+ * @return bool True if current IP address is disabled.
819
  */
820
+ private function is_ip_address_disabled() {
821
  $is_disabled = false;
822
+ $ip = $this->plugin->settings()->get_main_client_ip();
823
+ $excluded_ips = $this->plugin->settings()->get_excluded_monitoring_ip();
824
 
825
  if ( ! empty( $excluded_ips ) ) {
826
  foreach ( $excluded_ips as $excluded_ip ) {
904
  * @since 3.2.4
905
  *
906
  * @param integer $limit – Number of events.
907
+ * @return WSAL_Models_Occurrence[]|boolean
908
  */
909
  public function get_latest_events( $limit = 1 ) {
910
  // Occurrence query.
911
  $occ_query = new WSAL_Models_OccurrenceQuery();
912
+ if ( ! $occ_query->get_adapter()->is_connected() ) {
913
+ // Connection problem while using external database (if local database is used, we would see WordPress's
914
+ // "Error Establishing a Database Connection" screen).
915
  return false;
916
  }
917
 
918
  // Get site id.
919
  $site_id = (int) $this->plugin->settings()->get_view_site_id();
920
  if ( $site_id ) {
921
+ $occ_query->add_condition( 'site_id = %d ', $site_id );
922
  }
923
 
924
+ $occ_query->add_order_by( 'created_on', true ); // Set order for latest events.
925
+ $occ_query->set_limit( $limit ); // Set limit.
926
+ $events = $occ_query->get_adapter()->execute_query( $occ_query );
927
 
928
  if ( ! empty( $events ) && is_array( $events ) ) {
929
  return $events;
944
  $event_transient = 'wsal_admin_bar_event';
945
 
946
  // Check for multisite.
947
+ $get_fn = $this->plugin->is_multisite() ? 'get_site_transient' : 'get_transient';
948
+ $set_fn = $this->plugin->is_multisite() ? 'set_site_transient' : 'set_transient';
949
 
950
  $admin_bar_event = $get_fn( $event_transient );
951
  if ( false === $admin_bar_event || false !== $from_db ) {
987
  */
988
  public function get_event_objects_data( $object = '' ) {
989
  $objects = array(
990
+ 'user' => esc_html__( 'User', 'wp-security-audit-log' ),
991
+ 'system' => esc_html__( 'System', 'wp-security-audit-log' ),
992
+ 'plugin' => esc_html__( 'Plugin', 'wp-security-audit-log' ),
993
+ 'database' => esc_html__( 'Database', 'wp-security-audit-log' ),
994
+ 'post' => esc_html__( 'Post', 'wp-security-audit-log' ),
995
+ 'file' => esc_html__( 'File', 'wp-security-audit-log' ),
996
+ 'tag' => esc_html__( 'Tag', 'wp-security-audit-log' ),
997
+ 'comment' => esc_html__( 'Comment', 'wp-security-audit-log' ),
998
+ 'setting' => esc_html__( 'Setting', 'wp-security-audit-log' ),
999
+ 'file' => esc_html__( 'File', 'wp-security-audit-log' ),
1000
+ 'system-setting' => esc_html__( 'System Setting', 'wp-security-audit-log' ),
1001
+ 'mainwp-network' => esc_html__( 'MainWP Network', 'wp-security-audit-log' ),
1002
+ 'mainwp' => esc_html__( 'MainWP', 'wp-security-audit-log' ),
1003
+ 'category' => esc_html__( 'Category', 'wp-security-audit-log' ),
1004
+ 'custom-field' => esc_html__( 'Custom Field', 'wp-security-audit-log' ),
1005
+ 'widget' => esc_html__( 'Widget', 'wp-security-audit-log' ),
1006
+ 'menu' => esc_html__( 'Menu', 'wp-security-audit-log' ),
1007
+ 'theme' => esc_html__( 'Theme', 'wp-security-audit-log' ),
1008
+ 'activity-log' => esc_html__( 'Activity log', 'wp-security-audit-log' ),
1009
+ 'wp-activity-log' => esc_html__( 'WP Activity Log', 'wp-security-audit-log' ),
1010
+ 'multisite-network' => esc_html__( 'Multisite Network', 'wp-security-audit-log' ),
1011
+ 'ip-address' => esc_html__( 'IP Address', 'wp-security-audit-log' ),
1012
  );
1013
+
1014
  asort( $objects );
1015
  $objects = apply_filters(
1016
  'wsal_event_objects',
1062
  */
1063
  public function get_event_type_data( $type = '' ) {
1064
  $types = array(
1065
+ 'login' => esc_html__( 'Login', 'wp-security-audit-log' ),
1066
+ 'logout' => esc_html__( 'Logout', 'wp-security-audit-log' ),
1067
+ 'installed' => esc_html__( 'Installed', 'wp-security-audit-log' ),
1068
+ 'activated' => esc_html__( 'Activated', 'wp-security-audit-log' ),
1069
+ 'deactivated' => esc_html__( 'Deactivated', 'wp-security-audit-log' ),
1070
+ 'uninstalled' => esc_html__( 'Uninstalled', 'wp-security-audit-log' ),
1071
+ 'updated' => esc_html__( 'Updated', 'wp-security-audit-log' ),
1072
+ 'created' => esc_html__( 'Created', 'wp-security-audit-log' ),
1073
+ 'modified' => esc_html__( 'Modified', 'wp-security-audit-log' ),
1074
+ 'deleted' => esc_html__( 'Deleted', 'wp-security-audit-log' ),
1075
+ 'published' => esc_html__( 'Published', 'wp-security-audit-log' ),
1076
+ 'approved' => esc_html__( 'Approved', 'wp-security-audit-log' ),
1077
+ 'unapproved' => esc_html__( 'Unapproved', 'wp-security-audit-log' ),
1078
+ 'enabled' => esc_html__( 'Enabled', 'wp-security-audit-log' ),
1079
+ 'disabled' => esc_html__( 'Disabled', 'wp-security-audit-log' ),
1080
+ 'added' => esc_html__( 'Added', 'wp-security-audit-log' ),
1081
+ 'failed-login' => esc_html__( 'Failed Login', 'wp-security-audit-log' ),
1082
+ 'blocked' => esc_html__( 'Blocked', 'wp-security-audit-log' ),
1083
+ 'uploaded' => esc_html__( 'Uploaded', 'wp-security-audit-log' ),
1084
+ 'restored' => esc_html__( 'Restored', 'wp-security-audit-log' ),
1085
+ 'opened' => esc_html__( 'Opened', 'wp-security-audit-log' ),
1086
+ 'viewed' => esc_html__( 'Viewed', 'wp-security-audit-log' ),
1087
+ 'started' => esc_html__( 'Started', 'wp-security-audit-log' ),
1088
+ 'stopped' => esc_html__( 'Stopped', 'wp-security-audit-log' ),
1089
+ 'removed' => esc_html__( 'Removed', 'wp-security-audit-log' ),
1090
+ 'unblocked' => esc_html__( 'Unblocked', 'wp-security-audit-log' ),
1091
+ 'renamed' => esc_html__( 'Renamed', 'wp-security-audit-log' ),
1092
+ 'duplicated' => esc_html__( 'Duplicated', 'wp-security-audit-log' ),
1093
+ 'submitted' => esc_html__( 'Submitted', 'wp-security-audit-log' ),
1094
+ 'revoked' => esc_html__( 'Revoked', 'wp-security-audit-log' ),
1095
  );
1096
  // sort the types alphabetically.
1097
  asort( $types );
1133
  * @return string
1134
  */
1135
  public function get_display_event_type_text( $event_type ) {
1136
+ // Try to get string from the companion data method.
1137
  return get_event_type_data( $event_type );
1138
  }
1139
 
 
 
 
 
 
 
 
 
 
 
1140
  /**
1141
  * Return sub-categorized events of WSAL.
1142
  *
1143
  * @return array
1144
  */
1145
  public function get_sub_categorized_events() {
1146
+ $cg_alerts = $this->get_categorized_alerts();
1147
  $events = array();
1148
 
1149
  foreach ( $cg_alerts as $group ) {
1195
  }
1196
 
1197
  // Get MainWP dashboard user ids.
1198
+ $result = $wpdb->get_results( $sql, ARRAY_A ); // phpcs:ignore
1199
 
1200
  $users = array();
1201
  if ( ! empty( $result ) ) {
1289
  * @param string $context Display context.
1290
  *
1291
  * @return array|false Alert details.
 
1292
  */
1293
  public function get_alert_details( $entry, $context = 'default' ) {
1294
  $entry_id = $entry->id;
1312
  $user_id = ( ! is_numeric( $user_id ) && null !== $user_id ) ? WSAL_Utilities_UsersUtils::swap_login_for_id( $user_id ) : $user_id;
1313
 
1314
  // Get alert details.
1315
+ $code = $this->get_alert( $alert_id );
1316
  $code = $code ? $code->severity : 0;
1317
  $const = (object) array(
1318
  'name' => 'E_UNKNOWN',
1319
  'value' => 0,
1320
  'description' => __( 'Unknown error code.', 'wp-security-audit-log' ),
1321
  );
1322
+ $const = $this->plugin->constants->get_constant_by( 'value', $code, $const );
1323
 
1324
+ $blog_info = self::get_blog_info( $this->plugin, $site_id );
1325
 
1326
  // Get the alert message - properly.
1327
  $occurrence->id = $entry_id;
1336
  $occurrence->post_id = $entry->post_id;
1337
  $occurrence->post_type = $entry->post_type;
1338
  $occurrence->post_status = $entry->post_status;
1339
+ $occurrence->set_user_roles( $roles );
1340
 
1341
+ $event_metadata = $occurrence->get_meta_array();
1342
+ if ( ! $occurrence->_cached_message ) {
1343
+ $occurrence->_cached_message = $occurrence->get_alert()->get_message( $event_metadata, null, $entry_id, $context );
1344
  }
1345
 
1346
  if ( ! $user_id ) {
1347
  $username = __( 'System', 'wp-security-audit-log' );
1348
  $roles = '';
1349
  } else {
1350
+ $username = WSAL_Utilities_UsersUtils::get_username( $event_metadata );
1351
  }
1352
 
1353
  // Meta details.
1356
  'blog_name' => $blog_info['name'],
1357
  'blog_url' => $blog_info['url'],
1358
  'alert_id' => $alert_id,
1359
+ 'date' => WSAL_Utilities_DateTimeFormatter::instance()->get_formatted_date_time( $created_on ),
1360
  // We need to keep the timestamp to be able to group entries by dates etc. The "date" field is not suitable
1361
  // as it is already translated, thus difficult to parse and process.
1362
  'timestamp' => $created_on,
1363
  'code' => $const->name,
1364
  // Fill variables in message.
1365
+ 'message' => $occurrence->get_message( $event_metadata, $context ),
1366
  'user_id' => $user_id,
1367
  'user_name' => $username,
1368
  'user_data' => $user_id ? $this->get_event_user_data( $username ) : false,
1386
  */
1387
  public static function get_blog_info( $plugin, $site_id ) {
1388
  // Blog details.
1389
+ if ( $plugin->is_multisite() ) {
1390
  $blog_info = get_blog_details( $site_id, true );
1391
  $blog_name = esc_html__( 'Unknown Site', 'wp-security-audit-log' );
1392
  $blog_url = '';
1423
  public function get_wp_users(): array {
1424
  return $this->wp_users;
1425
  }
1426
+
1427
+ /**
1428
+ * Deprecated placeholder function.
1429
+ *
1430
+ * @param integer $type - Alert type.
1431
+ * @param array $data - Alert data.
1432
+ * @param mixed $delayed - False if delayed, function if not.
1433
+ *
1434
+ * @deprecated 4.4.1 Replaced by function trigger_event.
1435
+ *
1436
+ * @see WSAL_AlertManager::trigger_event()
1437
+ *
1438
+ * @phpcs:disable WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid
1439
+ */
1440
+ public function Trigger( $type, $data = array(), $delayed = false ) {
1441
+ $this->trigger_event( $type, $data, $delayed );
1442
+ }
1443
+
1444
+ /**
1445
+ * Deprecated placeholder function.
1446
+ *
1447
+ * @param integer $type - Alert type ID.
1448
+ * @param array $data - Alert data.
1449
+ * @param callable $cond - A future condition callback (receives an object of type WSAL_AlertManager as parameter).
1450
+ *
1451
+ * @deprecated 4.4.1 Replaced by function trigger_event_if.
1452
+ *
1453
+ * @see WSAL_AlertManager::trigger_event_if()
1454
+ *
1455
+ * @phpcs:disable WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid
1456
+ */
1457
+ public function TriggerIf( $type, $data, $cond = null ) {
1458
+ $this->trigger_event_if( $type, $data, $cond );
1459
+ }
1460
+
1461
+ /**
1462
+ * Deprecated placeholder function.
1463
+ *
1464
+ * @param integer $type - Alert type ID.
1465
+ * @param int $count - A minimum number of event occurrences.
1466
+ *
1467
+ * @return boolean
1468
+ *
1469
+ * @deprecated 4.4.1 Replaced by function will_trigger.
1470
+ * @see WSAL_AlertManager::will_trigger()
1471
+ *
1472
+ * @phpcs:disable WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid
1473
+ */
1474
+ public function WillTrigger( $type, $count = 1 ) {
1475
+ return $this->will_trigger( $type, $count );
1476
+ }
1477
+
1478
+ /**
1479
+ * Deprecated placeholder function.
1480
+ *
1481
+ * @param int $type - Alert type ID.
1482
+ * @param int $count - A minimum number of event occurrences.
1483
+ *
1484
+ * @return boolean
1485
+ *
1486
+ * @deprecated 4.4.1 Replaced by function will_or_has_triggered.
1487
+ * @see WSAL_AlertManager::will_or_has_triggered()
1488
+ *
1489
+ * @phpcs:disable WordPress.NamingConventions.ValidFunctionName.MethodNameInvalid
1490
+ */
1491
+ public function WillOrHasTriggered( $type, $count = 1 ) {
1492
+ return $this->will_or_has_triggered( $type, $count );
1493
+ }
1494
  }
classes/AuditLogGridView.php CHANGED
@@ -4,7 +4,7 @@
4
  *
5
  * CLass file for audit log list view.
6
  *
7
- * @since 1.0.0
8
  * @package wsal
9
  */
10
 
@@ -19,7 +19,7 @@ require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
19
  /**
20
  * This view is included in Audit Log Viewer Page.
21
  *
22
- * @see Views/AuditLog.php
23
  * @package wsal
24
  */
25
  class WSAL_AuditLogGridView extends WP_List_Table {
@@ -29,7 +29,7 @@ class WSAL_AuditLogGridView extends WP_List_Table {
29
  *
30
  * @var WpSecurityAuditLog
31
  */
32
- protected $_plugin;
33
 
34
  /**
35
  * Current Alert ID
@@ -78,6 +78,8 @@ class WSAL_AuditLogGridView extends WP_List_Table {
78
  private $item_meta = array();
79
 
80
  /**
 
 
81
  * @var WSAL_Views_AuditLog
82
  * @since 4.3.2
83
  */
@@ -86,12 +88,12 @@ class WSAL_AuditLogGridView extends WP_List_Table {
86
  /**
87
  * Method: Constructor.
88
  *
89
- * @param WpSecurityAuditLog $plugin - Instance of WpSecurityAuditLog.
90
  * @param WSAL_Views_AuditLog $audit_log_view Audit log view.
91
- * @param stdClass $query_args - Events query arguments.
92
  */
93
  public function __construct( $plugin, $audit_log_view, $query_args ) {
94
- $this->_plugin = $plugin;
95
  $this->audit_log_view = $audit_log_view;
96
  $this->query_args = $query_args;
97
 
@@ -106,22 +108,21 @@ class WSAL_AuditLogGridView extends WP_List_Table {
106
  }
107
 
108
  /**
109
- * Empty View.
110
  */
111
  public function no_items() {
112
  esc_html_e( 'No events so far.', 'wp-security-audit-log' );
113
  }
114
 
115
-
 
 
116
  protected function get_table_classes() {
117
  return array( 'widefat', 'fixed', 'striped', $this->_args['plural'], 'wsal-table', 'wsal-table-grid' );
118
  }
119
 
120
  /**
121
- * Generate the table navigation above or below the table
122
- *
123
- * @since 3.2.3
124
- * @param string $which – Position of the nav.
125
  */
126
  protected function display_tablenav( $which ) {
127
  if ( 'top' === $which ) {
@@ -144,7 +145,7 @@ class WSAL_AuditLogGridView extends WP_List_Table {
144
  ?>
145
  <div class="display-type-buttons">
146
  <?php
147
- $user_selected_view = $this->_plugin->views->views[0]->detect_view_type();
148
  ?>
149
  <a id ="wsal-list-view-toggle" href="<?php echo esc_url( add_query_arg( 'view', 'list' ) ); ?>" class="button wsal-button dashicons-before dashicons-list-view" <?php echo ( 'list' === $user_selected_view ) ? esc_attr( 'disabled' ) : ''; ?>><?php esc_html_e( 'List View', 'wp-security-audit-log' ); ?></a>
150
  <a id ="wsal-grid-view-toggle" href="<?php echo esc_url( add_query_arg( 'view', 'grid' ) ); ?>" class="button wsal-button dashicons-before dashicons-grid-view" <?php echo ( 'grid' === $user_selected_view ) ? esc_attr( 'disabled' ) : ''; ?>><?php esc_html_e( 'Grid View', 'wp-security-audit-log' ); ?></a>
@@ -157,15 +158,13 @@ class WSAL_AuditLogGridView extends WP_List_Table {
157
  }
158
 
159
  /**
160
- * Table navigation.
161
- *
162
- * @param string $which - Position of the nav.
163
  */
164
  public function extra_tablenav( $which ) {
165
  // If the position is not top then render.
166
- if ( 'top' !== $which && ! $this->_plugin->settings()->is_infinite_scroll() ) :
167
  // Items-per-page widget.
168
- $p = $this->_plugin->settings()->GetViewPerPage();
169
  $items = array( 5, 10, 15, 30, 50 );
170
  if ( ! in_array( $p, $items, true ) ) {
171
  $items[] = $p;
@@ -185,7 +184,7 @@ class WSAL_AuditLogGridView extends WP_List_Table {
185
  <?php
186
  endif;
187
 
188
- if ( 'top' !== $which && $this->_plugin->settings()->is_infinite_scroll() ) :
189
  ?>
190
  <div id="wsal-auditlog-end"><p><?php esc_html_e( '— End of Activity Log —', 'wp-security-audit-log' ); ?></p></div>
191
  <div id="wsal-event-loader"><div class="wsal-lds-ellipsis"><div></div><div></div><div></div><div></div></div></div>
@@ -196,10 +195,10 @@ class WSAL_AuditLogGridView extends WP_List_Table {
196
  // NOTE: this is shown when the filter IS NOT true.
197
  if ( $this->is_multisite() && $this->is_main_blog() && ! apply_filters( 'search_extensition_active', false ) ) {
198
  if (
199
- ( 'top' === $which && $this->_plugin->settings()->is_infinite_scroll() )
200
- || ! $this->_plugin->settings()->is_infinite_scroll()
201
  ) {
202
- $curr = $this->_plugin->settings()->get_view_site_id();
203
  ?>
204
  <div class="wsal-ssa wsal-ssa-<?php echo esc_attr( $which ); ?>">
205
  <?php if ( $this->get_site_count() > 15 ) : ?>
@@ -210,7 +209,7 @@ class WSAL_AuditLogGridView extends WP_List_Table {
210
  <select class="wsal-ssas" onchange="WsalSsasChange(value);">
211
  <option value="0"><?php esc_html_e( 'All Sites', 'wp-security-audit-log' ); ?></option>
212
  <?php foreach ( $this->get_sites() as $info ) : ?>
213
- <option value="<?php echo esc_attr( $info->blog_id ); ?>" <?php echo ( $info->blog_id == $curr ) ? 'selected="selected"' : false; ?>>
214
  <?php echo esc_html( $info->blogname ) . ' (' . esc_html( $info->domain ) . ')'; ?>
215
  </option>
216
  <?php endforeach; ?>
@@ -238,7 +237,7 @@ class WSAL_AuditLogGridView extends WP_List_Table {
238
  }
239
 
240
  // Execute query.
241
- $res = $wpdb->get_results( $sql );
242
 
243
  // Modify result.
244
  foreach ( $res as $row ) {
@@ -257,13 +256,11 @@ class WSAL_AuditLogGridView extends WP_List_Table {
257
  public function get_site_count() {
258
  global $wpdb;
259
  $sql = 'SELECT COUNT(*) FROM ' . $wpdb->blogs;
260
- return (int) $wpdb->get_var( $sql );
261
  }
262
 
263
  /**
264
- * Method: Get View Columns.
265
- *
266
- * @return array
267
  */
268
  public function get_columns() {
269
 
@@ -282,7 +279,7 @@ class WSAL_AuditLogGridView extends WP_List_Table {
282
 
283
  // Get selected columns from settings.
284
  if ( empty( $this->selected_columns ) && ! is_array( $this->selected_columns ) ) {
285
- $this->selected_columns = $this->_plugin->settings()->GetColumnsSelected();
286
  }
287
 
288
  // If selected columns are not empty, then unset default columns.
@@ -303,9 +300,9 @@ class WSAL_AuditLogGridView extends WP_List_Table {
303
  case 'message':
304
  $cols['mesg'] = __( 'Message', 'wp-security-audit-log' );
305
  break;
306
- default:
307
- // fallback for any new columns would go here
308
- break;
309
  }
310
  }
311
  }
@@ -314,19 +311,14 @@ class WSAL_AuditLogGridView extends WP_List_Table {
314
  }
315
 
316
  /**
317
- * Method: Get checkbox column.
318
- *
319
- * @param object $item - Item.
320
- * @return string
321
  */
322
  public function column_cb( $item ) {
323
  return '<input type="checkbox" value="' . $item->id . '" name="' . esc_attr( $this->_args['singular'] ) . '[]" />';
324
  }
325
 
326
  /**
327
- * Method: Get Sortable Columns.
328
- *
329
- * @return array
330
  */
331
  public function get_sortable_columns() {
332
  return array(
@@ -336,15 +328,12 @@ class WSAL_AuditLogGridView extends WP_List_Table {
336
  }
337
 
338
  /**
339
- * Method: Get default column values.
340
- *
341
- * @param WSAL_Models_Occurrence $item - Column item.
342
- * @param string $column_name - Name of the column.
343
  */
344
  public function column_default( $item, $column_name ) {
345
  // Store meta if not set.
346
- if ( ! isset( $this->item_meta[ $item->getId() ] ) ) {
347
- $this->item_meta[ $item->getId() ] = $item->GetMetaArray();
348
  }
349
 
350
  // Store current alert id.
@@ -352,7 +341,7 @@ class WSAL_AuditLogGridView extends WP_List_Table {
352
 
353
  switch ( $column_name ) {
354
  case 'type':
355
- $code = $this->_plugin->alerts->GetAlert( $item->alert_id );
356
  $extra_msg = '';
357
  $data_link = '';
358
  $modification_alerts = array( 1002, 1003 );
@@ -361,7 +350,7 @@ class WSAL_AuditLogGridView extends WP_List_Table {
361
  $data_link = add_query_arg( 'page', 'wsal-togglealerts#tab-users-profiles---activity', admin_url( 'admin.php' ) );
362
  }
363
 
364
- if ( ! $this->_plugin->settings()->CurrentUserCan( 'edit' ) ) {
365
  return '<span class="log-disable">' . str_pad( $item->alert_id, 4, '0', STR_PAD_LEFT ) . ' </span>';
366
  }
367
  // add description to $extra_msg only if one is available.
@@ -370,13 +359,13 @@ class WSAL_AuditLogGridView extends WP_List_Table {
370
  . str_pad( $item->alert_id, 4, '0', STR_PAD_LEFT ) . ' </span>';
371
 
372
  case 'code':
373
- $code = $this->_plugin->alerts->GetAlert( $item->alert_id );
374
  $code = $code ? $code->severity : 0;
375
- $const = $this->_plugin->constants->get_constant_to_display( $code );
376
 
377
- $css_classes = ['log-type', 'log-type-' . $const->value ];
378
- if (property_exists($const, 'css')) {
379
- array_push($css_classes, 'log-type-' . $const->css);
380
  }
381
  return '<a class="tooltip" href="#" data-tooltip="' . esc_html( $const->name ) . '"><span class="' . implode( ' ', $css_classes ) . '"></span></a>';
382
  case 'site':
@@ -386,48 +375,49 @@ class WSAL_AuditLogGridView extends WP_List_Table {
386
  case 'mesg':
387
  // login, logout and failed login have no message attached.
388
  if ( ! in_array( $item->alert_id, array( 1000, 1001, 1002 ), true ) ) {
389
- $event_meta = $this->item_meta[ $item->getId() ];
390
- $result = '<table id="Event' . absint( $item->id ) . '">';
391
- $result .= '<td class="wsal-grid-text-header">' . esc_html__( 'Message:', 'wp-security-audit-log' ) . '</td>';
392
- $result .= '<td class="wsal-grid-text-data">' . $item->GetMessage( $event_meta ) . '</td>';
393
- $result .= '</table>';
394
- $result .= $this->audit_log_view->maybe_build_teaser_html( $event_meta );
395
  return $result;
396
  }
397
  return '';
398
  case 'info':
399
  $eventdate = $item->created_on
400
- ? WSAL_Utilities_DateTimeFormatter::instance()->getFormattedDateTime($item->created_on, 'date' )
401
- : '<i>' . __( 'Unknown', 'wp-security-audit-log' ) . '</i>';
402
 
403
  $eventtime = $item->created_on
404
- ? WSAL_Utilities_DateTimeFormatter::instance()->getFormattedDateTime($item->created_on, 'time' )
405
- : '<i>' . __( 'Unknown', 'wp-security-audit-log' ) . '</i>';
406
 
407
- $username = WSAL_Utilities_UsersUtils::GetUsername( $this->item_meta[ $item->getId() ] ); // Get username.
408
  $user = get_user_by( 'login', $username ); // Get user.
409
  if ( empty( $this->name_type ) ) {
410
- $this->name_type = $this->_plugin->settings()->get_type_username();
411
  }
412
 
413
  // Check if the username and user exists.
414
  if ( $username && $user ) {
415
 
416
- $display_name = WSAL_Utilities_UsersUtils::get_display_label( $this->_plugin, $user );
417
  $user_edit_link = admin_url( 'user-edit.php?user_id=' . $user->ID );
418
-
419
  // Additional user info tooltip.
420
  $tooltip = WSAL_Utilities_UsersUtils::get_tooltip_user_content( $user );
421
- $uhtml = '<a class="tooltip" data-tooltip="' . esc_attr( $tooltip ) . '" data-user="' . $user->user_login . '" href="' . $user_edit_link . '" target="_blank">' . esc_html( $display_name ) . '</a>';
422
 
423
- $roles = WSAL_Utilities_UsersUtils::get_roles_label( $item->GetUserRoles() );
424
- } elseif ( 'Plugin' == $username ) {
 
425
  $uhtml = '<i>' . __( 'Plugin', 'wp-security-audit-log' ) . '</i>';
426
  $roles = '';
427
- } elseif ( 'Plugins' == $username ) {
428
  $uhtml = '<i>' . __( 'Plugins', 'wp-security-audit-log' ) . '</i>';
429
  $roles = '';
430
- } elseif ( 'Website Visitor' == $username || 'Unregistered user' == $username ) {
431
  $uhtml = '<i>' . __( 'Unregistered user', 'wp-security-audit-log' ) . '</i>';
432
  $roles = '';
433
  } else {
@@ -448,9 +438,7 @@ class WSAL_AuditLogGridView extends WP_List_Table {
448
  */
449
  $eventuser = apply_filters( 'wsal_auditlog_row_user_data', $row_user_data, $this->current_alert_id );
450
 
451
-
452
-
453
- $scip = $item->GetSourceIP();
454
  if ( is_string( $scip ) ) {
455
  $scip = str_replace( array( '"', '[', ']' ), '', $scip );
456
  }
@@ -458,7 +446,7 @@ class WSAL_AuditLogGridView extends WP_List_Table {
458
  $oips = array();
459
 
460
  // If there's no IP...
461
- if ( is_null( $scip ) || '' == $scip ) {
462
  return '<i>unknown</i>';
463
  }
464
 
@@ -482,7 +470,7 @@ class WSAL_AuditLogGridView extends WP_List_Table {
482
 
483
  $ip_html = "<a class='search-ip' data-tooltip='$tooltip' data-ip='$scip' target='_blank' href='https://whatismyipaddress.com/ip/$scip'>" . esc_html( $scip ) . '</a> <a href="javascript:;" onclick="jQuery(this).hide().next().show();">(more&hellip;)</a><div style="display: none;">';
484
  foreach ( $oips as $ip ) {
485
- if ( $scip != $ip ) {
486
  $ip_html .= '<div>' . $ip . '</div>';
487
  }
488
  }
@@ -490,45 +478,43 @@ class WSAL_AuditLogGridView extends WP_List_Table {
490
  } else {
491
  $ip_html = "<a target='_blank' href='https://whatismyipaddress.com/ip/$scip'>" . esc_html( $scip ) . '</a> <a href="javascript:;" onclick="jQuery(this).hide().next().show();">(more&hellip;)</a><div style="display: none;">';
492
  foreach ( $oips as $ip ) {
493
- if ( $scip != $ip ) {
494
  $ip_html .= '<div>' . $ip . '</div>';
495
  }
496
  }
497
  $ip_html .= '</div>';
498
  }
499
 
 
500
 
501
-
502
- $eventobj = isset( $this->item_meta[ $item->getId() ]['Object'] ) ? $this->_plugin->alerts->get_event_objects_data( $this->item_meta[ $item->getId() ]['Object'] ) : '';
503
-
504
- $eventtypeobj = isset( $this->item_meta[ $item->getId() ]['EventType'] ) ? $this->_plugin->alerts->get_event_type_data( $this->item_meta[ $item->getId() ]['EventType'] ) : '';
505
 
506
  ob_start();
507
  ?>
508
  <table>
509
  <tr>
510
  <td class="wsal-grid-text-header"><?php esc_html_e( 'Date:' ); ?></td>
511
- <td class="wsal-grid-text-data"><?php echo $eventdate; ?></td>
512
  </tr>
513
  <tr>
514
  <td class="wsal-grid-text-header"><?php esc_html_e( 'Time:' ); ?></td>
515
- <td class="wsal-grid-text-data"><?php echo $eventtime; ?></td>
516
  </tr>
517
  <tr>
518
  <td class="wsal-grid-text-header"><?php esc_html_e( 'User:' ); ?></td>
519
- <td class="wsal-grid-text-data"><?php echo $eventuser; ?></td>
520
  </tr>
521
  <tr>
522
  <td class="wsal-grid-text-header"><?php esc_html_e( 'IP:' ); ?></td>
523
- <td class="wsal-grid-text-data"><?php echo ( isset( $oips_html ) && ! empty( $oips_html ) ) ? $oips_html : $ip_html ?></td>
524
  </tr>
525
  <tr>
526
  <td class="wsal-grid-text-header"><?php esc_html_e( 'Object:' ); ?></td>
527
- <td class="wsal-grid-text-data"><?php echo $eventobj; ?></td>
528
  </tr>
529
  <tr>
530
  <td class="wsal-grid-text-header"><?php esc_html_e( 'Event Type:' ); ?></td>
531
- <td class="wsal-grid-text-data"><?php echo $eventtypeobj; ?></td>
532
  </tr>
533
  </table>
534
  <?php
@@ -575,7 +561,7 @@ class WSAL_AuditLogGridView extends WP_List_Table {
575
  * @return bool
576
  */
577
  protected function is_multisite() {
578
- return $this->_plugin->IsMultisite();
579
  }
580
 
581
  /**
@@ -584,7 +570,7 @@ class WSAL_AuditLogGridView extends WP_List_Table {
584
  * @return bool
585
  */
586
  protected function is_main_blog() {
587
- return get_current_blog_id() == 1;
588
  }
589
 
590
  /**
@@ -593,7 +579,7 @@ class WSAL_AuditLogGridView extends WP_List_Table {
593
  * @return bool
594
  */
595
  protected function is_specific_view() {
596
- return isset( $this->query_args->site_id ) && '0' != $this->query_args->site_id;
597
  }
598
 
599
  /**
@@ -641,7 +627,7 @@ class WSAL_AuditLogGridView extends WP_List_Table {
641
  $total_items = isset( $query_events['total_items'] ) ? $query_events['total_items'] : false;
642
  $per_page = isset( $query_events['per_page'] ) ? $query_events['per_page'] : false;
643
 
644
- if ( ! $this->_plugin->settings()->is_infinite_scroll() ) {
645
  $this->set_pagination_args(
646
  array(
647
  'total_items' => $total_items,
@@ -653,9 +639,7 @@ class WSAL_AuditLogGridView extends WP_List_Table {
653
  }
654
 
655
  /**
656
- * Method: Output Single row.
657
- *
658
- * @param object $item - Item.
659
  */
660
  public function single_row( $item ) {
661
  if ( 9999 === $item->alert_id ) {
@@ -668,17 +652,12 @@ class WSAL_AuditLogGridView extends WP_List_Table {
668
  }
669
 
670
  /**
671
- * Print column headers, accounting for hidden and sortable columns.
672
- *
673
- * @static var int $cb_counter
674
- *
675
- * @param bool $with_id – Whether to set the id attribute or not.
676
- * @since 3.2.3
677
  */
678
  public function print_column_headers( $with_id = true ) {
679
  list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
680
 
681
- $current_url = set_url_scheme( esc_url_raw( wp_unslash( $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ) ) );
682
  $current_url = remove_query_arg( 'paged', $current_url );
683
 
684
  // Set order by query arg.
@@ -704,13 +683,13 @@ class WSAL_AuditLogGridView extends WP_List_Table {
704
  foreach ( $columns as $column_key => $column_display_name ) {
705
  $class = array( 'manage-column', "column-$column_key" );
706
 
707
- if ( in_array( $column_key, $hidden ) ) {
708
  $class[] = 'hidden';
709
  }
710
 
711
  if ( 'cb' === $column_key ) {
712
  $class[] = 'check-column';
713
- } elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ) ) ) {
714
  $class[] = 'num';
715
  }
716
 
@@ -742,7 +721,7 @@ class WSAL_AuditLogGridView extends WP_List_Table {
742
  $class = "class='" . implode( ' ', $class ) . "'";
743
  }
744
 
745
- echo "<$tag $scope $id $class>";
746
  echo ! in_array( $column_key, array( 'code', 'data', 'site' ), true ) ? '<div class="wsal-filter-wrap">' : '';
747
 
748
  if ( $with_id ) {
@@ -757,9 +736,9 @@ class WSAL_AuditLogGridView extends WP_List_Table {
757
  do_action( 'wsal_audit_log_column_header', $column_key );
758
  }
759
 
760
- echo $column_display_name;
761
  echo ! in_array( $column_key, array( 'code', 'data', 'site' ), true ) ? '</div>' : '';
762
- echo "</$tag>";
763
  }
764
  }
765
 
@@ -787,7 +766,7 @@ class WSAL_AuditLogGridView extends WP_List_Table {
787
 
788
  $bid = (int) $this->query_args->site_id;
789
  if ( $bid ) {
790
- $query->addCondition( 'site_id = %s ', $bid );
791
  }
792
 
793
  /**
@@ -801,9 +780,9 @@ class WSAL_AuditLogGridView extends WP_List_Table {
801
  */
802
  $query = apply_filters( 'wsal_auditlog_query', $query );
803
 
804
- if ( ! $this->_plugin->settings()->is_infinite_scroll() ) {
805
- $total_items = $query->getAdapter()->Count( $query );
806
- $per_page = $this->_plugin->settings()->GetViewPerPage();
807
  $offset = ( $this->get_pagenum() - 1 ) * $per_page;
808
  } else {
809
  $total_items = false;
@@ -816,7 +795,7 @@ class WSAL_AuditLogGridView extends WP_List_Table {
816
  $order = isset( $this->query_args->order ) ? $this->query_args->order : false;
817
 
818
  if ( ! $order_by ) {
819
- $query->addOrderBy( 'created_on', true );
820
  } else {
821
  $is_descending = true;
822
  if ( $order && 'asc' === $order ) {
@@ -827,30 +806,30 @@ class WSAL_AuditLogGridView extends WP_List_Table {
827
  /*
828
  * Handle the 'code' (Severity) column sorting.
829
  */
830
- $query->addMetaJoin(); // Since LEFT JOIN clause causes the result values to duplicate.
831
- $query->addCondition( 'meta.name = %s', 'Severity' ); // A where condition is added to make sure that we're only requesting the relevant meta data rows from metadata table.
832
- $query->addOrderBy( 'CASE WHEN meta.name = "Severity" THEN meta.value END', $is_descending );
833
  } elseif ( 'info' === $order_by ) {
834
  // for the info col we are ordering just by dates.
835
- $query->addOrderBy( 'created_on', $is_descending );
836
  } else {
837
  $tmp = new WSAL_Models_Occurrence();
838
  // Making sure the field exists to order by.
839
  if ( isset( $tmp->{$order_by} ) ) {
840
- $query->addOrderBy( $order_by, $is_descending );
841
  } else {
842
- $query->addOrderBy( 'created_on', true );
843
  }
844
  }
845
  }
846
 
847
- $query->setOffset( $offset ); // Set query offset.
848
- $query->setLimit( $per_page ); // Set number of events per page.
849
 
850
  return array(
851
  'total_items' => $total_items,
852
  'per_page' => $per_page,
853
- 'items' => $query->getAdapter()->Execute( $query ),
854
  );
855
  }
856
  }
4
  *
5
  * CLass file for audit log list view.
6
  *
7
+ * @since 1.0.0
8
  * @package wsal
9
  */
10
 
19
  /**
20
  * This view is included in Audit Log Viewer Page.
21
  *
22
+ * @see Views/AuditLog.php
23
  * @package wsal
24
  */
25
  class WSAL_AuditLogGridView extends WP_List_Table {
29
  *
30
  * @var WpSecurityAuditLog
31
  */
32
+ protected $plugin;
33
 
34
  /**
35
  * Current Alert ID
78
  private $item_meta = array();
79
 
80
  /**
81
+ * Audit log view.
82
+ *
83
  * @var WSAL_Views_AuditLog
84
  * @since 4.3.2
85
  */
88
  /**
89
  * Method: Constructor.
90
  *
91
+ * @param WpSecurityAuditLog $plugin Instance of WpSecurityAuditLog.
92
  * @param WSAL_Views_AuditLog $audit_log_view Audit log view.
93
+ * @param stdClass $query_args Events query arguments.
94
  */
95
  public function __construct( $plugin, $audit_log_view, $query_args ) {
96
+ $this->plugin = $plugin;
97
  $this->audit_log_view = $audit_log_view;
98
  $this->query_args = $query_args;
99
 
108
  }
109
 
110
  /**
111
+ * {@inheritDoc}
112
  */
113
  public function no_items() {
114
  esc_html_e( 'No events so far.', 'wp-security-audit-log' );
115
  }
116
 
117
+ /**
118
+ * {@inheritDoc}
119
+ */
120
  protected function get_table_classes() {
121
  return array( 'widefat', 'fixed', 'striped', $this->_args['plural'], 'wsal-table', 'wsal-table-grid' );
122
  }
123
 
124
  /**
125
+ * {@inheritDoc}
 
 
 
126
  */
127
  protected function display_tablenav( $which ) {
128
  if ( 'top' === $which ) {
145
  ?>
146
  <div class="display-type-buttons">
147
  <?php
148
+ $user_selected_view = $this->plugin->views->views[0]->detect_view_type();
149
  ?>
150
  <a id ="wsal-list-view-toggle" href="<?php echo esc_url( add_query_arg( 'view', 'list' ) ); ?>" class="button wsal-button dashicons-before dashicons-list-view" <?php echo ( 'list' === $user_selected_view ) ? esc_attr( 'disabled' ) : ''; ?>><?php esc_html_e( 'List View', 'wp-security-audit-log' ); ?></a>
151
  <a id ="wsal-grid-view-toggle" href="<?php echo esc_url( add_query_arg( 'view', 'grid' ) ); ?>" class="button wsal-button dashicons-before dashicons-grid-view" <?php echo ( 'grid' === $user_selected_view ) ? esc_attr( 'disabled' ) : ''; ?>><?php esc_html_e( 'Grid View', 'wp-security-audit-log' ); ?></a>
158
  }
159
 
160
  /**
161
+ * {@inheritDoc}
 
 
162
  */
163
  public function extra_tablenav( $which ) {
164
  // If the position is not top then render.
165
+ if ( 'top' !== $which && ! $this->plugin->settings()->is_infinite_scroll() ) :
166
  // Items-per-page widget.
167
+ $p = $this->plugin->settings()->get_views_per_page();
168
  $items = array( 5, 10, 15, 30, 50 );
169
  if ( ! in_array( $p, $items, true ) ) {
170
  $items[] = $p;
184
  <?php
185
  endif;
186
 
187
+ if ( 'top' !== $which && $this->plugin->settings()->is_infinite_scroll() ) :
188
  ?>
189
  <div id="wsal-auditlog-end"><p><?php esc_html_e( '— End of Activity Log —', 'wp-security-audit-log' ); ?></p></div>
190
  <div id="wsal-event-loader"><div class="wsal-lds-ellipsis"><div></div><div></div><div></div><div></div></div></div>
195
  // NOTE: this is shown when the filter IS NOT true.
196
  if ( $this->is_multisite() && $this->is_main_blog() && ! apply_filters( 'search_extensition_active', false ) ) {
197
  if (
198
+ ( 'top' === $which && $this->plugin->settings()->is_infinite_scroll() )
199
+ || ! $this->plugin->settings()->is_infinite_scroll()
200
  ) {
201
+ $curr = $this->plugin->settings()->get_view_site_id();
202
  ?>
203
  <div class="wsal-ssa wsal-ssa-<?php echo esc_attr( $which ); ?>">
204
  <?php if ( $this->get_site_count() > 15 ) : ?>
209
  <select class="wsal-ssas" onchange="WsalSsasChange(value);">
210
  <option value="0"><?php esc_html_e( 'All Sites', 'wp-security-audit-log' ); ?></option>
211
  <?php foreach ( $this->get_sites() as $info ) : ?>
212
+ <option value="<?php echo esc_attr( $info->blog_id ); ?>" <?php echo ( $info->blog_id === $curr ) ? 'selected="selected"' : false; ?>>
213
  <?php echo esc_html( $info->blogname ) . ' (' . esc_html( $info->domain ) . ')'; ?>
214
  </option>
215
  <?php endforeach; ?>
237
  }
238
 
239
  // Execute query.
240
+ $res = $wpdb->get_results( $sql ); // phpcs:ignore
241
 
242
  // Modify result.
243
  foreach ( $res as $row ) {
256
  public function get_site_count() {
257
  global $wpdb;
258
  $sql = 'SELECT COUNT(*) FROM ' . $wpdb->blogs;
259
+ return (int) $wpdb->get_var( $sql ); // phpcs:ignore
260
  }
261
 
262
  /**
263
+ * {@inheritDoc}
 
 
264
  */
265
  public function get_columns() {
266
 
279
 
280
  // Get selected columns from settings.
281
  if ( empty( $this->selected_columns ) && ! is_array( $this->selected_columns ) ) {
282
+ $this->selected_columns = $this->plugin->settings()->get_columns_selected();
283
  }
284
 
285
  // If selected columns are not empty, then unset default columns.
300
  case 'message':
301
  $cols['mesg'] = __( 'Message', 'wp-security-audit-log' );
302
  break;
303
+ default:
304
+ // Fallback for any new columns would go here.
305
+ break;
306
  }
307
  }
308
  }
311
  }
312
 
313
  /**
314
+ * {@inheritDoc}
 
 
 
315
  */
316
  public function column_cb( $item ) {
317
  return '<input type="checkbox" value="' . $item->id . '" name="' . esc_attr( $this->_args['singular'] ) . '[]" />';
318
  }
319
 
320
  /**
321
+ * {@inheritDoc}
 
 
322
  */
323
  public function get_sortable_columns() {
324
  return array(
328
  }
329
 
330
  /**
331
+ * {@inheritDoc}
 
 
 
332
  */
333
  public function column_default( $item, $column_name ) {
334
  // Store meta if not set.
335
+ if ( ! isset( $this->item_meta[ $item->get_id() ] ) ) {
336
+ $this->item_meta[ $item->get_id() ] = $item->get_meta_array();
337
  }
338
 
339
  // Store current alert id.
341
 
342
  switch ( $column_name ) {
343
  case 'type':
344
+ $code = $this->plugin->alerts->get_alert( $item->alert_id );
345
  $extra_msg = '';
346
  $data_link = '';
347
  $modification_alerts = array( 1002, 1003 );
350
  $data_link = add_query_arg( 'page', 'wsal-togglealerts#tab-users-profiles---activity', admin_url( 'admin.php' ) );
351
  }
352
 
353
+ if ( ! $this->plugin->settings()->current_user_can( 'edit' ) ) {
354
  return '<span class="log-disable">' . str_pad( $item->alert_id, 4, '0', STR_PAD_LEFT ) . ' </span>';
355
  }
356
  // add description to $extra_msg only if one is available.
359
  . str_pad( $item->alert_id, 4, '0', STR_PAD_LEFT ) . ' </span>';
360
 
361
  case 'code':
362
+ $code = $this->plugin->alerts->get_alert( $item->alert_id );
363
  $code = $code ? $code->severity : 0;
364
+ $const = $this->plugin->constants->get_constant_to_display( $code );
365
 
366
+ $css_classes = array( 'log-type', 'log-type-' . $const->value );
367
+ if ( property_exists( $const, 'css' ) ) {
368
+ array_push( $css_classes, 'log-type-' . $const->css );
369
  }
370
  return '<a class="tooltip" href="#" data-tooltip="' . esc_html( $const->name ) . '"><span class="' . implode( ' ', $css_classes ) . '"></span></a>';
371
  case 'site':
375
  case 'mesg':
376
  // login, logout and failed login have no message attached.
377
  if ( ! in_array( $item->alert_id, array( 1000, 1001, 1002 ), true ) ) {
378
+ $event_meta = $this->item_meta[ $item->get_id() ];
379
+ $result = '<table id="Event' . absint( $item->id ) . '">';
380
+ $result .= '<td class="wsal-grid-text-header">' . esc_html__( 'Message:', 'wp-security-audit-log' ) . '</td>';
381
+ $result .= '<td class="wsal-grid-text-data">' . $item->get_message( $event_meta ) . '</td>';
382
+ $result .= '</table>';
383
+ $result .= $this->audit_log_view->maybe_build_teaser_html( $event_meta );
384
  return $result;
385
  }
386
  return '';
387
  case 'info':
388
  $eventdate = $item->created_on
389
+ ? WSAL_Utilities_DateTimeFormatter::instance()->get_formatted_date_time( $item->created_on, 'date' )
390
+ : '<i>' . __( 'Unknown', 'wp-security-audit-log' ) . '</i>';
391
 
392
  $eventtime = $item->created_on
393
+ ? WSAL_Utilities_DateTimeFormatter::instance()->get_formatted_date_time( $item->created_on, 'time' )
394
+ : '<i>' . __( 'Unknown', 'wp-security-audit-log' ) . '</i>';
395
 
396
+ $username = WSAL_Utilities_UsersUtils::get_username( $this->item_meta[ $item->get_id() ] ); // Get username.
397
  $user = get_user_by( 'login', $username ); // Get user.
398
  if ( empty( $this->name_type ) ) {
399
+ $this->name_type = $this->plugin->settings()->get_type_username();
400
  }
401
 
402
  // Check if the username and user exists.
403
  if ( $username && $user ) {
404
 
405
+ $display_name = WSAL_Utilities_UsersUtils::get_display_label( $this->plugin, $user );
406
  $user_edit_link = admin_url( 'user-edit.php?user_id=' . $user->ID );
407
+
408
  // Additional user info tooltip.
409
  $tooltip = WSAL_Utilities_UsersUtils::get_tooltip_user_content( $user );
410
+ $uhtml = '<a class="tooltip" data-tooltip="' . esc_attr( $tooltip ) . '" data-user="' . $user->user_login . '" href="' . $user_edit_link . '" target="_blank">' . esc_html( $display_name ) . '</a>';
411
 
412
+
413
+ $roles = WSAL_Utilities_UsersUtils::get_roles_label( $item->get_user_roles() );
414
+ } elseif ( 'Plugin' === $username ) {
415
  $uhtml = '<i>' . __( 'Plugin', 'wp-security-audit-log' ) . '</i>';
416
  $roles = '';
417
+ } elseif ( 'Plugins' === $username ) {
418
  $uhtml = '<i>' . __( 'Plugins', 'wp-security-audit-log' ) . '</i>';
419
  $roles = '';
420
+ } elseif ( 'Website Visitor' === $username || 'Unregistered user' === $username ) {
421
  $uhtml = '<i>' . __( 'Unregistered user', 'wp-security-audit-log' ) . '</i>';
422
  $roles = '';
423
  } else {
438
  */
439
  $eventuser = apply_filters( 'wsal_auditlog_row_user_data', $row_user_data, $this->current_alert_id );
440
 
441
+ $scip = $item->get_source_ip();
 
 
442
  if ( is_string( $scip ) ) {
443
  $scip = str_replace( array( '"', '[', ']' ), '', $scip );
444
  }
446
  $oips = array();
447
 
448
  // If there's no IP...
449
+ if ( is_null( $scip ) || '' === $scip ) {
450
  return '<i>unknown</i>';
451
  }
452
 
470
 
471
  $ip_html = "<a class='search-ip' data-tooltip='$tooltip' data-ip='$scip' target='_blank' href='https://whatismyipaddress.com/ip/$scip'>" . esc_html( $scip ) . '</a> <a href="javascript:;" onclick="jQuery(this).hide().next().show();">(more&hellip;)</a><div style="display: none;">';
472
  foreach ( $oips as $ip ) {
473
+ if ( $scip != $ip ) { // phpcs:ignore
474
  $ip_html .= '<div>' . $ip . '</div>';
475
  }
476
  }
478
  } else {
479
  $ip_html = "<a target='_blank' href='https://whatismyipaddress.com/ip/$scip'>" . esc_html( $scip ) . '</a> <a href="javascript:;" onclick="jQuery(this).hide().next().show();">(more&hellip;)</a><div style="display: none;">';
480
  foreach ( $oips as $ip ) {
481
+ if ( $scip != $ip ) { // phpcs:ignore
482
  $ip_html .= '<div>' . $ip . '</div>';
483
  }
484
  }
485
  $ip_html .= '</div>';
486
  }
487
 
488
+ $eventobj = isset( $this->item_meta[ $item->get_id() ]['Object'] ) ? $this->plugin->alerts->get_event_objects_data( $this->item_meta[ $item->get_id() ]['Object'] ) : '';
489
 
490
+ $eventtypeobj = isset( $this->item_meta[ $item->get_id() ]['EventType'] ) ? $this->plugin->alerts->get_event_type_data( $this->item_meta[ $item->get_id() ]['EventType'] ) : '';
 
 
 
491
 
492
  ob_start();
493
  ?>
494
  <table>
495
  <tr>
496
  <td class="wsal-grid-text-header"><?php esc_html_e( 'Date:' ); ?></td>
497
+ <td class="wsal-grid-text-data"><?php echo $eventdate; // phpcs:ignore ?></td>
498
  </tr>
499
  <tr>
500
  <td class="wsal-grid-text-header"><?php esc_html_e( 'Time:' ); ?></td>
501
+ <td class="wsal-grid-text-data"><?php echo $eventtime; // phpcs:ignore ?></td>
502
  </tr>
503
  <tr>
504
  <td class="wsal-grid-text-header"><?php esc_html_e( 'User:' ); ?></td>
505
+ <td class="wsal-grid-text-data"><?php echo $eventuser; // phpcs:ignore ?></td>
506
  </tr>
507
  <tr>
508
  <td class="wsal-grid-text-header"><?php esc_html_e( 'IP:' ); ?></td>
509
+ <td class="wsal-grid-text-data"><?php echo ( isset( $oips_html ) && ! empty( $oips_html ) ) ? $oips_html : $ip_html; // phpcs:ignore ?></td>
510
  </tr>
511
  <tr>
512
  <td class="wsal-grid-text-header"><?php esc_html_e( 'Object:' ); ?></td>
513
+ <td class="wsal-grid-text-data"><?php echo $eventobj; // phpcs:ignore ?></td>
514
  </tr>
515
  <tr>
516
  <td class="wsal-grid-text-header"><?php esc_html_e( 'Event Type:' ); ?></td>
517
+ <td class="wsal-grid-text-data"><?php echo $eventtypeobj; // phpcs:ignore ?></td>
518
  </tr>
519
  </table>
520
  <?php
561
  * @return bool
562
  */
563
  protected function is_multisite() {
564
+ return $this->plugin->is_multisite();
565
  }
566
 
567
  /**
570
  * @return bool
571
  */
572
  protected function is_main_blog() {
573
+ return get_current_blog_id() === 1;
574
  }
575
 
576
  /**
579
  * @return bool
580
  */
581
  protected function is_specific_view() {
582
+ return isset( $this->query_args->site_id ) && '0' != $this->query_args->site_id; // phpcs:ignore
583
  }
584
 
585
  /**
627
  $total_items = isset( $query_events['total_items'] ) ? $query_events['total_items'] : false;
628
  $per_page = isset( $query_events['per_page'] ) ? $query_events['per_page'] : false;
629
 
630
+ if ( ! $this->plugin->settings()->is_infinite_scroll() ) {
631
  $this->set_pagination_args(
632
  array(
633
  'total_items' => $total_items,
639
  }
640
 
641
  /**
642
+ * {@inheritDoc}
 
 
643
  */
644
  public function single_row( $item ) {
645
  if ( 9999 === $item->alert_id ) {
652
  }
653
 
654
  /**
655
+ * {@inheritDoc}
 
 
 
 
 
656
  */
657
  public function print_column_headers( $with_id = true ) {
658
  list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
659
 
660
+ $current_url = set_url_scheme( esc_url_raw( wp_unslash( $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ) ) ); // phpcs:ignore
661
  $current_url = remove_query_arg( 'paged', $current_url );
662
 
663
  // Set order by query arg.
683
  foreach ( $columns as $column_key => $column_display_name ) {
684
  $class = array( 'manage-column', "column-$column_key" );
685
 
686
+ if ( in_array( $column_key, $hidden, true ) ) {
687
  $class[] = 'hidden';
688
  }
689
 
690
  if ( 'cb' === $column_key ) {
691
  $class[] = 'check-column';
692
+ } elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ), true ) ) {
693
  $class[] = 'num';
694
  }
695
 
721
  $class = "class='" . implode( ' ', $class ) . "'";
722
  }
723
 
724
+ echo "<$tag $scope $id $class>"; // phpcs:ignore
725
  echo ! in_array( $column_key, array( 'code', 'data', 'site' ), true ) ? '<div class="wsal-filter-wrap">' : '';
726
 
727
  if ( $with_id ) {
736
  do_action( 'wsal_audit_log_column_header', $column_key );
737
  }
738
 
739
+ echo $column_display_name; // phpcs:ignore
740
  echo ! in_array( $column_key, array( 'code', 'data', 'site' ), true ) ? '</div>' : '';
741
+ echo "</$tag>"; // phpcs:ignore
742
  }
743
  }
744
 
766
 
767
  $bid = (int) $this->query_args->site_id;
768
  if ( $bid ) {
769
+ $query->add_condition( 'site_id = %s ', $bid );
770
  }
771
 
772
  /**
780
  */
781
  $query = apply_filters( 'wsal_auditlog_query', $query );
782
 
783
+ if ( ! $this->plugin->settings()->is_infinite_scroll() ) {
784
+ $total_items = $query->get_adapter()->count( $query );
785
+ $per_page = $this->plugin->settings()->get_views_per_page();
786
  $offset = ( $this->get_pagenum() - 1 ) * $per_page;
787
  } else {
788
  $total_items = false;
795
  $order = isset( $this->query_args->order ) ? $this->query_args->order : false;
796
 
797
  if ( ! $order_by ) {
798
+ $query->add_order_by( 'created_on', true );
799
  } else {
800
  $is_descending = true;
801
  if ( $order && 'asc' === $order ) {
806
  /*
807
  * Handle the 'code' (Severity) column sorting.
808
  */
809
+ $query->add_meta_join(); // Since LEFT JOIN clause causes the result values to duplicate.
810
+ $query->add_condition( 'meta.name = %s', 'Severity' ); // A where condition is added to make sure that we're only requesting the relevant meta data rows from metadata table.
811
+ $query->add_order_by( 'CASE WHEN meta.name = "Severity" THEN meta.value END', $is_descending );
812
  } elseif ( 'info' === $order_by ) {
813
  // for the info col we are ordering just by dates.
814
+ $query->add_order_by( 'created_on', $is_descending );
815
  } else {
816
  $tmp = new WSAL_Models_Occurrence();
817
  // Making sure the field exists to order by.
818
  if ( isset( $tmp->{$order_by} ) ) {
819
+ $query->add_order_by( $order_by, $is_descending );
820
  } else {
821
+ $query->add_order_by( 'created_on', true );
822
  }
823
  }
824
  }
825
 
826
+ $query->set_offset( $offset ); // Set query offset.
827
+ $query->set_limit( $per_page ); // Set number of events per page.
828
 
829
  return array(
830
  'total_items' => $total_items,
831
  'per_page' => $per_page,
832
+ 'items' => $query->get_adapter()->execute_query( $query ),
833
  );
834
  }
835
  }
classes/AuditLogListView.php CHANGED
@@ -29,7 +29,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
29
  *
30
  * @var WpSecurityAuditLog
31
  */
32
- protected $_plugin;
33
 
34
  /**
35
  * Current Alert ID
@@ -69,6 +69,8 @@ class WSAL_AuditLogListView extends WP_List_Table {
69
  private $item_meta = array();
70
 
71
  /**
 
 
72
  * @var WSAL_Views_AuditLog
73
  * @since 4.3.2
74
  */
@@ -77,12 +79,12 @@ class WSAL_AuditLogListView extends WP_List_Table {
77
  /**
78
  * Method: Constructor.
79
  *
80
- * @param WpSecurityAuditLog $plugin - Instance of WpSecurityAuditLog.
81
  * @param WSAL_Views_AuditLog $audit_log_view Audit log view.
82
- * @param stdClass $query_args - Events query arguments.
83
  */
84
  public function __construct( $plugin, $audit_log_view, $query_args ) {
85
- $this->_plugin = $plugin;
86
  $this->audit_log_view = $audit_log_view;
87
  $this->query_args = $query_args;
88
 
@@ -106,7 +108,6 @@ class WSAL_AuditLogListView extends WP_List_Table {
106
  /**
107
  * Array of class names that are applied to the table for this view.
108
  *
109
- * @method get_table_classes
110
  * @since 4.0.0
111
  * @return array of strings
112
  */
@@ -142,7 +143,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
142
  ?>
143
  <div class="display-type-buttons">
144
  <?php
145
- $user_selected_view = $this->_plugin->views->views[0]->detect_view_type();
146
  ?>
147
  <a id ="wsal-list-view-toggle" href="<?php echo esc_url( add_query_arg( 'view', 'list' ) ); ?>" class="button wsal-button dashicons-before dashicons-list-view" <?php echo ( 'list' === $user_selected_view ) ? esc_attr( 'disabled' ) : ''; ?>><?php esc_html_e( 'List View', 'wp-security-audit-log' ); ?></a>
148
  <a id ="wsal-grid-view-toggle" href="<?php echo esc_url( add_query_arg( 'view', 'grid' ) ); ?>" class="button wsal-button dashicons-before dashicons-grid-view" <?php echo ( 'grid' === $user_selected_view ) ? esc_attr( 'disabled' ) : ''; ?>><?php esc_html_e( 'Grid View', 'wp-security-audit-log' ); ?></a>
@@ -161,9 +162,9 @@ class WSAL_AuditLogListView extends WP_List_Table {
161
  */
162
  public function extra_tablenav( $which ) {
163
  // If the position is not top then render.
164
- if ( 'top' !== $which && ! $this->_plugin->settings()->is_infinite_scroll() ) :
165
  // Items-per-page widget.
166
- $p = $this->_plugin->settings()->GetViewPerPage();
167
  $items = array( 5, 10, 15, 30, 50 );
168
  if ( ! in_array( $p, $items, true ) ) {
169
  $items[] = $p;
@@ -183,7 +184,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
183
  <?php
184
  endif;
185
 
186
- if ( 'top' !== $which && $this->_plugin->settings()->is_infinite_scroll() ) :
187
  ?>
188
  <div id="wsal-auditlog-end"><p><?php esc_html_e( '— End of Activity Log —', 'wp-security-audit-log' ); ?></p></div>
189
  <div id="wsal-event-loader"><div class="wsal-lds-ellipsis"><div></div><div></div><div></div><div></div></div></div>
@@ -194,10 +195,10 @@ class WSAL_AuditLogListView extends WP_List_Table {
194
  // NOTE: this is shown when the filter IS NOT true.
195
  if ( $this->is_multisite() && $this->is_main_blog() && ! apply_filters( 'search_extensition_active', false ) ) {
196
  if (
197
- ( 'top' === $which && $this->_plugin->settings()->is_infinite_scroll() )
198
- || ! $this->_plugin->settings()->is_infinite_scroll()
199
  ) {
200
- $curr = $this->_plugin->settings()->get_view_site_id();
201
  ?>
202
  <div class="wsal-ssa wsal-ssa-<?php echo esc_attr( $which ); ?>">
203
  <?php if ( $this->get_site_count() > 15 ) : ?>
@@ -208,7 +209,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
208
  <select class="wsal-ssas" onchange="WsalSsasChange(value);">
209
  <option value="0"><?php esc_html_e( 'All Sites', 'wp-security-audit-log' ); ?></option>
210
  <?php foreach ( $this->get_sites() as $info ) : ?>
211
- <option value="<?php echo esc_attr( $info->blog_id ); ?>" <?php echo ( $info->blog_id == $curr ) ? 'selected="selected"' : false; ?>>
212
  <?php echo esc_html( $info->blogname ) . ' (' . esc_html( $info->domain ) . ')'; ?>
213
  </option>
214
  <?php endforeach; ?>
@@ -236,7 +237,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
236
  }
237
 
238
  // Execute query.
239
- $res = $wpdb->get_results( $sql );
240
 
241
  // Modify result.
242
  foreach ( $res as $row ) {
@@ -255,7 +256,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
255
  public function get_site_count() {
256
  global $wpdb;
257
  $sql = 'SELECT COUNT(*) FROM ' . $wpdb->blogs;
258
- return (int) $wpdb->get_var( $sql );
259
  }
260
 
261
  /**
@@ -284,7 +285,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
284
 
285
  // Get selected columns from settings.
286
  if ( empty( $this->selected_columns ) && ! is_array( $this->selected_columns ) ) {
287
- $this->selected_columns = $this->_plugin->settings()->GetColumnsSelected();
288
  }
289
 
290
  // If selected columns are not empty, then unset default columns.
@@ -320,9 +321,9 @@ class WSAL_AuditLogListView extends WP_List_Table {
320
  case 'message':
321
  $cols['mesg'] = __( 'Message', 'wp-security-audit-log' );
322
  break;
323
- default:
324
- // fallback for any new columns would go here
325
- break;
326
  }
327
  }
328
  }
@@ -331,19 +332,14 @@ class WSAL_AuditLogListView extends WP_List_Table {
331
  }
332
 
333
  /**
334
- * Method: Get checkbox column.
335
- *
336
- * @param object $item - Item.
337
- * @return string
338
  */
339
  public function column_cb( $item ) {
340
  return '<input type="checkbox" value="' . $item->id . '" name="' . esc_attr( $this->_args['singular'] ) . '[]" />';
341
  }
342
 
343
  /**
344
- * Method: Get Sortable Columns.
345
- *
346
- * @return array
347
  */
348
  public function get_sortable_columns() {
349
  return array(
@@ -358,17 +354,12 @@ class WSAL_AuditLogListView extends WP_List_Table {
358
  }
359
 
360
  /**
361
- * Method: Get default column values.
362
- *
363
- * @param WSAL_Models_Occurrence $item - Column item.
364
- * @param string $column_name - Name of the column.
365
- *
366
- * @return string
367
  */
368
  public function column_default( $item, $column_name ) {
369
  // Store meta if not set.
370
- if ( ! isset( $this->item_meta[ $item->getId() ] ) ) {
371
- $this->item_meta[ $item->getId() ] = $item->GetMetaArray();
372
  }
373
 
374
  // Store current alert id.
@@ -376,7 +367,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
376
 
377
  switch ( $column_name ) {
378
  case 'type':
379
- $code = $this->_plugin->alerts->GetAlert(
380
  $item->alert_id,
381
  (object) array(
382
  'mesg' => __( 'Alert message not found.', 'wp-security-audit-log' ),
@@ -391,38 +382,38 @@ class WSAL_AuditLogListView extends WP_List_Table {
391
  $data_link = add_query_arg( 'page', 'wsal-togglealerts#tab-users-profiles---activity', admin_url( 'admin.php' ) );
392
  }
393
 
394
- if ( ! $this->_plugin->settings()->CurrentUserCan( 'edit' ) ) {
395
  return '<span class="log-disable">' . str_pad( $item->alert_id, 4, '0', STR_PAD_LEFT ) . ' </span>';
396
  }
397
 
398
  return '<span class="log-disable" data-disable-alert-nonce="' . wp_create_nonce( 'disable-alert-nonce' . $item->alert_id ) . '" data-tooltip="<strong>' . __( 'Disable this type of events.', 'wp-security-audit-log' ) . '</strong><br>' . $item->alert_id . ' - ' . esc_html( $code->desc ) . $extra_msg . '" data-alert-id="' . $item->alert_id . '" ' . esc_attr( 'data-link=' . $data_link ) . ' >'
399
  . str_pad( $item->alert_id, 4, '0', STR_PAD_LEFT ) . ' </span>';
400
  case 'code':
401
- $code = $this->_plugin->alerts->GetAlert( $item->alert_id );
402
  $code = $code ? $code->severity : 0;
403
- $const = $this->_plugin->constants->get_constant_to_display( $code );
404
 
405
- $css_classes = ['log-type', 'log-type-' . $const->value ];
406
- if (property_exists($const, 'css')) {
407
- array_push($css_classes, 'log-type-' . $const->css);
408
  }
409
  return '<a class="tooltip" href="#" data-tooltip="' . esc_html( $const->name ) . '"><span class="' . implode( ' ', $css_classes ) . '"></span></a>';
410
  case 'crtd':
411
  return $item->created_on
412
- ? WSAL_Utilities_DateTimeFormatter::instance()->getFormattedDateTime( $item->created_on, 'datetime', true, true )
413
- : '<i>' . __( 'Unknown', 'wp-security-audit-log' ) . '</i>';
414
  case 'user':
415
- $username = WSAL_Utilities_UsersUtils::GetUsername( $this->item_meta[ $item->getId() ] );
416
  $user = get_user_by( 'login', $username );
417
- $roles = '';
418
  $image = '<span class="dashicons dashicons-wordpress wsal-system-icon"></span>';
419
 
420
- // check if there's a user with given username
421
  if ( $user instanceof WP_User ) {
422
  // Get user avatar.
423
  $image = get_avatar( $user->ID, 32 );
424
 
425
- $display_name = WSAL_Utilities_UsersUtils::get_display_label( $this->_plugin, $user );
426
  $user_edit_link = admin_url( 'user-edit.php?user_id=' . $user->ID );
427
 
428
  // Additional user info tooltip.
@@ -431,12 +422,12 @@ class WSAL_AuditLogListView extends WP_List_Table {
431
  $uhtml = '<a class="tooltip" data-tooltip="' . esc_attr( $tooltip ) . '" data-user="' . $user->user_login . '" href="' . $user_edit_link . '" target="_blank">' . esc_html( $display_name ) . '</a>';
432
 
433
 
434
- $roles = WSAL_Utilities_UsersUtils::get_roles_label( $item->GetUserRoles() );
435
- } elseif ( 'Plugin' == $username ) {
436
  $uhtml = '<i>' . __( 'Plugin', 'wp-security-audit-log' ) . '</i>';
437
- } elseif ( 'Plugins' == $username ) {
438
  $uhtml = '<i>' . __( 'Plugins', 'wp-security-audit-log' ) . '</i>';
439
- } elseif ( 'Website Visitor' == $username || 'Unregistered user' == $username ) {
440
  $uhtml = '<i>' . __( 'Unregistered user', 'wp-security-audit-log' ) . '</i>';
441
  } else {
442
  $uhtml = '<i>' . __( 'System', 'wp-security-audit-log' ) . '</i>';
@@ -455,7 +446,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
455
  */
456
  return apply_filters( 'wsal_auditlog_row_user_data', $row_user_data, $this->current_alert_id );
457
  case 'scip':
458
- $scip = $item->GetSourceIP();
459
  if ( is_string( $scip ) ) {
460
  $scip = str_replace( array( '"', '[', ']' ), '', $scip );
461
  }
@@ -463,7 +454,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
463
  $oips = array();
464
 
465
  // If there's no IP...
466
- if ( is_null( $scip ) || '' == $scip ) {
467
  return '<i>unknown</i>';
468
  }
469
 
@@ -487,7 +478,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
487
 
488
  $html = "<a class='search-ip' data-tooltip='$tooltip' data-ip='$scip' target='_blank' href='https://whatismyipaddress.com/ip/$scip'>" . esc_html( $scip ) . '</a> <a href="javascript:;" onclick="jQuery(this).hide().next().show();">(more&hellip;)</a><div style="display: none;">';
489
  foreach ( $oips as $ip ) {
490
- if ( $scip != $ip ) {
491
  $html .= '<div>' . $ip . '</div>';
492
  }
493
  }
@@ -496,7 +487,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
496
  } else {
497
  $html = "<a target='_blank' href='https://whatismyipaddress.com/ip/$scip'>" . esc_html( $scip ) . '</a> <a href="javascript:;" onclick="jQuery(this).hide().next().show();">(more&hellip;)</a><div style="display: none;">';
498
  foreach ( $oips as $ip ) {
499
- if ( $scip != $ip ) {
500
  $html .= '<div>' . $ip . '</div>';
501
  }
502
  }
@@ -509,9 +500,9 @@ class WSAL_AuditLogListView extends WP_List_Table {
509
  return ! $info ? ( 'Unknown Site ' . $item->site_id )
510
  : ( '<a href="' . esc_attr( $info->siteurl ) . '">' . esc_html( $info->blogname ) . '</a>' );
511
  case 'mesg':
512
- $event_meta = $this->item_meta[ $item->getId() ];
513
- $result = '<div id="Event' . $item->id . '">' . $item->GetMessage( $event_meta ) . '</div>';
514
- $result .= $this->audit_log_view->maybe_build_teaser_html( $event_meta );
515
  return $result;
516
  case 'data':
517
  $url = admin_url( 'admin-ajax.php' ) . '?action=AjaxInspector&amp;occurrence=' . $item->id;
@@ -519,9 +510,9 @@ class WSAL_AuditLogListView extends WP_List_Table {
519
  return '<a class="more-info thickbox" data-tooltip="' . $tooltip . '" title="' . __( 'Alert Data Inspector', 'wp-security-audit-log' ) . '"'
520
  . ' href="' . $url . '&amp;TB_iframe=true&amp;width=600&amp;height=550">&hellip;</a>';
521
  case 'object':
522
- return isset( $this->item_meta[ $item->getId() ]['Object'] ) ? $this->_plugin->alerts->get_event_objects_data( $this->item_meta[ $item->getId() ]['Object'] ) : '';
523
  case 'event_type':
524
- return isset( $this->item_meta[ $item->getId() ]['EventType'] ) ? $this->_plugin->alerts->get_event_type_data( $this->item_meta[ $item->getId() ]['EventType'] ) : '';
525
  default:
526
  return isset( $item->$column_name )
527
  ? esc_html( $item->$column_name )
@@ -559,7 +550,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
559
  * @return bool
560
  */
561
  protected function is_multisite() {
562
- return $this->_plugin->IsMultisite();
563
  }
564
 
565
  /**
@@ -568,7 +559,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
568
  * @return bool
569
  */
570
  protected function is_main_blog() {
571
- return get_current_blog_id() == 1;
572
  }
573
 
574
  /**
@@ -577,7 +568,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
577
  * @return bool
578
  */
579
  protected function is_specific_view() {
580
- return isset( $this->query_args->site_id ) && '0' != $this->query_args->site_id;
581
  }
582
 
583
  /**
@@ -625,7 +616,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
625
  $total_items = isset( $query_events['total_items'] ) ? $query_events['total_items'] : false;
626
  $per_page = isset( $query_events['per_page'] ) ? $query_events['per_page'] : false;
627
 
628
- if ( ! $this->_plugin->settings()->is_infinite_scroll() ) {
629
  $this->set_pagination_args(
630
  array(
631
  'total_items' => $total_items,
@@ -662,7 +653,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
662
  public function print_column_headers( $with_id = true ) {
663
  list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
664
 
665
- $current_url = set_url_scheme( esc_url_raw( wp_unslash( $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ) ) );
666
  $current_url = remove_query_arg( 'paged', $current_url );
667
 
668
  // Set order by query arg.
@@ -688,13 +679,13 @@ class WSAL_AuditLogListView extends WP_List_Table {
688
  foreach ( $columns as $column_key => $column_display_name ) {
689
  $class = array( 'manage-column', "column-$column_key" );
690
 
691
- if ( in_array( $column_key, $hidden ) ) {
692
  $class[] = 'hidden';
693
  }
694
 
695
  if ( 'cb' === $column_key ) {
696
  $class[] = 'check-column';
697
- } elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ) ) ) {
698
  $class[] = 'num';
699
  }
700
 
@@ -726,7 +717,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
726
  $class = "class='" . implode( ' ', $class ) . "'";
727
  }
728
 
729
- echo "<$tag $scope $id $class>";
730
  echo ! in_array( $column_key, array( 'code', 'data', 'site' ), true ) ? '<div class="wsal-filter-wrap">' : '';
731
 
732
  if ( $with_id ) {
@@ -741,9 +732,9 @@ class WSAL_AuditLogListView extends WP_List_Table {
741
  do_action( 'wsal_audit_log_column_header', $column_key );
742
  }
743
 
744
- echo $column_display_name;
745
  echo ! in_array( $column_key, array( 'code', 'data', 'site' ), true ) ? '</div>' : '';
746
- echo "</$tag>";
747
  }
748
  }
749
 
@@ -770,7 +761,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
770
  $query = new WSAL_Models_OccurrenceQuery();
771
  $bid = (int) $this->query_args->site_id;
772
  if ( $bid ) {
773
- $query->addCondition( 'site_id = %s ', $bid );
774
  }
775
 
776
  /**
@@ -784,9 +775,9 @@ class WSAL_AuditLogListView extends WP_List_Table {
784
  */
785
  $query = apply_filters( 'wsal_auditlog_query', $query );
786
 
787
- if ( ! $this->_plugin->settings()->is_infinite_scroll() ) {
788
- $total_items = $query->getAdapter()->Count( $query );
789
- $per_page = $this->_plugin->settings()->GetViewPerPage();
790
  $offset = ( $this->get_pagenum() - 1 ) * $per_page;
791
  } else {
792
  $total_items = false;
@@ -799,7 +790,7 @@ class WSAL_AuditLogListView extends WP_List_Table {
799
  $order = isset( $this->query_args->order ) ? $this->query_args->order : false;
800
 
801
  if ( ! $order_by ) {
802
- $query->addOrderBy( 'created_on', true );
803
  } else {
804
  $is_descending = true;
805
  if ( $order && 'asc' === $order ) {
@@ -808,42 +799,42 @@ class WSAL_AuditLogListView extends WP_List_Table {
808
 
809
  // TO DO: Allow order by meta values.
810
  if ( 'scip' === $order_by ) {
811
- $query->addOrderBy( 'client_ip', $is_descending );
812
  } elseif ( 'user' === $order_by ) {
813
- $query->addOrderBy( 'user_id', $is_descending );
814
  } elseif ( 'code' === $order_by ) {
815
  /*
816
  * Handle the 'code' (Severity) column sorting.
817
  */
818
- $query->addOrderBy( 'severity', $is_descending );
819
  } elseif ( 'object' === $order_by ) {
820
  /*
821
  * Handle the 'object' column sorting.
822
  */
823
- $query->addOrderBy( 'object', $is_descending );
824
  } elseif ( 'event_type' === $order_by ) {
825
  /*
826
  * Handle the 'Event Type' column sorting.
827
  */
828
- $query->addOrderBy( 'event_type', $is_descending );
829
  } else {
830
  $tmp = new WSAL_Models_Occurrence();
831
  // Making sure the field exists to order by.
832
  if ( isset( $tmp->{$order_by} ) ) {
833
  // TODO: We used to use a custom comparator ... is it safe to let MySQL do the ordering now?.
834
- $query->addOrderBy( $order_by, $is_descending );
835
  } else {
836
- $query->addOrderBy( 'created_on', true );
837
  }
838
  }
839
  }
840
 
841
- $query->setOffset( $offset ); // Set query offset.
842
- $query->setLimit( $per_page ); // Set number of events per page.
843
  return array(
844
  'total_items' => $total_items,
845
  'per_page' => $per_page,
846
- 'items' => $query->getAdapter()->Execute( $query ),
847
  );
848
  }
849
  }
29
  *
30
  * @var WpSecurityAuditLog
31
  */
32
+ protected $plugin;
33
 
34
  /**
35
  * Current Alert ID
69
  private $item_meta = array();
70
 
71
  /**
72
+ * Audit log view.
73
+ *
74
  * @var WSAL_Views_AuditLog
75
  * @since 4.3.2
76
  */
79
  /**
80
  * Method: Constructor.
81
  *
82
+ * @param WpSecurityAuditLog $plugin Instance of WpSecurityAuditLog.
83
  * @param WSAL_Views_AuditLog $audit_log_view Audit log view.
84
+ * @param stdClass $query_args Events query arguments.
85
  */
86
  public function __construct( $plugin, $audit_log_view, $query_args ) {
87
+ $this->plugin = $plugin;
88
  $this->audit_log_view = $audit_log_view;
89
  $this->query_args = $query_args;
90
 
108
  /**
109
  * Array of class names that are applied to the table for this view.
110
  *
 
111
  * @since 4.0.0
112
  * @return array of strings
113
  */
143
  ?>
144
  <div class="display-type-buttons">
145
  <?php
146
+ $user_selected_view = $this->plugin->views->views[0]->detect_view_type();
147
  ?>
148
  <a id ="wsal-list-view-toggle" href="<?php echo esc_url( add_query_arg( 'view', 'list' ) ); ?>" class="button wsal-button dashicons-before dashicons-list-view" <?php echo ( 'list' === $user_selected_view ) ? esc_attr( 'disabled' ) : ''; ?>><?php esc_html_e( 'List View', 'wp-security-audit-log' ); ?></a>
149
  <a id ="wsal-grid-view-toggle" href="<?php echo esc_url( add_query_arg( 'view', 'grid' ) ); ?>" class="button wsal-button dashicons-before dashicons-grid-view" <?php echo ( 'grid' === $user_selected_view ) ? esc_attr( 'disabled' ) : ''; ?>><?php esc_html_e( 'Grid View', 'wp-security-audit-log' ); ?></a>
162
  */
163
  public function extra_tablenav( $which ) {
164
  // If the position is not top then render.
165
+ if ( 'top' !== $which && ! $this->plugin->settings()->is_infinite_scroll() ) :
166
  // Items-per-page widget.
167
+ $p = $this->plugin->settings()->get_views_per_page();
168
  $items = array( 5, 10, 15, 30, 50 );
169
  if ( ! in_array( $p, $items, true ) ) {
170
  $items[] = $p;
184
  <?php
185
  endif;
186
 
187
+ if ( 'top' !== $which && $this->plugin->settings()->is_infinite_scroll() ) :
188
  ?>
189
  <div id="wsal-auditlog-end"><p><?php esc_html_e( '— End of Activity Log —', 'wp-security-audit-log' ); ?></p></div>
190
  <div id="wsal-event-loader"><div class="wsal-lds-ellipsis"><div></div><div></div><div></div><div></div></div></div>
195
  // NOTE: this is shown when the filter IS NOT true.
196
  if ( $this->is_multisite() && $this->is_main_blog() && ! apply_filters( 'search_extensition_active', false ) ) {
197
  if (
198
+ ( 'top' === $which && $this->plugin->settings()->is_infinite_scroll() )
199
+ || ! $this->plugin->settings()->is_infinite_scroll()
200
  ) {
201
+ $curr = $this->plugin->settings()->get_view_site_id();
202
  ?>
203
  <div class="wsal-ssa wsal-ssa-<?php echo esc_attr( $which ); ?>">
204
  <?php if ( $this->get_site_count() > 15 ) : ?>
209
  <select class="wsal-ssas" onchange="WsalSsasChange(value);">
210
  <option value="0"><?php esc_html_e( 'All Sites', 'wp-security-audit-log' ); ?></option>
211
  <?php foreach ( $this->get_sites() as $info ) : ?>
212
+ <option value="<?php echo esc_attr( $info->blog_id ); ?>" <?php selected( $info->blog_id, $curr ); ?>>
213
  <?php echo esc_html( $info->blogname ) . ' (' . esc_html( $info->domain ) . ')'; ?>
214
  </option>
215
  <?php endforeach; ?>
237
  }
238
 
239
  // Execute query.
240
+ $res = $wpdb->get_results( $sql ); // phpcs:ignore
241
 
242
  // Modify result.
243
  foreach ( $res as $row ) {
256
  public function get_site_count() {
257
  global $wpdb;
258
  $sql = 'SELECT COUNT(*) FROM ' . $wpdb->blogs;
259
+ return (int) $wpdb->get_var( $sql ); // phpcs:ignore
260
  }
261
 
262
  /**
285
 
286
  // Get selected columns from settings.
287
  if ( empty( $this->selected_columns ) && ! is_array( $this->selected_columns ) ) {
288
+ $this->selected_columns = $this->plugin->settings()->get_columns_selected();
289
  }
290
 
291
  // If selected columns are not empty, then unset default columns.
321
  case 'message':
322
  $cols['mesg'] = __( 'Message', 'wp-security-audit-log' );
323
  break;
324
+ default:
325
+ // Fallback for any new columns would go here.
326
+ break;
327
  }
328
  }
329
  }
332
  }
333
 
334
  /**
335
+ * {@inheritDoc}
 
 
 
336
  */
337
  public function column_cb( $item ) {
338
  return '<input type="checkbox" value="' . $item->id . '" name="' . esc_attr( $this->_args['singular'] ) . '[]" />';
339
  }
340
 
341
  /**
342
+ * {@inheritDoc}
 
 
343
  */
344
  public function get_sortable_columns() {
345
  return array(
354
  }
355
 
356
  /**
357
+ * {@inheritDoc}
 
 
 
 
 
358
  */
359
  public function column_default( $item, $column_name ) {
360
  // Store meta if not set.
361
+ if ( ! isset( $this->item_meta[ $item->get_id() ] ) ) {
362
+ $this->item_meta[ $item->get_id() ] = $item->get_meta_array();
363
  }
364
 
365
  // Store current alert id.
367
 
368
  switch ( $column_name ) {
369
  case 'type':
370
+ $code = $this->plugin->alerts->get_alert(
371
  $item->alert_id,
372
  (object) array(
373
  'mesg' => __( 'Alert message not found.', 'wp-security-audit-log' ),
382
  $data_link = add_query_arg( 'page', 'wsal-togglealerts#tab-users-profiles---activity', admin_url( 'admin.php' ) );
383
  }
384
 
385
+ if ( ! $this->plugin->settings()->current_user_can( 'edit' ) ) {
386
  return '<span class="log-disable">' . str_pad( $item->alert_id, 4, '0', STR_PAD_LEFT ) . ' </span>';
387
  }
388
 
389
  return '<span class="log-disable" data-disable-alert-nonce="' . wp_create_nonce( 'disable-alert-nonce' . $item->alert_id ) . '" data-tooltip="<strong>' . __( 'Disable this type of events.', 'wp-security-audit-log' ) . '</strong><br>' . $item->alert_id . ' - ' . esc_html( $code->desc ) . $extra_msg . '" data-alert-id="' . $item->alert_id . '" ' . esc_attr( 'data-link=' . $data_link ) . ' >'
390
  . str_pad( $item->alert_id, 4, '0', STR_PAD_LEFT ) . ' </span>';
391
  case 'code':
392
+ $code = $this->plugin->alerts->get_alert( $item->alert_id );
393
  $code = $code ? $code->severity : 0;
394
+ $const = $this->plugin->constants->get_constant_to_display( $code );
395
 
396
+ $css_classes = array( 'log-type', 'log-type-' . $const->value );
397
+ if ( property_exists( $const, 'css' ) ) {
398
+ array_push( $css_classes, 'log-type-' . $const->css );
399
  }
400
  return '<a class="tooltip" href="#" data-tooltip="' . esc_html( $const->name ) . '"><span class="' . implode( ' ', $css_classes ) . '"></span></a>';
401
  case 'crtd':
402
  return $item->created_on
403
+ ? WSAL_Utilities_DateTimeFormatter::instance()->get_formatted_date_time( $item->created_on, 'datetime', true, true )
404
+ : '<i>' . __( 'Unknown', 'wp-security-audit-log' ) . '</i>';
405
  case 'user':
406
+ $username = WSAL_Utilities_UsersUtils::get_username( $this->item_meta[ $item->get_id() ] );
407
  $user = get_user_by( 'login', $username );
408
+ $roles = '';
409
  $image = '<span class="dashicons dashicons-wordpress wsal-system-icon"></span>';
410
 
411
+ // Check if there's a user with given username.
412
  if ( $user instanceof WP_User ) {
413
  // Get user avatar.
414
  $image = get_avatar( $user->ID, 32 );
415
 
416
+ $display_name = WSAL_Utilities_UsersUtils::get_display_label( $this->plugin, $user );
417
  $user_edit_link = admin_url( 'user-edit.php?user_id=' . $user->ID );
418
 
419
  // Additional user info tooltip.
422
  $uhtml = '<a class="tooltip" data-tooltip="' . esc_attr( $tooltip ) . '" data-user="' . $user->user_login . '" href="' . $user_edit_link . '" target="_blank">' . esc_html( $display_name ) . '</a>';
423
 
424
 
425
+ $roles = WSAL_Utilities_UsersUtils::get_roles_label( $item->get_user_roles() );
426
+ } elseif ( 'Plugin' === $username ) {
427
  $uhtml = '<i>' . __( 'Plugin', 'wp-security-audit-log' ) . '</i>';
428
+ } elseif ( 'Plugins' === $username ) {
429
  $uhtml = '<i>' . __( 'Plugins', 'wp-security-audit-log' ) . '</i>';
430
+ } elseif ( 'Website Visitor' === $username || 'Unregistered user' === $username ) {
431
  $uhtml = '<i>' . __( 'Unregistered user', 'wp-security-audit-log' ) . '</i>';
432
  } else {
433
  $uhtml = '<i>' . __( 'System', 'wp-security-audit-log' ) . '</i>';
446
  */
447
  return apply_filters( 'wsal_auditlog_row_user_data', $row_user_data, $this->current_alert_id );
448
  case 'scip':
449
+ $scip = $item->get_source_ip();
450
  if ( is_string( $scip ) ) {
451
  $scip = str_replace( array( '"', '[', ']' ), '', $scip );
452
  }
454
  $oips = array();
455
 
456
  // If there's no IP...
457
+ if ( is_null( $scip ) || '' === $scip ) {
458
  return '<i>unknown</i>';
459
  }
460
 
478
 
479
  $html = "<a class='search-ip' data-tooltip='$tooltip' data-ip='$scip' target='_blank' href='https://whatismyipaddress.com/ip/$scip'>" . esc_html( $scip ) . '</a> <a href="javascript:;" onclick="jQuery(this).hide().next().show();">(more&hellip;)</a><div style="display: none;">';
480
  foreach ( $oips as $ip ) {
481
+ if ( $scip != $ip ) { // phpcs:ignore
482
  $html .= '<div>' . $ip . '</div>';
483
  }
484
  }
487
  } else {
488
  $html = "<a target='_blank' href='https://whatismyipaddress.com/ip/$scip'>" . esc_html( $scip ) . '</a> <a href="javascript:;" onclick="jQuery(this).hide().next().show();">(more&hellip;)</a><div style="display: none;">';
489
  foreach ( $oips as $ip ) {
490
+ if ( $scip != $ip ) { // phpcs:ignore
491
  $html .= '<div>' . $ip . '</div>';
492
  }
493
  }
500
  return ! $info ? ( 'Unknown Site ' . $item->site_id )
501
  : ( '<a href="' . esc_attr( $info->siteurl ) . '">' . esc_html( $info->blogname ) . '</a>' );
502
  case 'mesg':
503
+ $event_meta = $this->item_meta[ $item->get_id() ];
504
+ $result = '<div id="Event' . $item->id . '">' . $item->get_message( $event_meta ) . '</div>';
505
+ $result .= $this->audit_log_view->maybe_build_teaser_html( $event_meta );
506
  return $result;
507
  case 'data':
508
  $url = admin_url( 'admin-ajax.php' ) . '?action=AjaxInspector&amp;occurrence=' . $item->id;
510
  return '<a class="more-info thickbox" data-tooltip="' . $tooltip . '" title="' . __( 'Alert Data Inspector', 'wp-security-audit-log' ) . '"'
511
  . ' href="' . $url . '&amp;TB_iframe=true&amp;width=600&amp;height=550">&hellip;</a>';
512
  case 'object':
513
+ return isset( $this->item_meta[ $item->get_id() ]['Object'] ) ? $this->plugin->alerts->get_event_objects_data( $this->item_meta[ $item->get_id() ]['Object'] ) : '';
514
  case 'event_type':
515
+ return isset( $this->item_meta[ $item->get_id() ]['EventType'] ) ? $this->plugin->alerts->get_event_type_data( $this->item_meta[ $item->get_id() ]['EventType'] ) : '';
516
  default:
517
  return isset( $item->$column_name )
518
  ? esc_html( $item->$column_name )
550
  * @return bool
551
  */
552
  protected function is_multisite() {
553
+ return $this->plugin->is_multisite();
554
  }
555
 
556
  /**
559
  * @return bool
560
  */
561
  protected function is_main_blog() {
562
+ return get_current_blog_id() === 1;
563
  }
564
 
565
  /**
568
  * @return bool
569
  */
570
  protected function is_specific_view() {
571
+ return isset( $this->query_args->site_id ) && '0' != $this->query_args->site_id; // phpcs:ignore
572
  }
573
 
574
  /**
616
  $total_items = isset( $query_events['total_items'] ) ? $query_events['total_items'] : false;
617
  $per_page = isset( $query_events['per_page'] ) ? $query_events['per_page'] : false;
618
 
619
+ if ( ! $this->plugin->settings()->is_infinite_scroll() ) {
620
  $this->set_pagination_args(
621
  array(
622
  'total_items' => $total_items,
653
  public function print_column_headers( $with_id = true ) {
654
  list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
655
 
656
+ $current_url = set_url_scheme( esc_url_raw( wp_unslash( $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ) ) ); // phpcs:ignore
657
  $current_url = remove_query_arg( 'paged', $current_url );
658
 
659
  // Set order by query arg.
679
  foreach ( $columns as $column_key => $column_display_name ) {
680
  $class = array( 'manage-column', "column-$column_key" );
681
 
682
+ if ( in_array( $column_key, $hidden, true ) ) {
683
  $class[] = 'hidden';
684
  }
685
 
686
  if ( 'cb' === $column_key ) {
687
  $class[] = 'check-column';
688
+ } elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ), true ) ) {
689
  $class[] = 'num';
690
  }
691
 
717
  $class = "class='" . implode( ' ', $class ) . "'";
718
  }
719
 
720
+ echo "<$tag $scope $id $class>"; // phpcs:ignore
721
  echo ! in_array( $column_key, array( 'code', 'data', 'site' ), true ) ? '<div class="wsal-filter-wrap">' : '';
722
 
723
  if ( $with_id ) {
732
  do_action( 'wsal_audit_log_column_header', $column_key );
733
  }
734
 
735
+ echo $column_display_name; // phpcs:ignore
736
  echo ! in_array( $column_key, array( 'code', 'data', 'site' ), true ) ? '</div>' : '';
737
+ echo "</$tag>"; // phpcs:ignore
738
  }
739
  }
740
 
761
  $query = new WSAL_Models_OccurrenceQuery();
762
  $bid = (int) $this->query_args->site_id;
763
  if ( $bid ) {
764
+ $query->add_condition( 'site_id = %s ', $bid );
765
  }
766
 
767
  /**
775
  */
776
  $query = apply_filters( 'wsal_auditlog_query', $query );
777
 
778
+ if ( ! $this->plugin->settings()->is_infinite_scroll() ) {
779
+ $total_items = $query->get_adapter()->count( $query );
780
+ $per_page = $this->plugin->settings()->get_views_per_page();
781
  $offset = ( $this->get_pagenum() - 1 ) * $per_page;
782
  } else {
783
  $total_items = false;
790
  $order = isset( $this->query_args->order ) ? $this->query_args->order : false;
791
 
792
  if ( ! $order_by ) {
793
+ $query->add_order_by( 'created_on', true );
794
  } else {
795
  $is_descending = true;
796
  if ( $order && 'asc' === $order ) {
799
 
800
  // TO DO: Allow order by meta values.
801
  if ( 'scip' === $order_by ) {
802
+ $query->add_order_by( 'client_ip', $is_descending );
803
  } elseif ( 'user' === $order_by ) {
804
+ $query->add_order_by( 'user_id', $is_descending );
805
  } elseif ( 'code' === $order_by ) {
806
  /*
807
  * Handle the 'code' (Severity) column sorting.
808
  */
809
+ $query->add_order_by( 'severity', $is_descending );
810
  } elseif ( 'object' === $order_by ) {
811
  /*
812
  * Handle the 'object' column sorting.
813
  */
814
+ $query->add_order_by( 'object', $is_descending );
815
  } elseif ( 'event_type' === $order_by ) {
816
  /*
817
  * Handle the 'Event Type' column sorting.
818
  */
819
+ $query->add_order_by( 'event_type', $is_descending );
820
  } else {
821
  $tmp = new WSAL_Models_Occurrence();
822
  // Making sure the field exists to order by.
823
  if ( isset( $tmp->{$order_by} ) ) {
824
  // TODO: We used to use a custom comparator ... is it safe to let MySQL do the ordering now?.
825
+ $query->add_order_by( $order_by, $is_descending );
826
  } else {
827
+ $query->add_order_by( 'created_on', true );
828
  }
829
  }
830
  }
831
 
832
+ $query->set_offset( $offset ); // Set query offset.
833
+ $query->set_limit( $per_page ); // Set number of events per page.
834
  return array(
835
  'total_items' => $total_items,
836
  'per_page' => $per_page,
837
+ 'items' => $query->get_adapter()->execute_query( $query ),
838
  );
839
  }
840
  }
classes/Autoloader.php CHANGED
@@ -1,4 +1,10 @@
1
  <?php
 
 
 
 
 
 
2
  /**
3
  * Classes Auto Loader.
4
  *
@@ -29,7 +35,7 @@ class WSAL_Autoloader {
29
  $this->plugin = $plugin;
30
 
31
  // Register autoloader.
32
- spl_autoload_register( array( $this, 'LoadClass' ) );
33
  }
34
 
35
  /**
@@ -38,7 +44,7 @@ class WSAL_Autoloader {
38
  * @param string $prefix - Prefix of the class.
39
  * @param string $path - Path of the file.
40
  */
41
- public function Register( $prefix, $path ) {
42
  if ( ! isset( $this->paths[ $prefix ] ) ) {
43
  $this->paths[ $prefix ] = array();
44
  }
@@ -51,7 +57,7 @@ class WSAL_Autoloader {
51
  * @param string $class - Class name.
52
  * @return boolean - True if class is found and loaded, false otherwise.
53
  */
54
- public function LoadClass( $class ) {
55
  foreach ( $this->paths as $prefix => $paths ) {
56
  foreach ( $paths as $path ) {
57
  if ( strstr( $class, $prefix ) !== false ) {
@@ -72,7 +78,7 @@ class WSAL_Autoloader {
72
  * @param string $file File name.
73
  * @return string|false Class name or false on error.
74
  */
75
- public function GetClassFileClassName( $file ) {
76
  $file = str_replace( '\\', '/', $file ); // Win/DOS hotfix.
77
 
78
  foreach ( $this->paths as $prefix => $paths ) {
1
  <?php
2
+ /**
3
+ * Autoloader class.
4
+ *
5
+ * @package wsal
6
+ */
7
+
8
  /**
9
  * Classes Auto Loader.
10
  *
35
  $this->plugin = $plugin;
36
 
37
  // Register autoloader.
38
+ spl_autoload_register( array( $this, 'load_class' ) );
39
  }
40
 
41
  /**
44
  * @param string $prefix - Prefix of the class.
45
  * @param string $path - Path of the file.
46
  */
47
+ public function register( $prefix, $path ) {
48
  if ( ! isset( $this->paths[ $prefix ] ) ) {
49
  $this->paths[ $prefix ] = array();
50
  }
57
  * @param string $class - Class name.
58
  * @return boolean - True if class is found and loaded, false otherwise.
59
  */
60
+ public function load_class( $class ) {
61
  foreach ( $this->paths as $prefix => $paths ) {
62
  foreach ( $paths as $path ) {
63
  if ( strstr( $class, $prefix ) !== false ) {
78
  * @param string $file File name.
79
  * @return string|false Class name or false on error.
80
  */
81
+ public function get_class_file_class_name( $file ) {
82
  $file = str_replace( '\\', '/', $file ); // Win/DOS hotfix.
83
 
84
  foreach ( $this->paths as $prefix => $paths ) {
classes/Connector/AbstractConnector.php CHANGED
@@ -12,8 +12,7 @@ if ( ! defined( 'ABSPATH' ) ) {
12
  exit;
13
  }
14
 
15
- // require_once('ConnectorInterface.php');.
16
- require_once( 'wp-db-custom.php' );
17
 
18
  /**
19
  * Adapter Classes loader class.
@@ -36,14 +35,14 @@ abstract class WSAL_Connector_AbstractConnector {
36
  *
37
  * @var null
38
  */
39
- protected $adaptersBasePath = null;
40
 
41
  /**
42
  * Adapter Directory Name.
43
  *
44
  * @var null
45
  */
46
- protected $adaptersDirName = null;
47
 
48
  /**
49
  * Method: Constructor.
@@ -51,14 +50,15 @@ abstract class WSAL_Connector_AbstractConnector {
51
  * @param string $adapters_dir_name - Adapter directory name.
52
  */
53
  public function __construct( $adapters_dir_name = null ) {
54
- $this->adaptersBasePath = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'Adapters' . DIRECTORY_SEPARATOR;
55
  if ( ! empty( $adapters_dir_name ) ) {
56
- $this->adaptersDirName = $adapters_dir_name;
57
- require_once( $this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . 'ActiveRecordAdapter.php' );
58
- require_once( $this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . 'MetaAdapter.php' );
59
- require_once( $this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . 'OccurrenceAdapter.php' );
60
- require_once( $this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . 'QueryAdapter.php' );
61
- require_once( $this->getAdaptersDirectory() . DIRECTORY_SEPARATOR . 'TmpUserAdapter.php' );
 
62
  do_action( 'wsal_require_additional_adapters' );
63
  }
64
  }
@@ -66,9 +66,9 @@ abstract class WSAL_Connector_AbstractConnector {
66
  /**
67
  * Method: Get adapters directory.
68
  */
69
- public function getAdaptersDirectory() {
70
- if ( ! empty( $this->adaptersBasePath ) && ! empty( $this->adaptersDirName ) ) {
71
- return $this->adaptersBasePath . $this->adaptersDirName;
72
  } else {
73
  return false;
74
  }
12
  exit;
13
  }
14
 
15
+ require_once 'wp-db-custom.php';
 
16
 
17
  /**
18
  * Adapter Classes loader class.
35
  *
36
  * @var null
37
  */
38
+ protected $adapters_base_path = null;
39
 
40
  /**
41
  * Adapter Directory Name.
42
  *
43
  * @var null
44
  */
45
+ protected $adapters_dir_name = null;
46
 
47
  /**
48
  * Method: Constructor.
50
  * @param string $adapters_dir_name - Adapter directory name.
51
  */
52
  public function __construct( $adapters_dir_name = null ) {
53
+ $this->adapters_base_path = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'Adapters' . DIRECTORY_SEPARATOR;
54
  if ( ! empty( $adapters_dir_name ) ) {
55
+ $this->adapters_dir_name = $adapters_dir_name;
56
+ $adapters_directory = $this->get_adapters_directory();
57
+ require_once $adapters_directory . DIRECTORY_SEPARATOR . 'ActiveRecordAdapter.php';
58
+ require_once $adapters_directory . DIRECTORY_SEPARATOR . 'MetaAdapter.php';
59
+ require_once $adapters_directory . DIRECTORY_SEPARATOR . 'OccurrenceAdapter.php';
60
+ require_once $adapters_directory . DIRECTORY_SEPARATOR . 'QueryAdapter.php';
61
+ require_once $adapters_directory . DIRECTORY_SEPARATOR . 'TmpUserAdapter.php';
62
  do_action( 'wsal_require_additional_adapters' );
63
  }
64
  }
66
  /**
67
  * Method: Get adapters directory.
68
  */
69
+ public function get_adapters_directory() {
70
+ if ( ! empty( $this->adapters_base_path ) && ! empty( $this->adapters_dir_name ) ) {
71
+ return $this->adapters_base_path . $this->adapters_dir_name;
72
  } else {
73
  return false;
74
  }
classes/Connector/ConnectorFactory.php CHANGED
@@ -58,7 +58,7 @@ abstract class WSAL_Connector_ConnectorFactory {
58
  * Returns the default WPDB connector that must be always used for some data, for example user sessions and
59
  * also custom options table in the past.
60
  */
61
- public static function GetDefaultConnector() {
62
  return new WSAL_Connector_MySQLDB();
63
  }
64
 
@@ -71,17 +71,17 @@ abstract class WSAL_Connector_ConnectorFactory {
71
  * @return WSAL_Connector_ConnectorInterface
72
  * @throws Freemius_Exception
73
  */
74
- public static function GetConnector( $config = null, $reset = false ) {
75
  $connection_config = null;
76
  if ( is_null( $config ) || empty( $config ) ) {
77
  if ( self::$archive_mode ) {
78
  // Force archive database if no config provided and archive mode is enabled.
79
- $plugin = WpSecurityAuditLog::GetInstance();
80
- $connection_name = $plugin->GetGlobalSetting( 'archive-connection' );
81
  $connection_config = self::load_connection_config( $connection_name );
82
  } else {
83
  // Default config - local or external, depending on plugin settings and licensing.
84
- $connection_config = self::GetConfig( $config );
85
  }
86
  } else {
87
  if ( is_string( $config ) ) {
@@ -124,9 +124,9 @@ abstract class WSAL_Connector_ConnectorFactory {
124
  * @return array|null adapter config
125
  * @throws Freemius_Exception
126
  */
127
- public static function GetConfig() {
128
- $plugin = WpSecurityAuditLog::GetInstance();
129
- $connection_name = $plugin->GetGlobalSetting( 'adapter-connection' );
130
 
131
  if ( function_exists( 'wsal_freemius' ) && ! apply_filters( 'wsal_disable_freemius_sdk', false ) ) {
132
  $is_not_paying = wsal_freemius()->is_not_paying();
@@ -138,8 +138,8 @@ abstract class WSAL_Connector_ConnectorFactory {
138
  $connector = new WSAL_Connector_MySQLDB();
139
 
140
  if ( ! self::$is_installed ) {
141
- self::$is_installed = $connector->isInstalled();
142
- $connector->installAll();
143
  }
144
 
145
  $connection_name = null;
@@ -166,9 +166,9 @@ abstract class WSAL_Connector_ConnectorFactory {
166
  *
167
  * @see WSAL_Ext_Common::get_connection()
168
  */
169
- $plugin = WpSecurityAuditLog::GetInstance();
170
- $connection_raw = maybe_unserialize( $plugin->GetGlobalSetting( 'connection-' . $connection_name ) );
171
- $connection = ( $connection_raw instanceof stdClass ) ? json_decode( json_encode( $connection_raw ), true ) : $connection_raw;
172
  if ( ! is_array( $connection ) || empty( $connection ) ) {
173
  return null;
174
  }
@@ -183,7 +183,7 @@ abstract class WSAL_Connector_ConnectorFactory {
183
  *
184
  * @return boolean true|false
185
  */
186
- public static function CheckConfig( $config ) {
187
  // Only mysql supported at the moment.
188
  if ( array_key_exists( 'type', $config ) && 'mysql' === $config['type'] ) {
189
  try {
58
  * Returns the default WPDB connector that must be always used for some data, for example user sessions and
59
  * also custom options table in the past.
60
  */
61
+ public static function get_default_connector() {
62
  return new WSAL_Connector_MySQLDB();
63
  }
64
 
71
  * @return WSAL_Connector_ConnectorInterface
72
  * @throws Freemius_Exception
73
  */
74
+ public static function get_connector( $config = null, $reset = false ) {
75
  $connection_config = null;
76
  if ( is_null( $config ) || empty( $config ) ) {
77
  if ( self::$archive_mode ) {
78
  // Force archive database if no config provided and archive mode is enabled.
79
+ $plugin = WpSecurityAuditLog::get_instance();
80
+ $connection_name = $plugin->get_global_setting( 'archive-connection' );
81
  $connection_config = self::load_connection_config( $connection_name );
82
  } else {
83
  // Default config - local or external, depending on plugin settings and licensing.
84
+ $connection_config = self::get_config( $config );
85
  }
86
  } else {
87
  if ( is_string( $config ) ) {
124
  * @return array|null adapter config
125
  * @throws Freemius_Exception
126
  */
127
+ public static function get_config() {
128
+ $plugin = WpSecurityAuditLog::get_instance();
129
+ $connection_name = $plugin->get_global_setting( 'adapter-connection' );
130
 
131
  if ( function_exists( 'wsal_freemius' ) && ! apply_filters( 'wsal_disable_freemius_sdk', false ) ) {
132
  $is_not_paying = wsal_freemius()->is_not_paying();
138
  $connector = new WSAL_Connector_MySQLDB();
139
 
140
  if ( ! self::$is_installed ) {
141
+ self::$is_installed = $connector->is_installed();
142
+ $connector->install_all();
143
  }
144
 
145
  $connection_name = null;
166
  *
167
  * @see WSAL_Ext_Common::get_connection()
168
  */
169
+ $plugin = WpSecurityAuditLog::get_instance();
170
+ $connection_raw = maybe_unserialize( $plugin->get_global_setting( 'connection-' . $connection_name ) );
171
+ $connection = ( $connection_raw instanceof stdClass ) ? json_decode( json_encode( $connection_raw ), true ) : $connection_raw; // phpcs:ignore
172
  if ( ! is_array( $connection ) || empty( $connection ) ) {
173
  return null;
174
  }
183
  *
184
  * @return boolean true|false
185
  */
186
+ public static function check_config( $config ) {
187
  // Only mysql supported at the moment.
188
  if ( array_key_exists( 'type', $config ) && 'mysql' === $config['type'] ) {
189
  try {
classes/Connector/ConnectorInterface.php CHANGED
@@ -26,53 +26,53 @@ interface WSAL_Connector_ConnectorInterface {
26
  *
27
  * @return WSAL_Adapters_ActiveRecordInterface
28
  */
29
- public function getAdapter( $class_name );
30
 
31
  /**
32
  * Get the connection.
33
  *
34
  * @return wpdb
35
  */
36
- public function getConnection();
37
 
38
  /**
39
  * Close the connection.
40
  */
41
- public function closeConnection();
42
 
43
  /**
44
  * Checks if the necessary tables are available
45
  *
46
  * @return bool true|false
47
  */
48
- public function isInstalled();
49
 
50
  /**
51
  * Install all.
52
  *
53
- * @param bool $is_external_database
54
  */
55
- public function installAll( $is_external_database = false );
56
 
57
  /**
58
- * Install single.
59
  *
60
- * @param $class_name
61
- * @param bool $is_external_database
62
  *
63
  * @since 4.1.4.1
64
  */
65
- public function installSingle( $class_name, $is_external_database = false );
66
 
67
  /**
68
  * Uninstall all.
69
  */
70
- public function uninstallAll();
71
 
72
  /**
73
  * Run any query.
74
  *
75
- * @param string $query
76
  *
77
  * @return mixed
78
  * @since 4.4.0
26
  *
27
  * @return WSAL_Adapters_ActiveRecordInterface
28
  */
29
+ public function get_adapter( $class_name );
30
 
31
  /**
32
  * Get the connection.
33
  *
34
  * @return wpdb
35
  */
36
+ public function get_connection();
37
 
38
  /**
39
  * Close the connection.
40
  */
41
+ public function close_connection();
42
 
43
  /**
44
  * Checks if the necessary tables are available
45
  *
46
  * @return bool true|false
47
  */
48
+ public function is_installed();
49
 
50
  /**
51
  * Install all.
52
  *
53
+ * @param bool $is_external_database True if this is external database.
54
  */
55
+ public function install_all( $is_external_database = false );
56
 
57
  /**
58
+ * Installs single database table based on its adapter class name.
59
  *
60
+ * @param string $class_name Adapter class name.
61
+ * @param bool $is_external_database True if this is external database.
62
  *
63
  * @since 4.1.4.1
64
  */
65
+ public function install_single( $class_name, $is_external_database = false );
66
 
67
  /**
68
  * Uninstall all.
69
  */
70
+ public function uninstall_all();
71
 
72
  /**
73
  * Run any query.
74
  *
75
+ * @param string $query Databse query to execute.
76
  *
77
  * @return mixed
78
  * @since 4.4.0
classes/Connector/MySQLDB.php CHANGED
@@ -26,7 +26,7 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
26
  *
27
  * @var array
28
  */
29
- protected $connectionConfig = null;
30
 
31
  /**
32
  * Method: Constructor.
@@ -34,7 +34,7 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
34
  * @param array $connection_config - Connection config.
35
  */
36
  public function __construct( $connection_config = null ) {
37
- $this->connectionConfig = $connection_config;
38
  parent::__construct( 'MySQL' );
39
  }
40
 
@@ -45,21 +45,21 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
45
  * @throws Exception - Connection failed.
46
  */
47
  public function TestConnection() {
48
- error_reporting( E_ALL ^ ( E_NOTICE | E_WARNING | E_DEPRECATED ) );
49
- $connection_config = $this->connectionConfig;
50
- $password = $this->decryptString( $connection_config['password'] );
51
 
52
  $new_wpdb = new wpdbCustom( $connection_config['user'], $password, $connection_config['db_name'], $connection_config['hostname'], $connection_config['is_ssl'], $connection_config['is_cc'], $connection_config['ssl_ca'], $connection_config['ssl_cert'], $connection_config['ssl_key'] );
53
 
54
  if ( isset( $new_wpdb->error ) && isset( $new_wpdb->dbh ) ) {
55
  throw new Exception( $new_wpdb->dbh->error, $new_wpdb->dbh->errno );
56
  } elseif ( ! isset( $new_wpdb->dbh ) ) {
57
- $error_code = mysqli_connect_errno();
58
 
59
  if ( 1045 === $error_code ) {
60
  throw new Exception( __( 'Error establishing a database connection. DB username or password are not valid.' ), $error_code );
61
  } else {
62
- $error_message = mysqli_connect_error();
63
  // if we get an error message from mysqli then use it otherwise use a generic message.
64
  if ( $error_message ) {
65
  throw new Exception(
@@ -91,7 +91,7 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
91
  * @return string
92
  * @since 2.6.3
93
  */
94
- public function decryptString( $ciphertext_base64 ) {
95
  $encrypt_method = 'AES-256-CBC';
96
  $secret_key = $this->truncateKey();
97
  $secret_iv = $this->get_openssl_iv();
@@ -102,7 +102,7 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
102
  // iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning.
103
  $iv = substr( hash( 'sha256', $secret_iv ), 0, 16 );
104
 
105
- return openssl_decrypt( base64_decode( $ciphertext_base64 ), $encrypt_method, $key, 0, $iv );
106
  }
107
 
108
  /**
@@ -140,24 +140,22 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
140
  }
141
 
142
  /**
143
- * Close DB connection
144
  */
145
- public function closeConnection() {
146
- $current_wpdb = $this->getConnection();
147
 
148
  return $current_wpdb->close();
149
  }
150
 
151
  /**
152
- * Returns a wpdb instance
153
- *
154
- * @return wpdb
155
  */
156
- public function getConnection() {
157
  if ( ! empty( $this->connection ) ) {
158
  return $this->connection;
159
  } else {
160
- $this->connection = $this->createConnection();
161
 
162
  return $this->connection;
163
  }
@@ -168,10 +166,10 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
168
  *
169
  * @return wpdb Instance of WPDB.
170
  */
171
- private function createConnection() {
172
- if ( ! empty( $this->connectionConfig ) ) {
173
- $connection_config = $this->connectionConfig;
174
- $password = $this->decryptString( $connection_config['password'] );
175
  $new_wpdb = new wpdbCustom( $connection_config['user'], $password, $connection_config['db_name'], $connection_config['hostname'], $connection_config['is_ssl'], $connection_config['is_cc'], $connection_config['ssl_ca'], $connection_config['ssl_cert'], $connection_config['ssl_key'] );
176
  if ( array_key_exists( 'baseprefix', $connection_config ) ) {
177
  $new_wpdb->set_prefix( $connection_config['baseprefix'] );
@@ -186,12 +184,12 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
186
  }
187
 
188
  /**
189
- * @inheritDoc
190
  */
191
- public function getAdapter( $class_name ) {
192
- $obj_name = $this->getAdapterClassName( $class_name );
193
 
194
- return new $obj_name( $this->getConnection() );
195
  }
196
 
197
  /**
@@ -201,76 +199,71 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
201
  *
202
  * @return string
203
  */
204
- protected function getAdapterClassName( $class_name ) {
205
  return 'WSAL_Adapters_MySQL_' . $class_name;
206
  }
207
 
208
  /**
209
- * @inheritDoc
210
  */
211
- public function isInstalled() {
212
- $wpdb = $this->getConnection();
213
  $table = $wpdb->base_prefix . 'wsal_occurrences';
214
- $db_result = $wpdb->query( "SELECT COUNT(1) FROM {$table};" );
215
 
216
  return 1 === $db_result;
217
  }
218
 
219
  /**
220
- * Install all DB tables.
221
- *
222
- * @param bool $is_external_database If true, some tables will not be created.
223
  */
224
- public function installAll( $is_external_database = false ) {
225
- $adapter_list = WSAL_Utilities_FileSystemUtils::read_files_in_folder( $this->getAdaptersDirectory(), '*.php' );
226
  $adapter_list = apply_filters( 'wsal_install_adapters_list', $adapter_list );
227
  foreach ( $adapter_list as $file ) {
228
  $file_path = explode( DIRECTORY_SEPARATOR, $file );
229
  $file_name = $file_path[ count( $file_path ) - 1 ];
230
- $class_name = $this->getAdapterClassName( str_replace( 'Adapter.php', '', $file_name ) );
231
- $this->installSingle( $class_name, $is_external_database );
232
  }
233
  }
234
 
235
  /**
236
- * Installs single database table based on its adapter class name.
237
- *
238
- * @param string $class_name
239
- * @param bool $is_external_database
240
  */
241
- public function installSingle( $class_name, $is_external_database = false ) {
242
  if ( ! class_exists( $class_name ) ) {
243
  return;
244
  }
245
 
246
- $class = new $class_name( $this->getConnection() );
247
  if ( $is_external_database && $class instanceof WSAL_Adapters_MySQL_Session ) {
248
- // sessions table should only ever exist only in local database
249
  return;
250
  }
251
 
252
  if ( ! $is_external_database && $class instanceof WSAL_Adapters_MySQL_TmpUser ) {
253
- // exclude the tmp_users table for local database
254
  return;
255
  }
256
 
257
  if ( is_subclass_of( $class, 'WSAL_Adapters_MySQL_ActiveRecord' ) ) {
258
- $class->Install();
259
  }
260
  }
261
 
262
  /**
263
- * Uninstall all DB tables.
264
  */
265
- public function uninstallAll() {
266
- foreach ( WSAL_Utilities_FileSystemUtils::read_files_in_folder( $this->getAdaptersDirectory(), '*.php' ) as $file ) {
267
  $file_path = explode( DIRECTORY_SEPARATOR, $file );
268
  $file_name = $file_path[ count( $file_path ) - 1 ];
269
- $class_name = $this->getAdapterClassName( str_replace( 'Adapter.php', '', $file_name ) );
270
 
271
- $class = new $class_name( $this->getConnection() );
272
  if ( is_subclass_of( $class, 'WSAL_Adapters_MySQL_ActiveRecord' ) ) {
273
- $class->Uninstall();
274
  }
275
  }
276
  }
@@ -282,10 +275,10 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
282
  *
283
  * @return int
284
  */
285
- public function MigrateOccurrenceFromLocalToExternal( $limit ) {
286
  global $wpdb;
287
 
288
- return $this->MigrateOccurrence( $wpdb, $this->getConnection(), $limit );
289
  }
290
 
291
  /**
@@ -293,66 +286,70 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
293
  *
294
  * It also deletes the tables in the source database when there is no more data to migrate.
295
  *
296
- * @param wpdb $source_db
297
- * @param wpdb $target_db
298
- * @param int $limit
299
  *
300
  * @return int Number of occurrence entries migrated.
301
  */
302
- private function MigrateOccurrence( $source_db, $target_db, $limit ) {
303
- // load occurrence data from the source database
304
  $occurrence_adapter_source = new WSAL_Adapters_MySQL_Occurrence( $source_db );
305
- if ( ! $occurrence_adapter_source->IsInstalled() ) {
306
  return 0;
307
  }
308
 
309
- $sql = 'SELECT * FROM ' . $occurrence_adapter_source->GetTable() . ' LIMIT ' . $limit;
310
  $occurrences = $source_db->get_results( $sql, ARRAY_A );
311
 
312
- // no more data to migrate, delete the old tables
313
  if ( empty( $occurrences ) ) {
314
- $this->DeleteAfterMigrate( $occurrence_adapter_source );
315
- $this->DeleteAfterMigrate( new WSAL_Adapters_MySQL_Meta( $source_db ) );
316
 
317
  return 0;
318
  }
319
 
320
  // Insert data to the target database.
321
  $occurrence_adapter_target = new WSAL_Adapters_MySQL_Occurrence( $target_db );
322
- $occurrence_table_name_target = $occurrence_adapter_target->GetTable();
323
 
324
- $occurrence_ids_to_delete = [];
325
  foreach ( $occurrences as $entry ) {
326
 
327
- $target_db->insert( $occurrence_table_name_target, [
328
- 'site_id' => $entry['site_id'],
329
- 'alert_id' => $entry['alert_id'],
330
- 'created_on' => $entry['created_on'],
331
- 'client_ip' => $entry['client_ip'],
332
- 'severity' => $entry['severity'],
333
- 'object' => $entry['object'],
334
- 'event_type' => $entry['event_type'],
335
- 'user_agent' => $entry['user_agent'],
336
- 'user_roles' => $entry['user_roles'],
337
- 'username' => $entry['username'],
338
- 'user_id' => $entry['user_id'],
339
- 'session_id' => $entry['session_id'],
340
- 'post_status' => $entry['post_status'],
341
- 'post_type' => $entry['post_type'],
342
- 'post_id' => $entry['post_id'],
343
- ], [ '%d', '%d', '%f','%s', '%d','%s', '%s', '%s', '%s', '%s', '%d', '%s', '%s', '%s', '%d'] );
 
 
 
 
344
 
345
  $old_entry_id = intval( $entry['id'] );
346
  $new_entry_id = $target_db->insert_id;
347
- $this->MigrateMeta( $source_db, $target_db, $old_entry_id, $new_entry_id );
348
 
349
  array_push( $occurrence_ids_to_delete, $old_entry_id );
350
  }
351
 
352
- // delete migrated events and associated meta data
353
  $meta_adapter_source = new WSAL_Adapters_MySQL_Meta( $source_db );
354
- $source_db->query( 'DELETE FROM ' . $occurrence_adapter_source->GetTable() . ' WHERE id IN (' . implode( ',', $occurrence_ids_to_delete ) . ');' );
355
- $source_db->query( 'DELETE FROM ' . $meta_adapter_source->GetTable() . ' WHERE occurrence_id IN (' . implode( ',', $occurrence_ids_to_delete ) . ');' );
356
 
357
  return count( $occurrence_ids_to_delete );
358
  }
@@ -362,39 +359,39 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
362
  *
363
  * @param object $record - Type of record.
364
  */
365
- private function DeleteAfterMigrate( $record ) {
366
  global $wpdb;
367
- $sql = 'DROP TABLE IF EXISTS ' . $record->GetTable();
368
- $wpdb->query( $sql );
369
  }
370
 
371
  /**
372
  * Migrate Metadata from WP DB to External DB.
373
  *
374
- * @param wpdb $source_db
375
- * @param wpdb $target_db
376
- * @param int $old_occurrence_id
377
- * @param int $new_occurrence_id
378
  *
379
  * @return int Number of metadata migrated.
380
  */
381
- private function MigrateMeta( $source_db, $target_db, $old_occurrence_id, $new_occurrence_id ) {
382
 
383
- // load meta data from the source database
384
  $meta_adapter_source = new WSAL_Adapters_MySQL_Meta( $source_db );
385
- if ( ! $meta_adapter_source->IsInstalled() ) {
386
  return 0;
387
  }
388
 
389
- $query = 'SELECT * FROM ' . $meta_adapter_source->GetTable() . ' WHERE occurrence_id = %d;';
390
  $prepared_query = $source_db->prepare( $query, $old_occurrence_id );
391
  $metadata = $source_db->get_results( $prepared_query, ARRAY_A );
392
 
393
- // insert meta data to target database
394
  if ( ! empty( $metadata ) ) {
395
  $meta_adapter_target = new WSAL_Adapters_MySQL_Meta( $target_db );
396
 
397
- $query = 'INSERT INTO ' . $meta_adapter_target->GetTable() . ' (occurrence_id, name, value) VALUES ';
398
  foreach ( $metadata as $entry ) {
399
  $query .= $target_db->prepare(
400
  '( %d, %s, %s ), ',
@@ -419,9 +416,9 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
419
  *
420
  * @return array
421
  */
422
- public function MigrateOccurrenceFromExternalToLocal( $limit ) {
423
  global $wpdb;
424
- return $this->MigrateOccurrence( $this->getConnection(), $wpdb, $limit );
425
  }
426
 
427
  /**
@@ -433,7 +430,7 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
433
  * @return string
434
  * @since 2.6.3
435
  */
436
- public function encryptString( $plaintext ) {
437
 
438
  $ciphertext = false;
439
  $encrypt_method = 'AES-256-CBC';
@@ -447,7 +444,7 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
447
  $iv = substr( hash( 'sha256', $secret_iv ), 0, 16 );
448
 
449
  $ciphertext = openssl_encrypt( $plaintext, $encrypt_method, $key, 0, $iv );
450
- $ciphertext = base64_encode( $ciphertext );
451
 
452
  return $ciphertext;
453
  }
@@ -459,24 +456,26 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
459
  * @param array $args - Archive Database and limit by count OR by date.
460
  *
461
  * @return array|false|null
 
 
462
  */
463
- public function ArchiveOccurrence( $args ) {
464
- $_wpdb = $this->getConnection();
465
  /** @var wpdbCustom $archive_db */
466
  $archive_db = $args['archive_db'];
467
 
468
  // Load data Occurrences from WP.
469
  $occurrence = new WSAL_Adapters_MySQL_Occurrence( $_wpdb );
470
- if ( ! $occurrence->IsInstalled() ) {
471
  return null;
472
  }
473
  if ( ! empty( $args['by_date'] ) ) {
474
- $sql = 'SELECT * FROM ' . $occurrence->GetTable() . ' WHERE created_on <= ' . $args['by_date'];
475
  }
476
 
477
  if ( ! empty( $args['by_limit'] ) ) {
478
- $sql = 'SELECT occ.* FROM ' . $occurrence->GetTable() . ' occ
479
- LEFT JOIN (SELECT id FROM ' . $occurrence->GetTable() . ' order by created_on DESC limit ' . $args['by_limit'] . ') as ids
480
  on ids.id = occ.id
481
  WHERE ids.id IS NULL';
482
  }
@@ -497,7 +496,7 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
497
 
498
  $occurrence_new = new WSAL_Adapters_MySQL_Occurrence( $archive_db );
499
 
500
- $sql = 'INSERT INTO ' . $occurrence_new->GetTable() . ' ( id, site_id, alert_id, created_on, client_ip, severity, object, event_type, user_agent, user_roles, username, user_id, session_id, post_status, post_type, post_id ) VALUES ';
501
  foreach ( $occurrences as $entry ) {
502
 
503
  $sql .= $archive_db->prepare(
@@ -540,25 +539,25 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
540
  *
541
  * @return array|false|null
542
  */
543
- public function ArchiveMeta( $args ) {
544
- $_wpdb = $this->getConnection();
545
  /** @var wpdbCustom $archive_db */
546
  $archive_db = $args['archive_db'];
547
 
548
  // Load data Meta from WP.
549
  $meta = new WSAL_Adapters_MySQL_Meta( $_wpdb );
550
- if ( ! $meta->IsInstalled() ) {
551
  return null;
552
  }
553
  $s_occurrence_ids = implode( ', ', $args['occurrence_ids'] );
554
- $sql = 'SELECT * FROM ' . $meta->GetTable() . ' WHERE occurrence_id IN (' . $s_occurrence_ids . ')';
555
  $metadata = $_wpdb->get_results( $sql, ARRAY_A );
556
 
557
  // Insert data to Archive DB.
558
  if ( ! empty( $metadata ) ) {
559
  $meta_new = new WSAL_Adapters_MySQL_Meta( $archive_db );
560
 
561
- $sql = 'INSERT INTO ' . $meta_new->GetTable() . ' (occurrence_id, name, value) VALUES ';
562
  foreach ( $metadata as $entry ) {
563
  $sql .= $archive_db->prepare(
564
  '( %d, %s, %s ), ',
@@ -581,17 +580,17 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
581
  *
582
  * @param array $args - Archive Database and occurrences IDs.
583
  */
584
- public function DeleteAfterArchive( $args ) {
585
- $_wpdb = $this->getConnection();
586
 
587
  $s_occurrence_ids = implode( ', ', $args['occurrence_ids'] );
588
 
589
  $occurrence = new WSAL_Adapters_MySQL_Occurrence( $_wpdb );
590
- $sql = 'DELETE FROM ' . $occurrence->GetTable() . ' WHERE id IN (' . $s_occurrence_ids . ')';
591
  $_wpdb->query( $sql );
592
 
593
  $meta = new WSAL_Adapters_MySQL_Meta( $_wpdb );
594
- $sql = 'DELETE FROM ' . $meta->GetTable() . ' WHERE occurrence_id IN (' . $s_occurrence_ids . ')';
595
  $_wpdb->query( $sql );
596
  }
597
 
@@ -602,26 +601,26 @@ class WSAL_Connector_MySQLDB extends WSAL_Connector_AbstractConnector implements
602
  */
603
  public function purge_activity() {
604
  // Get connection.
605
- $wpdb = $this->getConnection();
606
 
607
  // Get occurrence model.
608
  $occ = new WSAL_Adapters_MySQL_Occurrence( $wpdb );
609
- $sql = 'TRUNCATE ' . $occ->GetTable();
610
- $query_occ = $wpdb->query( $sql );
611
 
612
  // Get meta model.
613
  $meta = new WSAL_Adapters_MySQL_Meta( $wpdb );
614
- $sql = 'TRUNCATE ' . $meta->GetTable();
615
- $query_meta = $wpdb->query( $sql );
616
 
617
  // If both queries are successful, then return true.
618
  return $query_occ && $query_meta;
619
  }
620
 
621
  /**
622
- * @inheritDoc
623
  */
624
  public function query( $query ) {
625
- return $this->getConnection()->query( $query );
626
  }
627
  }
26
  *
27
  * @var array
28
  */
29
+ protected $connection_config = null;
30
 
31
  /**
32
  * Method: Constructor.
34
  * @param array $connection_config - Connection config.
35
  */
36
  public function __construct( $connection_config = null ) {
37
+ $this->connection_config = $connection_config;
38
  parent::__construct( 'MySQL' );
39
  }
40
 
45
  * @throws Exception - Connection failed.
46
  */
47
  public function TestConnection() {
48
+ error_reporting( E_ALL ^ ( E_NOTICE | E_WARNING | E_DEPRECATED ) ); // phpcs:ignore
49
+ $connection_config = $this->connection_config;
50
+ $password = $this->decrypt_string( $connection_config['password'] );
51
 
52
  $new_wpdb = new wpdbCustom( $connection_config['user'], $password, $connection_config['db_name'], $connection_config['hostname'], $connection_config['is_ssl'], $connection_config['is_cc'], $connection_config['ssl_ca'], $connection_config['ssl_cert'], $connection_config['ssl_key'] );
53
 
54
  if ( isset( $new_wpdb->error ) && isset( $new_wpdb->dbh ) ) {
55
  throw new Exception( $new_wpdb->dbh->error, $new_wpdb->dbh->errno );
56
  } elseif ( ! isset( $new_wpdb->dbh ) ) {
57
+ $error_code = mysqli_connect_errno(); // phpcs:ignore
58
 
59
  if ( 1045 === $error_code ) {
60
  throw new Exception( __( 'Error establishing a database connection. DB username or password are not valid.' ), $error_code );
61
  } else {
62
+ $error_message = mysqli_connect_error(); // phpcs:ignore
63
  // if we get an error message from mysqli then use it otherwise use a generic message.
64
  if ( $error_message ) {
65
  throw new Exception(
91
  * @return string
92
  * @since 2.6.3
93
  */
94
+ public function decrypt_string( $ciphertext_base64 ) {
95
  $encrypt_method = 'AES-256-CBC';
96
  $secret_key = $this->truncateKey();
97
  $secret_iv = $this->get_openssl_iv();
102
  // iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning.
103
  $iv = substr( hash( 'sha256', $secret_iv ), 0, 16 );
104
 
105
+ return openssl_decrypt( base64_decode( $ciphertext_base64 ), $encrypt_method, $key, 0, $iv ); // phpcs:ignore
106
  }
107
 
108
  /**
140
  }
141
 
142
  /**
143
+ * {@inheritDoc}
144
  */
145
+ public function close_connection() {
146
+ $current_wpdb = $this->get_connection();
147
 
148
  return $current_wpdb->close();
149
  }
150
 
151
  /**
152
+ * {@inheritDoc}
 
 
153
  */
154
+ public function get_connection() {
155
  if ( ! empty( $this->connection ) ) {
156
  return $this->connection;
157
  } else {
158
+ $this->connection = $this->create_connection();
159
 
160
  return $this->connection;
161
  }
166
  *
167
  * @return wpdb Instance of WPDB.
168
  */
169
+ private function create_connection() {
170
+ if ( ! empty( $this->connection_config ) ) {
171
+ $connection_config = $this->connection_config;
172
+ $password = $this->decrypt_string( $connection_config['password'] );
173
  $new_wpdb = new wpdbCustom( $connection_config['user'], $password, $connection_config['db_name'], $connection_config['hostname'], $connection_config['is_ssl'], $connection_config['is_cc'], $connection_config['ssl_ca'], $connection_config['ssl_cert'], $connection_config['ssl_key'] );
174
  if ( array_key_exists( 'baseprefix', $connection_config ) ) {
175
  $new_wpdb->set_prefix( $connection_config['baseprefix'] );
184
  }
185
 
186
  /**
187
+ * {@inheritDoc}
188
  */
189
+ public function get_adapter( $class_name ) {
190
+ $obj_name = $this->get_adapter_class_name( $class_name );
191
 
192
+ return new $obj_name( $this->get_connection() );
193
  }
194
 
195
  /**
199
  *
200
  * @return string
201
  */
202
+ protected function get_adapter_class_name( $class_name ) {
203
  return 'WSAL_Adapters_MySQL_' . $class_name;
204
  }
205
 
206
  /**
207
+ * {@inheritDoc}
208
  */
209
+ public function is_installed() {
210
+ $wpdb = $this->get_connection();
211
  $table = $wpdb->base_prefix . 'wsal_occurrences';
212
+ $db_result = $wpdb->query( "SELECT COUNT(1) FROM {$table};" ); // phpcs:ignore
213
 
214
  return 1 === $db_result;
215
  }
216
 
217
  /**
218
+ * {@inheritDoc}
 
 
219
  */
220
+ public function install_all( $is_external_database = false ) {
221
+ $adapter_list = WSAL_Utilities_FileSystemUtils::read_files_in_folder( $this->get_adapters_directory(), '*.php' );
222
  $adapter_list = apply_filters( 'wsal_install_adapters_list', $adapter_list );
223
  foreach ( $adapter_list as $file ) {
224
  $file_path = explode( DIRECTORY_SEPARATOR, $file );
225
  $file_name = $file_path[ count( $file_path ) - 1 ];
226
+ $class_name = $this->get_adapter_class_name( str_replace( 'Adapter.php', '', $file_name ) );
227
+ $this->install_single( $class_name, $is_external_database );
228
  }
229
  }
230
 
231
  /**
232
+ * {@inheritDoc}
 
 
 
233
  */
234
+ public function install_single( $class_name, $is_external_database = false ) {
235
  if ( ! class_exists( $class_name ) ) {
236
  return;
237
  }
238
 
239
+ $class = new $class_name( $this->get_connection() );
240
  if ( $is_external_database && $class instanceof WSAL_Adapters_MySQL_Session ) {
241
+ // Sessions table should only ever exist only in local database.
242
  return;
243
  }
244
 
245
  if ( ! $is_external_database && $class instanceof WSAL_Adapters_MySQL_TmpUser ) {
246
+ // Exclude the tmp_users table for local database.
247
  return;
248
  }
249
 
250
  if ( is_subclass_of( $class, 'WSAL_Adapters_MySQL_ActiveRecord' ) ) {
251
+ $class->install();
252
  }
253
  }
254
 
255
  /**
256
+ * {@inheritDoc}
257
  */
258
+ public function uninstall_all() {
259
+ foreach ( WSAL_Utilities_FileSystemUtils::read_files_in_folder( $this->get_adapters_directory(), '*.php' ) as $file ) {
260
  $file_path = explode( DIRECTORY_SEPARATOR, $file );
261
  $file_name = $file_path[ count( $file_path ) - 1 ];
262
+ $class_name = $this->get_adapter_class_name( str_replace( 'Adapter.php', '', $file_name ) );
263
 
264
+ $class = new $class_name( $this->get_connection() );
265
  if ( is_subclass_of( $class, 'WSAL_Adapters_MySQL_ActiveRecord' ) ) {
266
+ $class->uninstall();
267
  }
268
  }
269
  }
275
  *
276
  * @return int
277
  */
278
+ public function migrate_occurrence_from_local_to_external( $limit ) {
279
  global $wpdb;
280
 
281
+ return $this->migrate_occurrence( $wpdb, $this->get_connection(), $limit );
282
  }
283
 
284
  /**
286
  *
287
  * It also deletes the tables in the source database when there is no more data to migrate.
288
  *
289
+ * @param wpdb $source_db Source database.
290
+ * @param wpdb $target_db Target database.
291
+ * @param int $limit Number of entries to migrate.
292
  *
293
  * @return int Number of occurrence entries migrated.
294
  */
295
+ private function migrate_occurrence( $source_db, $target_db, $limit ) {
296
+ // Load occurrence data from the source database.
297
  $occurrence_adapter_source = new WSAL_Adapters_MySQL_Occurrence( $source_db );
298
+ if ( ! $occurrence_adapter_source->is_installed() ) {
299
  return 0;
300
  }
301
 
302
+ $sql = 'SELECT * FROM ' . $occurrence_adapter_source->get_table() . ' LIMIT ' . $limit;
303
  $occurrences = $source_db->get_results( $sql, ARRAY_A );
304
 
305
+ // No more data to migrate, delete the old tables.
306
  if ( empty( $occurrences ) ) {
307
+ $this->delete_after_migrate( $occurrence_adapter_source );
308
+ $this->delete_after_migrate( new WSAL_Adapters_MySQL_Meta( $source_db ) );
309
 
310
  return 0;
311
  }
312
 
313
  // Insert data to the target database.
314
  $occurrence_adapter_target = new WSAL_Adapters_MySQL_Occurrence( $target_db );
315
+ $occurrence_table_name_target = $occurrence_adapter_target->get_table();
316
 
317
+ $occurrence_ids_to_delete = array();
318
  foreach ( $occurrences as $entry ) {
319
 
320
+ $target_db->insert(
321
+ $occurrence_table_name_target,
322
+ array(
323
+ 'site_id' => $entry['site_id'],
324
+ 'alert_id' => $entry['alert_id'],
325
+ 'created_on' => $entry['created_on'],
326
+ 'client_ip' => $entry['client_ip'],
327
+ 'severity' => $entry['severity'],
328
+ 'object' => $entry['object'],
329
+ 'event_type' => $entry['event_type'],
330
+ 'user_agent' => $entry['user_agent'],
331
+ 'user_roles' => $entry['user_roles'],
332
+ 'username' => $entry['username'],
333
+ 'user_id' => $entry['user_id'],
334
+ 'session_id' => $entry['session_id'],
335
+ 'post_status' => $entry['post_status'],
336
+ 'post_type' => $entry['post_type'],
337
+ 'post_id' => $entry['post_id'],
338
+ ),
339
+ array( '%d', '%d', '%f', '%s', '%d', '%s', '%s', '%s', '%s', '%s', '%d', '%s', '%s', '%s', '%d' )
340
+ );
341
 
342
  $old_entry_id = intval( $entry['id'] );
343
  $new_entry_id = $target_db->insert_id;
344
+ $this->migrate_meta( $source_db, $target_db, $old_entry_id, $new_entry_id );
345
 
346
  array_push( $occurrence_ids_to_delete, $old_entry_id );
347
  }
348
 
349
+ // Delete migrated events and associated meta data.
350
  $meta_adapter_source = new WSAL_Adapters_MySQL_Meta( $source_db );
351
+ $source_db->query( 'DELETE FROM ' . $occurrence_adapter_source->get_table() . ' WHERE id IN (' . implode( ',', $occurrence_ids_to_delete ) . ');' );
352
+ $source_db->query( 'DELETE FROM ' . $meta_adapter_source->get_table() . ' WHERE occurrence_id IN (' . implode( ',', $occurrence_ids_to_delete ) . ');' );
353
 
354
  return count( $occurrence_ids_to_delete );
355
  }
359
  *
360
  * @param object $record - Type of record.
361
  */
362
+ private function delete_after_migrate( $record ) {
363
  global $wpdb;
364
+ $sql = 'DROP TABLE IF EXISTS ' . $record->get_table();
365
+ $wpdb->query( $sql ); // phpcs:ignore
366
  }
367
 
368
  /**
369
  * Migrate Metadata from WP DB to External DB.
370
  *
371
+ * @param wpdb $source_db Source database.
372
+ * @param wpdb $target_db Target database.
373
+ * @param int $old_occurrence_id Old occurrence ID.
374
+ * @param int $new_occurrence_id New occurrence ID.
375
  *
376
  * @return int Number of metadata migrated.
377
  */
378
+ private function migrate_meta( $source_db, $target_db, $old_occurrence_id, $new_occurrence_id ) {
379
 
380
+ // Load meta data from the source database.
381
  $meta_adapter_source = new WSAL_Adapters_MySQL_Meta( $source_db );
382
+ if ( ! $meta_adapter_source->is_installed() ) {
383
  return 0;
384
  }
385
 
386
+ $query = 'SELECT * FROM ' . $meta_adapter_source->get_table() . ' WHERE occurrence_id = %d;';
387
  $prepared_query = $source_db->prepare( $query, $old_occurrence_id );
388
  $metadata = $source_db->get_results( $prepared_query, ARRAY_A );
389
 
390
+ // Insert meta data to target database.
391
  if ( ! empty( $metadata ) ) {
392
  $meta_adapter_target = new WSAL_Adapters_MySQL_Meta( $target_db );
393
 
394
+ $query = 'INSERT INTO ' . $meta_adapter_target->get_table() . ' (occurrence_id, name, value) VALUES ';
395
  foreach ( $metadata as $entry ) {
396
  $query .= $target_db->prepare(
397
  '( %d, %s, %s ), ',
416
  *
417
  * @return array
418
  */
419
+ public function migrate_occurrence_from_external_to_local( $limit ) {
420
  global $wpdb;
421
+ return $this->migrate_occurrence( $this->get_connection(), $wpdb, $limit );
422
  }
423
 
424
  /**
430
  * @return string
431
  * @since 2.6.3
432
  */
433
+ public function encrypt_string( $plaintext ) {
434
 
435
  $ciphertext = false;
436
  $encrypt_method = 'AES-256-CBC';
444
  $iv = substr( hash( 'sha256', $secret_iv ), 0, 16 );
445
 
446
  $ciphertext = openssl_encrypt( $plaintext, $encrypt_method, $key, 0, $iv );
447
+ $ciphertext = base64_encode( $ciphertext ); // phpcs:ignore
448
 
449
  return $ciphertext;
450
  }
456
  * @param array $args - Archive Database and limit by count OR by date.
457
  *
458
  * @return array|false|null
459
+ *
460
+ * @phpcs:disable Generic.Commenting.DocComment.MissingShort
461
  */
462
+ public function archive_occurrence( $args ) {
463
+ $_wpdb = $this->get_connection();
464
  /** @var wpdbCustom $archive_db */
465
  $archive_db = $args['archive_db'];
466
 
467
  // Load data Occurrences from WP.
468
  $occurrence = new WSAL_Adapters_MySQL_Occurrence( $_wpdb );
469
+ if ( ! $occurrence->is_installed() ) {
470
  return null;
471
  }
472
  if ( ! empty( $args['by_date'] ) ) {
473
+ $sql = 'SELECT * FROM ' . $occurrence->get_table() . ' WHERE created_on <= ' . $args['by_date'];
474
  }
475
 
476
  if ( ! empty( $args['by_limit'] ) ) {
477
+ $sql = 'SELECT occ.* FROM ' . $occurrence->get_table() . ' occ
478
+ LEFT JOIN (SELECT id FROM ' . $occurrence->get_table() . ' order by created_on DESC limit ' . $args['by_limit'] . ') as ids
479
  on ids.id = occ.id
480
  WHERE ids.id IS NULL';
481
  }
496
 
497
  $occurrence_new = new WSAL_Adapters_MySQL_Occurrence( $archive_db );
498
 
499
+ $sql = 'INSERT INTO ' . $occurrence_new->get_table() . ' ( id, site_id, alert_id, created_on, client_ip, severity, object, event_type, user_agent, user_roles, username, user_id, session_id, post_status, post_type, post_id ) VALUES ';
500
  foreach ( $occurrences as $entry ) {
501
 
502
  $sql .= $archive_db->prepare(
539
  *
540
  * @return array|false|null
541
  */
542
+ public function archive_meta( $args ) {
543
+ $_wpdb = $this->get_connection();
544
  /** @var wpdbCustom $archive_db */
545
  $archive_db = $args['archive_db'];
546
 
547
  // Load data Meta from WP.
548
  $meta = new WSAL_Adapters_MySQL_Meta( $_wpdb );
549
+ if ( ! $meta->is_installed() ) {
550
  return null;
551
  }
552
  $s_occurrence_ids = implode( ', ', $args['occurrence_ids'] );
553
+ $sql = 'SELECT * FROM ' . $meta->get_table() . ' WHERE occurrence_id IN (' . $s_occurrence_ids . ')';
554
  $metadata = $_wpdb->get_results( $sql, ARRAY_A );
555
 
556
  // Insert data to Archive DB.
557
  if ( ! empty( $metadata ) ) {
558
  $meta_new = new WSAL_Adapters_MySQL_Meta( $archive_db );
559
 
560
+ $sql = 'INSERT INTO ' . $meta_new->get_table() . ' (occurrence_id, name, value) VALUES ';
561
  foreach ( $metadata as $entry ) {
562
  $sql .= $archive_db->prepare(
563
  '( %d, %s, %s ), ',
580
  *
581
  * @param array $args - Archive Database and occurrences IDs.
582
  */
583
+ public function delete_after_archive( $args ) {
584
+ $_wpdb = $this->get_connection();
585
 
586
  $s_occurrence_ids = implode( ', ', $args['occurrence_ids'] );
587
 
588
  $occurrence = new WSAL_Adapters_MySQL_Occurrence( $_wpdb );
589
+ $sql = 'DELETE FROM ' . $occurrence->get_table() . ' WHERE id IN (' . $s_occurrence_ids . ')';
590
  $_wpdb->query( $sql );
591
 
592
  $meta = new WSAL_Adapters_MySQL_Meta( $_wpdb );
593
+ $sql = 'DELETE FROM ' . $meta->get_table() . ' WHERE occurrence_id IN (' . $s_occurrence_ids . ')';
594
  $_wpdb->query( $sql );
595
  }
596
 
601
  */
602
  public function purge_activity() {
603
  // Get connection.
604
+ $wpdb = $this->get_connection();
605
 
606
  // Get occurrence model.
607
  $occ = new WSAL_Adapters_MySQL_Occurrence( $wpdb );
608
+ $sql = 'TRUNCATE ' . $occ->get_table();
609
+ $query_occ = $wpdb->query( $sql ); // phpcs:ignore
610
 
611
  // Get meta model.
612
  $meta = new WSAL_Adapters_MySQL_Meta( $wpdb );
613
+ $sql = 'TRUNCATE ' . $meta->get_table();
614
+ $query_meta = $wpdb->query( $sql ); // phpcs:ignore
615
 
616
  // If both queries are successful, then return true.
617
  return $query_occ && $query_meta;
618
  }
619
 
620
  /**
621
+ * {@inheritDoc}
622
  */
623
  public function query( $query ) {
624
+ return $this->get_connection()->query( $query );
625
  }
626
  }
classes/Connector/wp-db-custom.php CHANGED
@@ -18,6 +18,8 @@ if ( ! defined( 'ABSPATH' ) ) {
18
  * It uses wpdb WordPress DB Class.
19
  *
20
  * @package wsal
 
 
21
  */
22
  class wpdbCustom extends wpdb {
23
 
@@ -87,17 +89,17 @@ class wpdbCustom extends wpdb {
87
  * If $allow_bail is false, the lack of database connection will need
88
  * to be handled manually.
89
  *
90
- * @since 3.0.0
91
- * @since 3.9.0 $allow_bail parameter added.
92
- *
93
  * @param bool $allow_bail Optional. Allows the function to bail. Default true.
 
94
  * @return bool True with a successful connection, false on failure.
 
 
95
  */
96
  public function db_connect( $allow_bail = true ) {
97
  $this->is_mysql = true;
98
- $client_flags = defined( 'MYSQL_CLIENT_FLAGS' ) ? MYSQL_CLIENT_FLAGS : 0;
99
  if ( $this->use_mysqli ) {
100
- $this->dbh = mysqli_init();
101
 
102
  // mysqli_real_connect doesn't support the host param including a port or socket
103
  // like mysql_connect does. This duplicates how mysql_connect detects a port and/or socket file.
@@ -138,7 +140,7 @@ class wpdbCustom extends wpdb {
138
  $ssl_opts_set = false;
139
  }
140
  if ( $ssl_opts_set ) {
141
- mysqli_ssl_set(
142
  $this->dbh,
143
  $ssl_opts['KEY'],
144
  $ssl_opts['CERT'],
@@ -149,9 +151,9 @@ class wpdbCustom extends wpdb {
149
  }
150
 
151
  if ( WP_DEBUG ) {
152
- mysqli_real_connect( $this->dbh, $host, $this->dbuser, $this->dbpassword, null, $port, $socket, $client_flags );
153
  } else {
154
- @mysqli_real_connect( $this->dbh, $host, $this->dbuser, $this->dbpassword, null, $port, $socket, $client_flags );
155
  }
156
 
157
  if ( $this->dbh->connect_errno ) {
@@ -166,8 +168,8 @@ class wpdbCustom extends wpdb {
166
  $attempt_fallback = true;
167
 
168
  if ( $this->has_connected
169
- || ( defined( 'WP_USE_EXT_MYSQL' ) && ! WP_USE_EXT_MYSQL )
170
- || ( ! function_exists( 'mysql_connect' ) ) ) {
171
  $attempt_fallback = false;
172
  }
173
 
@@ -207,7 +209,7 @@ class wpdbCustom extends wpdb {
207
  *
208
  * @since 0.71
209
  *
210
- * @param string $db MySQL database name
211
  * @param resource|null $dbh Optional link identifier.
212
  */
213
  public function select( $db, $dbh = null ) {
@@ -216,13 +218,13 @@ class wpdbCustom extends wpdb {
216
  }
217
 
218
  if ( $this->use_mysqli ) {
219
- $success = mysqli_select_db( $dbh, $db );
220
  } else {
221
- $success = mysql_select_db( $db, $dbh );
222
  }
223
 
224
  if ( ! $success ) {
225
- $this->ready = false;
226
  $this->db_select_error = true;
227
  }
228
  }
18
  * It uses wpdb WordPress DB Class.
19
  *
20
  * @package wsal
21
+ *
22
+ * @phpcs:disable PEAR.NamingConventions.ValidClassName.StartWithCapital
23
  */
24
  class wpdbCustom extends wpdb {
25
 
89
  * If $allow_bail is false, the lack of database connection will need
90
  * to be handled manually.
91
  *
 
 
 
92
  * @param bool $allow_bail Optional. Allows the function to bail. Default true.
93
+ *
94
  * @return bool True with a successful connection, false on failure.
95
+ * @since 3.0.0
96
+ * @since 3.9.0 $allow_bail parameter added.
97
  */
98
  public function db_connect( $allow_bail = true ) {
99
  $this->is_mysql = true;
100
+ $client_flags = defined( 'MYSQL_CLIENT_FLAGS' ) ? MYSQL_CLIENT_FLAGS : 0;
101
  if ( $this->use_mysqli ) {
102
+ $this->dbh = mysqli_init(); // phpcs:ignore
103
 
104
  // mysqli_real_connect doesn't support the host param including a port or socket
105
  // like mysql_connect does. This duplicates how mysql_connect detects a port and/or socket file.
140
  $ssl_opts_set = false;
141
  }
142
  if ( $ssl_opts_set ) {
143
+ mysqli_ssl_set( // phpcs:ignore
144
  $this->dbh,
145
  $ssl_opts['KEY'],
146
  $ssl_opts['CERT'],
151
  }
152
 
153
  if ( WP_DEBUG ) {
154
+ mysqli_real_connect( $this->dbh, $host, $this->dbuser, $this->dbpassword, null, $port, $socket, $client_flags ); // phpcs:ignore
155
  } else {
156
+ @mysqli_real_connect( $this->dbh, $host, $this->dbuser, $this->dbpassword, null, $port, $socket, $client_flags ); // phpcs:ignore
157
  }
158
 
159
  if ( $this->dbh->connect_errno ) {
168
  $attempt_fallback = true;
169
 
170
  if ( $this->has_connected
171
+ || ( defined( 'WP_USE_EXT_MYSQL' ) && ! WP_USE_EXT_MYSQL )
172
+ || ( ! function_exists( 'mysql_connect' ) ) ) {
173
  $attempt_fallback = false;
174
  }
175
 
209
  *
210
  * @since 0.71
211
  *
212
+ * @param string $db MySQL database name.
213
  * @param resource|null $dbh Optional link identifier.
214
  */
215
  public function select( $db, $dbh = null ) {
218
  }
219
 
220
  if ( $this->use_mysqli ) {
221
+ $success = mysqli_select_db( $dbh, $db ); // phpcs:ignore
222
  } else {
223
+ $success = mysql_select_db( $db, $dbh ); // phpcs:ignore
224
  }
225
 
226
  if ( ! $success ) {
227
+ $this->ready = false;
228
  $this->db_select_error = true;
229
  }
230
  }
classes/ConstantManager.php CHANGED
@@ -28,7 +28,7 @@ class WSAL_ConstantManager {
28
  *
29
  * @var array
30
  */
31
- protected $_constants = array();
32
 
33
  /**
34
  * Constants Cache.
@@ -43,8 +43,8 @@ class WSAL_ConstantManager {
43
  * @param string $name - Constant name.
44
  * @param string $description - Constant description.
45
  */
46
- public function UseConstant( $name, $description = '' ) {
47
- $this->_constants[] = (object) array(
48
  'name' => $name,
49
  'value' => constant( $name ),
50
  'description' => $description,
@@ -60,7 +60,7 @@ class WSAL_ConstantManager {
60
  *
61
  * @throws Exception - Error if a constant is already defined.
62
  */
63
- public function AddConstant( $name, $value, $description = '' ) {
64
  // Check for constant conflict and define new one if required.
65
  if ( defined( $name ) && constant( $name ) !== $value ) {
66
  throw new Exception( 'Constant already defined with a different value.' );
@@ -68,17 +68,19 @@ class WSAL_ConstantManager {
68
  define( $name, $value );
69
  }
70
  // Add constant to da list.
71
- $this->UseConstant( $name, $description );
72
  }
73
 
74
  /**
75
  * Add multiple constants in one go.
76
  *
77
  * @param array $items - Array of arrays with name, value, description pairs.
 
 
78
  */
79
- public function AddConstants( $items ) {
80
  foreach ( $items as $item ) {
81
- $this->AddConstant( $item['name'], $item['value'], $item['description'] );
82
  }
83
  }
84
 
@@ -87,9 +89,9 @@ class WSAL_ConstantManager {
87
  *
88
  * @param array $items - Array of arrays with name, description pairs.
89
  */
90
- public function UseConstants( $items ) {
91
  foreach ( $items as $item ) {
92
- $this->UseConstant( $item['name'], $item['description'] );
93
  }
94
  }
95
 
@@ -104,11 +106,11 @@ class WSAL_ConstantManager {
104
  *
105
  * @return mixed Either constant details (props: name, value, description) or $default if not found.
106
  */
107
- public function GetConstantBy( $what, $value, $default = null ) {
108
  // Make sure we do have some constants.
109
- if ( ! empty( $this->_constants ) ) {
110
  // Make sure that constants do have a $what property.
111
- if ( ! isset( $this->_constants[0]->$what ) ) {
112
  throw new Exception( 'Unexpected detail type "' . $what . '".' );
113
  }
114
 
@@ -119,14 +121,14 @@ class WSAL_ConstantManager {
119
 
120
  $possible_matches = array();
121
  // Return constant match the property value.
122
- foreach ( $this->_constants as $constant ) {
123
- if ( $value == $constant->$what ) {
124
  $this->constants_cache[ $value ] = $constant;
125
  $possible_matches[] = $constant;
126
  }
127
  }
128
 
129
- // If we got matches then get the last one in the array,
130
  if ( ! empty( $possible_matches ) ) {
131
  return end( $possible_matches );
132
  }
@@ -138,7 +140,10 @@ class WSAL_ConstantManager {
138
  * Get constant object for displaying.
139
  *
140
  * @param integer $code - Value of the constant.
 
141
  * @return stdClass
 
 
142
  */
143
  public function get_constant_to_display( $code ) {
144
  $const = (object) array(
@@ -147,11 +152,11 @@ class WSAL_ConstantManager {
147
  'description' => __( 'Unknown error code.', 'wp-security-audit-log' ),
148
  );
149
 
150
- $const = $this->GetConstantBy( 'value', $code, $const );
151
 
152
- // CSS property was added in 4.3.0 as part of severity levels refactoring to be able to print language
153
- // independent CSS class not based on the constant value
154
- if ( ! property_exists($const, 'css')) {
155
  $const->css = strtolower( $const->name );
156
  }
157
 
28
  *
29
  * @var array
30
  */
31
+ protected $constants = array();
32
 
33
  /**
34
  * Constants Cache.
43
  * @param string $name - Constant name.
44
  * @param string $description - Constant description.
45
  */
46
+ public function use_constant( $name, $description = '' ) {
47
+ $this->constants[] = (object) array(
48
  'name' => $name,
49
  'value' => constant( $name ),
50
  'description' => $description,
60
  *
61
  * @throws Exception - Error if a constant is already defined.
62
  */
63
+ public function add_constant( $name, $value, $description = '' ) {
64
  // Check for constant conflict and define new one if required.
65
  if ( defined( $name ) && constant( $name ) !== $value ) {
66
  throw new Exception( 'Constant already defined with a different value.' );
68
  define( $name, $value );
69
  }
70
  // Add constant to da list.
71
+ $this->use_constant( $name, $description );
72
  }
73
 
74
  /**
75
  * Add multiple constants in one go.
76
  *
77
  * @param array $items - Array of arrays with name, value, description pairs.
78
+ *
79
+ * @throws Exception Error if a constant is already defined.
80
  */
81
+ public function add_constants( $items ) {
82
  foreach ( $items as $item ) {
83
+ $this->add_constant( $item['name'], $item['value'], $item['description'] );
84
  }
85
  }
86
 
89
  *
90
  * @param array $items - Array of arrays with name, description pairs.
91
  */
92
+ public function use_constants( $items ) {
93
  foreach ( $items as $item ) {
94
+ $this->use_constant( $item['name'], $item['description'] );
95
  }
96
  }
97
 
106
  *
107
  * @return mixed Either constant details (props: name, value, description) or $default if not found.
108
  */
109
+ public function get_constant_by( $what, $value, $default = null ) {
110
  // Make sure we do have some constants.
111
+ if ( ! empty( $this->constants ) ) {
112
  // Make sure that constants do have a $what property.
113
+ if ( ! isset( $this->constants[0]->$what ) ) {
114
  throw new Exception( 'Unexpected detail type "' . $what . '".' );
115
  }
116
 
121
 
122
  $possible_matches = array();
123
  // Return constant match the property value.
124
+ foreach ( $this->constants as $constant ) {
125
+ if ( $value == $constant->$what ) { // phpcs:ignore
126
  $this->constants_cache[ $value ] = $constant;
127
  $possible_matches[] = $constant;
128
  }
129
  }
130
 
131
+ // If we got matches then get the last one in the array.
132
  if ( ! empty( $possible_matches ) ) {
133
  return end( $possible_matches );
134
  }
140
  * Get constant object for displaying.
141
  *
142
  * @param integer $code - Value of the constant.
143
+ *
144
  * @return stdClass
145
+ *
146
+ * @throws Exception Error if a constant is already defined.
147
  */
148
  public function get_constant_to_display( $code ) {
149
  $const = (object) array(
152
  'description' => __( 'Unknown error code.', 'wp-security-audit-log' ),
153
  );
154
 
155
+ $const = $this->get_constant_by( 'value', $code, $const );
156
 
157
+ // CSS property was added in 4.3.0 as part of severity levels refactoring to be able to print language
158
+ // independent CSS class not based on the constant value.
159
+ if ( ! property_exists( $const, 'css' ) ) {
160
  $const->css = strtolower( $const->name );
161
  }
162
 
classes/ExtensionPlaceholderView.php CHANGED
@@ -1,64 +1,88 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  /**
4
  * Abstract class used for the plugin extension placeholder views/admin pages.
5
  *
6
- * @see Views/*.php
7
- * @package wsal
8
- * @since 4.1.5.2
 
9
  */
10
  abstract class WSAL_ExtensionPlaceholderView extends WSAL_AbstractView {
11
 
 
 
 
12
  public function is_title_visible() {
13
  return false;
14
  }
15
 
16
- public function GetIcon() {
 
 
 
17
  return 'dashicons-external';
18
  }
19
 
20
- public function Header() {
 
 
 
21
  // Extension Page CSS.
22
- $extensionsFile = '/css/extensions.css';
23
  wp_enqueue_style(
24
  'extensions',
25
- $this->_plugin->GetBaseUrl() . $extensionsFile,
26
  array(),
27
- filemtime( $this->_plugin->GetBaseDir() . $extensionsFile )
28
  );
29
 
30
  // Simple lightbox CSS.
31
- $simpleLightboxFile = '/css/dist/simple-lightbox.min.css';
32
  wp_enqueue_style(
33
  'wsal-simple-lightbox-css',
34
- $this->_plugin->GetBaseUrl() . $simpleLightboxFile,
35
  array(),
36
- filemtime( $this->_plugin->GetBaseDir() . $simpleLightboxFile )
37
  );
38
  }
39
 
40
- public function Footer() {
 
 
 
41
  // jQuery.
42
  wp_enqueue_script( 'jquery' );
43
 
44
  // Simple lightbox JS.
45
- $simpleLightboxFile = '/js/dist/simple-lightbox.jquery.min.js';
46
  wp_register_script(
47
  'wsal-simple-lightbox-js',
48
- $this->_plugin->GetBaseUrl() . $simpleLightboxFile,
49
  array( 'jquery' ),
50
- filemtime( $this->_plugin->GetBaseDir() . $simpleLightboxFile ),
51
  false
52
  );
53
  wp_enqueue_script( 'wsal-simple-lightbox-js' );
54
 
55
  // Extensions JS.
56
- $extensionsFile = '/js/extensions.js';
57
  wp_register_script(
58
  'wsal-extensions-js',
59
- $this->_plugin->GetBaseUrl() . $extensionsFile,
60
  array( 'wsal-simple-lightbox-js' ),
61
- filemtime( $this->_plugin->GetBaseDir() . $extensionsFile ),
62
  false
63
  );
64
  wp_enqueue_script( 'wsal-extensions-js' );
1
  <?php
2
+ /**
3
+ * Abstract extension placeholder view class file.
4
+ *
5
+ * @package wsal
6
+ * @subpackage views
7
+ */
8
+
9
+ // Exit if accessed directly.
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
 
14
  /**
15
  * Abstract class used for the plugin extension placeholder views/admin pages.
16
  *
17
+ * @see Views/*.php
18
+ * @package wsal
19
+ * @subpackage views
20
+ * @since 4.1.5.2
21
  */
22
  abstract class WSAL_ExtensionPlaceholderView extends WSAL_AbstractView {
23
 
24
+ /**
25
+ * {@inheritDoc}
26
+ */
27
  public function is_title_visible() {
28
  return false;
29
  }
30
 
31
+ /**
32
+ * {@inheritDoc}
33
+ */
34
+ public function get_icon() {
35
  return 'dashicons-external';
36
  }
37
 
38
+ /**
39
+ * {@inheritDoc}
40
+ */
41
+ public function header() {
42
  // Extension Page CSS.
43
+ $extensions_file = '/css/extensions.css';
44
  wp_enqueue_style(
45
  'extensions',
46
+ $this->plugin->get_base_url() . $extensions_file,
47
  array(),
48
+ filemtime( $this->plugin->get_base_dir() . $extensions_file )
49
  );
50
 
51
  // Simple lightbox CSS.
52
+ $simple_lightbox_file = '/css/dist/simple-lightbox.min.css';
53
  wp_enqueue_style(
54
  'wsal-simple-lightbox-css',
55
+ $this->plugin->get_base_url() . $simple_lightbox_file,
56
  array(),
57
+ filemtime( $this->plugin->get_base_dir() . $simple_lightbox_file )
58
  );
59
  }
60
 
61
+ /**
62
+ * {@inheritDoc}
63
+ */
64
+ public function footer() {
65
  // jQuery.
66
  wp_enqueue_script( 'jquery' );
67
 
68
  // Simple lightbox JS.
69
+ $simple_lightbox_file = '/js/dist/simple-lightbox.jquery.min.js';
70
  wp_register_script(
71
  'wsal-simple-lightbox-js',
72
+ $this->plugin->get_base_url() . $simple_lightbox_file,
73
  array( 'jquery' ),
74
+ filemtime( $this->plugin->get_base_dir() . $simple_lightbox_file ),
75
  false
76
  );
77
  wp_enqueue_script( 'wsal-simple-lightbox-js' );
78
 
79
  // Extensions JS.
80
+ $extensions_file = '/js/extensions.js';
81
  wp_register_script(
82
  'wsal-extensions-js',
83
+ $this->plugin->get_base_url() . $extensions_file,
84
  array( 'wsal-simple-lightbox-js' ),
85
+ filemtime( $this->plugin->get_base_dir() . $extensions_file ),
86
  false
87
  );
88
  wp_enqueue_script( 'wsal-extensions-js' );
classes/Helpers/DataHelper.php CHANGED
@@ -25,8 +25,8 @@ class WSAL_Helpers_DataHelper {
25
  * @param mixed $data The data to encode.
26
  * @return string JSON string.
27
  */
28
- public static function JsonEncode( $data ) {
29
- return @json_encode( $data );
30
  }
31
 
32
  /**
@@ -35,7 +35,7 @@ class WSAL_Helpers_DataHelper {
35
  * @param string $data - The JSON string to decode.
36
  * @return mixed Decoded data.
37
  */
38
- public static function JsonDecode( $data ) {
39
- return @json_decode( $data );
40
  }
41
  }
25
  * @param mixed $data The data to encode.
26
  * @return string JSON string.
27
  */
28
+ public static function json_encode( $data ) {
29
+ return @json_encode( $data ); // phpcs:ignore
30
  }
31
 
32
  /**
35
  * @param string $data - The JSON string to decode.
36
  * @return mixed Decoded data.
37
  */
38
+ public static function json_decode( $data ) {
39
+ return @json_decode( $data ); // phpcs:ignore
40
  }
41
  }
classes/Helpers/Options.php CHANGED
@@ -20,26 +20,17 @@ namespace WSAL\Helpers;
20
  */
21
  class Options {
22
 
23
- /**
24
- * Instance of the main plugin class.
25
- *
26
- * @since 4.0.2
27
- * @var WpSecurityAuditLog
28
- */
29
- private $plugin;
30
-
31
  /**
32
  * Prefix used when setting/getting options.
33
  *
34
  * @since 4.0.2
35
- * @var @var string
36
  */
37
  public $prefix;
38
 
39
  /**
40
  * Sets up this class with the main plugin instance and a prefix.
41
  *
42
- * @method __construct
43
  * @param string $prefix A prefix to use when setting/getting.
44
  *
45
  * @since 4.0.2
@@ -76,12 +67,12 @@ class Options {
76
  }
77
 
78
  $actual_option_name = $option_name;
79
- if (!preg_match( '/\A' .preg_quote($this->prefix) . '/', $option_name)) {
80
- // remove prefix duplicate if present
81
  $actual_option_name = $this->prefix . $option_name;
82
  }
83
 
84
- return self::_get_option_value( $actual_option_name, $default);
85
  }
86
 
87
  /**
@@ -101,12 +92,12 @@ class Options {
101
  }
102
 
103
  $actual_option_name = $option_name;
104
- if ( ! preg_match( '/\A' . preg_quote( $this->prefix ) . '/', $option_name ) ) {
105
- // prepend prefix if not already present
106
  $actual_option_name = $this->prefix . $option_name;
107
  }
108
 
109
- return self::_set_option_value( $actual_option_name, $value, $autoload );
110
  }
111
 
112
  /**
@@ -120,19 +111,19 @@ class Options {
120
  */
121
  public function delete_option( $option_name = '' ) {
122
 
123
- if (is_multisite()) {
124
- switch_to_blog(get_main_network_id());
125
  }
126
 
127
  $actual_option_name = $option_name;
128
- if ( ! preg_match( '/\A' . preg_quote( $this->prefix ) . '/', $option_name ) ) {
129
- // prepend prefix if not already present
130
  $actual_option_name = $this->prefix . $option_name;
131
  }
132
 
133
  $result = \delete_option( $actual_option_name );
134
 
135
- if (is_multisite()) {
136
  restore_current_blog();
137
  }
138
 
@@ -149,41 +140,42 @@ class Options {
149
  *
150
  * In all other cases function \WpSecurityAuditLog::GetGlobalSetting() should be used instead.
151
  *
152
- * @see \WpSecurityAuditLog::GetGlobalSetting()
153
  * @since 4.1.3
154
  * @param string $option_name Option name we want to get a value for including necessary plugin prefix.
155
  * @param mixed $default a default value to use when one doesn't exist.
156
  * @return mixed
157
  */
158
- public static function get_option_value_ignore_prefix( $option_name = '', $default = null) {
159
- return self::_get_option_value($option_name, $default);
160
  }
161
 
162
  /**
163
  * Internal function used to get the value of an option. Any necessary prefixes are already contained in the option
164
  * name.
165
  *
166
- * @since 4.1.3
167
- * @param string $option_name Option name we want to get a value for including necessary plugin prefix.
168
- * @param mixed $default a default value to use when one doesn't exist.
169
  * @return mixed
 
170
  */
171
- private static function _get_option_value( $option_name = '', $default = null ) {
172
  // bail early if no option name was requested.
173
  if ( empty( $option_name ) || ! is_string( $option_name ) ) {
174
  return;
175
  }
176
 
177
- if (is_multisite()) {
178
- switch_to_blog(get_main_network_id());
179
  }
180
 
181
  $result = \get_option( $option_name, $default );
182
 
183
- if (is_multisite()) {
184
  restore_current_blog();
185
  }
186
- return maybe_unserialize($result);
187
  }
188
 
189
  /**
@@ -197,28 +189,30 @@ class Options {
197
  *
198
  * In all other cases function \WpSecurityAuditLog::SetGlobalSetting() should be used instead.
199
  *
200
- * @see \WpSecurityAuditLog::SetGlobalSetting()
201
- * @since 4.1.3
202
- * @param string $option_name Option name we want to get a value for including necessary plugin prefix.
203
- * @param mixed $value A value to store under the option name.
204
- * @param bool $autoload Whether or not to autoload this option.
205
  * @return mixed
 
 
206
  */
207
  public static function set_option_value_ignore_prefix( $option_name = '', $value = null, $autoload = false ) {
208
- return self::_set_option_value( $option_name, $value, $autoload );
209
  }
210
 
211
  /**
212
  * Internal function used to set the value of an option. Any necessary prefixes are already contained in the option
213
  * name.
214
  *
 
 
 
 
 
215
  * @since 4.1.3
216
- * @param string $option_name Option name we want to save a value for including necessary plugin prefix.
217
- * @param mixed $value A value to store under the option name.
218
- * @param bool $autoload Whether or not to autoload this option.
219
- * @return bool Whether or not the option was updated.
220
  */
221
- private static function _set_option_value( $option_name = '', $value = null, $autoload = false ) {
222
  // bail early if no option name or value was passed.
223
  if ( empty( $option_name ) || null === $value ) {
224
  return;
@@ -249,7 +243,7 @@ class Options {
249
  * @return bool
250
  */
251
  public static function string_to_bool( $string ) {
252
- return is_bool( $string ) ? $string : ( 'yes' === $string || 1 === $string || 'true' === $string || '1' === $string || 'on' === $string || 'enable' === $string);
253
  }
254
 
255
  /**
20
  */
21
  class Options {
22
 
 
 
 
 
 
 
 
 
23
  /**
24
  * Prefix used when setting/getting options.
25
  *
26
  * @since 4.0.2
27
+ * @var string
28
  */
29
  public $prefix;
30
 
31
  /**
32
  * Sets up this class with the main plugin instance and a prefix.
33
  *
 
34
  * @param string $prefix A prefix to use when setting/getting.
35
  *
36
  * @since 4.0.2
67
  }
68
 
69
  $actual_option_name = $option_name;
70
+ if ( ! preg_match( '/\A' . preg_quote( $this->prefix ) . '/', $option_name ) ) { // phpcs:ignore WordPress.PHP.PregQuoteDelimiter.Missing
71
+ // Remove prefix duplicate if present.
72
  $actual_option_name = $this->prefix . $option_name;
73
  }
74
 
75
+ return self::get_option_value_internal( $actual_option_name, $default );
76
  }
77
 
78
  /**
92
  }
93
 
94
  $actual_option_name = $option_name;
95
+ if ( ! preg_match( '/\A' . preg_quote( $this->prefix ) . '/', $option_name ) ) { // phpcs:ignore WordPress.PHP.PregQuoteDelimiter.Missing
96
+ // Prepend prefix if not already present.
97
  $actual_option_name = $this->prefix . $option_name;
98
  }
99
 
100
+ return self::set_option_value_internal( $actual_option_name, $value, $autoload );
101
  }
102
 
103
  /**
111
  */
112
  public function delete_option( $option_name = '' ) {
113
 
114
+ if ( is_multisite() ) {
115
+ switch_to_blog( get_main_network_id() );
116
  }
117
 
118
  $actual_option_name = $option_name;
119
+ if ( ! preg_match( '/\A' . preg_quote( $this->prefix ) . '/', $option_name ) ) { // phpcs:ignore WordPress.PHP.PregQuoteDelimiter.Missing
120
+ // Prepend prefix if not already present.
121
  $actual_option_name = $this->prefix . $option_name;
122
  }
123
 
124
  $result = \delete_option( $actual_option_name );
125
 
126
+ if ( is_multisite() ) {
127
  restore_current_blog();
128
  }
129
 
140
  *
141
  * In all other cases function \WpSecurityAuditLog::GetGlobalSetting() should be used instead.
142
  *
143
+ * @see \WpSecurityAuditLog::get_global_setting()
144
  * @since 4.1.3
145
  * @param string $option_name Option name we want to get a value for including necessary plugin prefix.
146
  * @param mixed $default a default value to use when one doesn't exist.
147
  * @return mixed
148
  */
149
+ public static function get_option_value_ignore_prefix( $option_name = '', $default = null ) {
150
+ return self::get_option_value_internal( $option_name, $default );
151
  }
152
 
153
  /**
154
  * Internal function used to get the value of an option. Any necessary prefixes are already contained in the option
155
  * name.
156
  *
157
+ * @param string $option_name Option name we want to get a value for including necessary plugin prefix.
158
+ * @param mixed $default a default value to use when one doesn't exist.
159
+ *
160
  * @return mixed
161
+ * @since 4.1.3
162
  */
163
+ private static function get_option_value_internal( $option_name = '', $default = null ) {
164
  // bail early if no option name was requested.
165
  if ( empty( $option_name ) || ! is_string( $option_name ) ) {
166
  return;
167
  }
168
 
169
+ if ( is_multisite() ) {
170
+ switch_to_blog( get_main_network_id() );
171
  }
172
 
173
  $result = \get_option( $option_name, $default );
174
 
175
+ if ( is_multisite() ) {
176
  restore_current_blog();
177
  }
178
+ return maybe_unserialize( $result );
179
  }
180
 
181
  /**
189
  *
190
  * In all other cases function \WpSecurityAuditLog::SetGlobalSetting() should be used instead.
191
  *
192
+ * @param string $option_name Option name we want to get a value for including necessary plugin prefix.
193
+ * @param mixed $value A value to store under the option name.
194
+ * @param bool $autoload Whether to autoload this option.
195
+ *
 
196
  * @return mixed
197
+ * @see \WpSecurityAuditLog::set_global_setting()
198
+ * @since 4.1.3
199
  */
200
  public static function set_option_value_ignore_prefix( $option_name = '', $value = null, $autoload = false ) {
201
+ return self::set_option_value_internal( $option_name, $value, $autoload );
202
  }
203
 
204
  /**
205
  * Internal function used to set the value of an option. Any necessary prefixes are already contained in the option
206
  * name.
207
  *
208
+ * @param string $option_name Option name we want to save a value for including necessary plugin prefix.
209
+ * @param mixed $value A value to store under the option name.
210
+ * @param bool $autoload Whether to autoload this option.
211
+ *
212
+ * @return bool Whether the option was updated.
213
  * @since 4.1.3
 
 
 
 
214
  */
215
+ private static function set_option_value_internal( $option_name = '', $value = null, $autoload = false ) {
216
  // bail early if no option name or value was passed.
217
  if ( empty( $option_name ) || null === $value ) {
218
  return;
243
  * @return bool
244
  */
245
  public static function string_to_bool( $string ) {
246
+ return is_bool( $string ) ? $string : ( 'yes' === $string || 1 === $string || 'true' === $string || '1' === $string || 'on' === $string || 'enable' === $string );
247
  }
248
 
249
  /**
classes/Loggers/Database.php CHANGED
@@ -4,8 +4,9 @@
4
  *
5
  * Logger class for wsal.
6
  *
7
- * @since 1.0.0
8
- * @package wsal
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -18,7 +19,7 @@ if ( ! defined( 'ABSPATH' ) ) {
18
  *
19
  * This class stores the logs in the database and there is also the function to clean up alerts.
20
  *
21
- * @package wsal
22
  * @subpackage loggers
23
  */
24
  class WSAL_Loggers_Database extends WSAL_AbstractLogger {
@@ -31,7 +32,7 @@ class WSAL_Loggers_Database extends WSAL_AbstractLogger {
31
  */
32
  public function __construct( WpSecurityAuditLog $plugin ) {
33
  parent::__construct( $plugin );
34
- $plugin->AddCleanupHook( array( $this, 'CleanUp' ) );
35
  }
36
 
37
  /**
@@ -41,7 +42,7 @@ class WSAL_Loggers_Database extends WSAL_AbstractLogger {
41
  * @return boolean
42
  */
43
  public function is_external() {
44
- $db_config = WSAL_Connector_ConnectorFactory::GetConfig();
45
 
46
  return is_array( $db_config ) && ! empty( $db_config );
47
  }
@@ -51,32 +52,32 @@ class WSAL_Loggers_Database extends WSAL_AbstractLogger {
51
  *
52
  * There is no difference between local and external database handling os of version 4.3.2.
53
  *
54
- * @param integer $type - Alert code.
55
- * @param array $data - Metadata.
56
- * @param integer $date - (Optional) created_on.
57
- * @param integer $site_id - (Optional) site_id.
58
  */
59
- public function Log( $type, $data = array(), $date = null, $site_id = null ) {
60
- // PHP alerts logging was deprecated in version 4.2.0
61
  if ( $type < 0010 ) {
62
  return;
63
  }
64
 
65
  // Create new occurrence.
66
- $occ = new WSAL_Models_Occurrence();
67
- $occ->created_on = $this->get_correct_timestamp( $data, $date );
68
- $occ->alert_id = $type;
69
- $occ->site_id = ! is_null( $site_id ) ? $site_id : ( function_exists( 'get_current_blog_id' ) ? get_current_blog_id() : 0 );
70
 
71
- // we need to remove the timestamp to prevent from saving it as meta
72
  unset( $data['Timestamp'] );
73
 
74
  // Get DB connector.
75
- $db_config = WSAL_Connector_ConnectorFactory::GetConfig(); // Get DB connector configuration.
76
 
77
  // Get connector for DB.
78
- $connector = $this->plugin->getConnector( $db_config );
79
- $wsal_db = $connector->getConnection(); // Get DB connection.
80
  $connection = true;
81
  if ( isset( $wsal_db->dbh->errno ) ) {
82
  $connection = ( 0 === (int) $wsal_db->dbh->errno ); // Database connection error check.
@@ -87,12 +88,12 @@ class WSAL_Loggers_Database extends WSAL_AbstractLogger {
87
  // Check DB connection.
88
  if ( $connection ) { // If connected then save the alert in DB.
89
  // Save the alert occurrence.
90
- $occ->Save();
91
 
92
  // Set up meta data of the alert.
93
  $occ->SetMeta( $data );
94
- } else {
95
- // @todo write to a debug log
96
  }
97
 
98
  /**
@@ -106,12 +107,12 @@ class WSAL_Loggers_Database extends WSAL_AbstractLogger {
106
  /**
107
  * Clean Up alerts by date OR by max number.
108
  */
109
- public function CleanUp() {
110
- $now = current_time( 'timestamp' );
111
- $max_sdate = $this->plugin->settings()->GetPruningDate();
112
- $max_count = $this->plugin->settings()->GetPruningLimit();
113
- $is_date_e = $this->plugin->settings()->IsPruningDateEnabled();
114
- $is_limt_e = $this->plugin->settings()->IsPruningLimitEnabled();
115
 
116
  // Return if retention is disabled.
117
  if ( ! $is_date_e && ! $is_limt_e ) {
@@ -120,7 +121,7 @@ class WSAL_Loggers_Database extends WSAL_AbstractLogger {
120
 
121
 
122
  $occ = new WSAL_Models_Occurrence();
123
- $cnt_items = $occ->Count();
124
 
125
  // Check if there is something to delete.
126
  if ( $is_limt_e && ( $cnt_items < $max_count ) ) {
@@ -131,23 +132,23 @@ class WSAL_Loggers_Database extends WSAL_AbstractLogger {
131
  $max_items = (int) max( ( $cnt_items - $max_count ) + 1, 0 );
132
 
133
  $query = new WSAL_Models_OccurrenceQuery();
134
- $query->addOrderBy( 'created_on', false );
135
  // TO DO: Fixing data.
136
  if ( $is_date_e ) {
137
- $query->addCondition( 'created_on <= %s', intval( $max_stamp ) );
138
  }
139
  if ( $is_limt_e ) {
140
- $query->setLimit( $max_items );
141
  }
142
 
143
- if ( ( $max_items - 1 ) == 0 ) {
144
  return; // Nothing to delete.
145
  }
146
 
147
- $result = $query->getAdapter()->GetSqlDelete( $query );
148
- $deleted_count = $query->getAdapter()->Delete( $query );
149
 
150
- if ( 0 == $deleted_count ) {
151
  return; // Nothing to delete.
152
  }
153
 
4
  *
5
  * Logger class for wsal.
6
  *
7
+ * @since 1.0.0
8
+ * @package wsal
9
+ * @subpackage loggers
10
  */
11
 
12
  // Exit if accessed directly.
19
  *
20
  * This class stores the logs in the database and there is also the function to clean up alerts.
21
  *
22
+ * @package wsal
23
  * @subpackage loggers
24
  */
25
  class WSAL_Loggers_Database extends WSAL_AbstractLogger {
32
  */
33
  public function __construct( WpSecurityAuditLog $plugin ) {
34
  parent::__construct( $plugin );
35
+ $plugin->add_cleanup_hook( array( $this, 'clean_up' ) );
36
  }
37
 
38
  /**
42
  * @return boolean
43
  */
44
  public function is_external() {
45
+ $db_config = WSAL_Connector_ConnectorFactory::get_config();
46
 
47
  return is_array( $db_config ) && ! empty( $db_config );
48
  }
52
  *
53
  * There is no difference between local and external database handling os of version 4.3.2.
54
  *
55
+ * @param integer $type - Alert code.
56
+ * @param array $data - Metadata.
57
+ * @param integer $date - (Optional) created_on.
58
+ * @param integer $site_id - (Optional) site_id.
59
  */
60
+ public function log( $type, $data = array(), $date = null, $site_id = null ) {
61
+ // PHP alerts logging was deprecated in version 4.2.0.
62
  if ( $type < 0010 ) {
63
  return;
64
  }
65
 
66
  // Create new occurrence.
67
+ $occ = new WSAL_Models_Occurrence();
68
+ $occ->created_on = $this->get_correct_timestamp( $data, $date );
69
+ $occ->alert_id = $type;
70
+ $occ->site_id = ! is_null( $site_id ) ? $site_id : ( function_exists( 'get_current_blog_id' ) ? get_current_blog_id() : 0 );
71
 
72
+ // We need to remove the timestamp to prevent from saving it as meta.
73
  unset( $data['Timestamp'] );
74
 
75
  // Get DB connector.
76
+ $db_config = WSAL_Connector_ConnectorFactory::get_config(); // Get DB connector configuration.
77
 
78
  // Get connector for DB.
79
+ $connector = $this->plugin->get_connector( $db_config );
80
+ $wsal_db = $connector->get_connection(); // Get DB connection.
81
  $connection = true;
82
  if ( isset( $wsal_db->dbh->errno ) ) {
83
  $connection = ( 0 === (int) $wsal_db->dbh->errno ); // Database connection error check.
88
  // Check DB connection.
89
  if ( $connection ) { // If connected then save the alert in DB.
90
  // Save the alert occurrence.
91
+ $occ->save();
92
 
93
  // Set up meta data of the alert.
94
  $occ->SetMeta( $data );
95
+ } else { // phpcs:ignore
96
+ // TODO write to a debug log.
97
  }
98
 
99
  /**
107
  /**
108
  * Clean Up alerts by date OR by max number.
109
  */
110
+ public function clean_up() {
111
+ $now = current_time( 'timestamp' ); // phpcs:ignore
112
+ $max_sdate = $this->plugin->settings()->get_pruning_date();
113
+ $max_count = $this->plugin->settings()->get_pruning_limit();
114
+ $is_date_e = $this->plugin->settings()->is_pruning_date_enabled();
115
+ $is_limt_e = $this->plugin->settings()->is_pruning_limit_enabled();
116
 
117
  // Return if retention is disabled.
118
  if ( ! $is_date_e && ! $is_limt_e ) {
121
 
122
 
123
  $occ = new WSAL_Models_Occurrence();
124
+ $cnt_items = $occ->count();
125
 
126
  // Check if there is something to delete.
127
  if ( $is_limt_e && ( $cnt_items < $max_count ) ) {
132
  $max_items = (int) max( ( $cnt_items - $max_count ) + 1, 0 );
133
 
134
  $query = new WSAL_Models_OccurrenceQuery();
135
+ $query->add_order_by( 'created_on', false );
136
  // TO DO: Fixing data.
137
  if ( $is_date_e ) {
138
+ $query->add_condition( 'created_on <= %s', intval( $max_stamp ) );
139
  }
140
  if ( $is_limt_e ) {
141
+ $query->set_limit( $max_items );
142
  }
143
 
144
+ if ( ( $max_items - 1 ) == 0 ) { // phpcs:ignore
145
  return; // Nothing to delete.
146
  }
147
 
148
+ $result = $query->get_adapter()->get_sql_delete( $query );
149
+ $deleted_count = $query->get_adapter()->delete( $query );
150
 
151
+ if ( 0 == $deleted_count ) { // phpcs:ignore
152
  return; // Nothing to delete.
153
  }
154
 
classes/MainWpApi.php CHANGED
@@ -1,11 +1,23 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  /**
4
  * Handler for MainWP API endpoints.
5
  *
6
  * @package wsal
7
  * @subpackage main-wp
8
- * @since 4.4.0
9
  */
10
  class WSAL_MainWpApi {
11
 
@@ -54,7 +66,7 @@ class WSAL_MainWpApi {
54
  case 'latest_event':
55
  // run the query and return it.
56
  $event = $this->query_for_latest_event();
57
- $event = $event->getAdapter()->Execute( $event );
58
 
59
  // Set the return object.
60
  if ( isset( $event[0] ) ) {
@@ -111,38 +123,37 @@ class WSAL_MainWpApi {
111
 
112
  // Initiate query occurrence object.
113
  $events_query = new WSAL_Models_OccurrenceQuery();
114
- $events_query->addCondition( 'site_id = %s ', 1 ); // Set site id.
115
- $events_query = $this->filter_query( $events_query, $query_args );
116
 
117
  // Check query arguments.
118
  if ( false !== $query_args ) {
119
  if ( isset( $query_args['get_count'] ) && $query_args['get_count'] ) {
120
- $mwp_events->total_items = $events_query->getAdapter()->Count( $events_query );
121
  } else {
122
  $mwp_events->total_items = false;
123
  }
124
  }
125
 
126
  // Set order by.
127
- $events_query->addOrderBy( 'created_on', true );
128
 
129
  // Set the limit.
130
- $events_query->setLimit( $limit );
131
 
132
  // Set the offset.
133
  if ( false !== $offset ) {
134
- $events_query->setOffset( $offset );
135
  }
136
 
137
  // Execute the query.
138
- /** @var \WSAL\MainWPExtension\Models\Occurrence[] $events */
139
- $events = $events_query->getAdapter()->Execute( $events_query );
140
 
141
  if ( ! empty( $events ) && is_array( $events ) ) {
142
  foreach ( $events as $event ) {
143
  // Get event meta.
144
- $meta_data = $event->GetMetaArray();
145
- $meta_data['UserData'] = $this->plugin->alerts->get_event_user_data( WSAL_Utilities_UsersUtils::GetUsername( $meta_data ) );
146
  $mwp_events->events[ $event->id ] = new stdClass();
147
  $mwp_events->events[ $event->id ]->id = $event->id;
148
  $mwp_events->events[ $event->id ]->alert_id = $event->alert_id;
@@ -156,138 +167,6 @@ class WSAL_MainWpApi {
156
  return $mwp_events;
157
  }
158
 
159
- /**
160
- * Filter query for MWPAL.
161
- *
162
- * @param WSAL_Models_OccurrenceQuery $query Events query.
163
- * @param array $query_args Query args.
164
- *
165
- * @return WSAL_Models_OccurrenceQuery
166
- */
167
- private function filter_query( $query, $query_args ) {
168
- if ( isset( $query_args['search_term'] ) && $query_args['search_term'] ) {
169
- $query->addSearchCondition( $query_args['search_term'] );
170
- }
171
-
172
- if ( ! empty( $query_args['search_filters'] ) ) {
173
- // Get DB connection array.
174
- $connection = $this->plugin->getConnector()->getAdapter( 'Occurrence' )->get_connection();
175
-
176
- // Tables.
177
- $meta = new WSAL_Adapters_MySQL_Meta( $connection );
178
- $table_meta = $meta->GetTable(); // Metadata.
179
- $occurrence = new WSAL_Adapters_MySQL_Occurrence( $connection );
180
- $table_occ = $occurrence->GetTable(); // Occurrences.
181
-
182
- foreach ( $query_args['search_filters'] as $prefix => $value ) {
183
- if ( 'event' === $prefix ) {
184
- $query->addORCondition( array( 'alert_id = %s' => $value ) );
185
- } elseif ( in_array( $prefix, array( 'from', 'to', 'on' ), true ) ) {
186
- $date = DateTime::createFromFormat( $this->sanitized_date_format, $value[0] );
187
- $date->setTime( 0, 0 ); // Reset time to 00:00:00.
188
- $date_string = $date->format( 'U' );
189
-
190
- if ( 'from' === $prefix ) {
191
- $query->addCondition( 'created_on >= %s', $date_string );
192
- } elseif ( 'to' === $prefix ) {
193
- $query->addCondition( 'created_on <= %s', strtotime( '+1 day -1 minute', $date_string ) );
194
- } elseif ( 'on' === $prefix ) {
195
- $query->addCondition( 'created_on >= %s', strtotime( '-1 day +1 day +1 second', $date_string ) );
196
- $query->addCondition( 'created_on <= %s', strtotime( '+1 day -1 second', $date_string ) );
197
- }
198
- } elseif ( in_array( $prefix, array( 'username', 'firstname', 'lastname' ), true ) ) {
199
- $users = array();
200
- if ( 'username' === $prefix ) {
201
- foreach ( $value as $username ) {
202
- $user = get_user_by( 'login', $username );
203
- if ( ! $user ) {
204
- $user = get_user_by( 'slug', $username );
205
- }
206
-
207
- if ( $user ) {
208
- array_push( $users, $user );
209
- }
210
- }
211
- } elseif ( 'firstname' === $prefix || 'lastname' === $prefix ) {
212
-
213
- $meta_key = 'firstname' === $prefix ? 'first_name' : ( 'lastname' === $prefix ? 'last_name' : false );
214
-
215
- foreach ( $value as $name ) {
216
- $users_array = get_users(
217
- array(
218
- 'meta_key' => $meta_key,
219
- 'meta_value' => $name,
220
- 'fields' => array( 'ID', 'user_login' ),
221
- 'meta_compare' => 'LIKE',
222
- )
223
- );
224
-
225
- foreach ( $users_array as $user ) {
226
- array_push( $users, $user );
227
- }
228
- }
229
- }
230
-
231
- if ( ! empty( $users ) ) {
232
- global $wpdb;
233
- $usernames = wp_list_pluck( $users, 'user_login' );
234
- $placeholders_string = implode( ', ', array_fill( 0, count( $usernames ), '%s' ) );
235
-
236
- $sql = $wpdb->prepare( 'username IN ( ' . $placeholders_string . ' ) ', $usernames );
237
-
238
- $user_ids = wp_list_pluck( $users, 'ID' );
239
- $placeholders_string = implode( ', ', array_fill( 0, count( $user_ids ), '%d' ) );
240
-
241
- $sql .= ' OR ' . $wpdb->prepare( 'user_id IN ( ' . $placeholders_string . ' ) ', $user_ids );
242
- $query->addORCondition( array( $sql => '' ) );
243
- }
244
- } elseif ( 'userrole' === $prefix ) {
245
- // User role search condition.
246
- $sql = "$table_occ.user_role replace(replace(replace(meta.value, ']', ''), '[', ''), '\\'', '') REGEXP %s )";
247
- $value = implode( '|', $value );
248
- $query->addORCondition( array( $sql => $value ) );
249
- } elseif ( 'postname' === $prefix ) {
250
-
251
- $sql = "$table_occ.id IN ( SELECT occurrence_id FROM $table_meta as meta WHERE meta.name='PostTitle' AND ( ";
252
- $value = array_map( array( $this, 'add_string_wildcards' ), $value );
253
-
254
- // Get the last value.
255
- $last_value = end( $value );
256
-
257
- foreach ( $value as $column_name ) {
258
- if ( $last_value === $column_name ) {
259
- continue;
260
- }
261
- $sql .= "( (meta.value LIKE '$column_name') > 0 ) OR ";
262
- }
263
-
264
- // Add placeholder for the last value.
265
- $sql .= "( (meta.value LIKE '%s') > 0 ) ) )";
266
-
267
- $query->addORCondition( array( $sql => $last_value ) );
268
- } elseif ( in_array( $prefix, array( 'posttype', 'poststatus', 'postid' ), true ) ) {
269
- $column_name = '';
270
- if ( 'posttype' === $prefix ) {
271
- $column_name = 'post_type';
272
- } elseif ( 'poststatus' === $prefix ) {
273
- $column_name = 'post_status';
274
- } elseif ( 'postid' === $prefix ) {
275
- $column_name = 'post_id';
276
- }
277
-
278
- $sql = " {$column_name} = %s ";
279
- $query->addORCondition( array( $sql => $value ) );
280
- } elseif ( 'ip' === $prefix ) {
281
- // IP search condition.
282
- $sql = "$table_occ.client_ip = %s ";
283
- $query->addORCondition( array( $sql => $value ) );
284
- }
285
- }
286
- }
287
-
288
- return $query;
289
- }
290
-
291
  /**
292
  * Generate report matching the filter passed.
293
  *
@@ -301,24 +180,6 @@ class WSAL_MainWpApi {
301
  public function get_report_data( array $filters, $report_type ) {
302
  $report = new stdClass();
303
  $report->data = array();
304
-
305
- if ( 'statistics_unique_ips' === $report_type ) {
306
- // Support for this report was removed in version 4.4.0, but we still returned empty dataset to avoid issues
307
- // in the MainWP extension.
308
- return $report;
309
- }
310
-
311
- do {
312
- $response = $this->generate_report( $filters );
313
-
314
- if ( isset( $response['data'] ) ) {
315
- $report->data = array_merge( $report->data, $response['data'] );
316
- }
317
-
318
- // Set the filters next date.
319
- $filters['nextDate'] = ( isset( $response['lastDate'] ) && $response['lastDate'] ) ? $response['lastDate'] : 0;
320
- } while ( $filters['nextDate'] );
321
-
322
  return $report;
323
  }
324
 
@@ -331,9 +192,9 @@ class WSAL_MainWpApi {
331
  public function query_for_latest_event() {
332
  $event_query = new WSAL_Models_OccurrenceQuery();
333
  // order by creation.
334
- $event_query->addOrderBy( 'created_on', true );
335
  // only request 1 item.
336
- $event_query->setLimit( 1 );
337
 
338
  return $event_query;
339
  }
@@ -371,20 +232,20 @@ class WSAL_MainWpApi {
371
 
372
  // Change the existing settings.
373
  if ( array_key_exists( 'pruning_enabled', $settings_to_enforce ) ) {
374
- $this->plugin->settings()->SetPruningDateEnabled( $settings_to_enforce['pruning_enabled'] );
375
  if ( array_key_exists( 'pruning_date', $settings_to_enforce ) && array_key_exists( 'pruning_unit', $settings_to_enforce ) ) {
376
- $this->plugin->settings()->SetPruningDate( $settings_to_enforce['pruning_date'] . ' ' . $settings_to_enforce['pruning_unit'] );
377
  $this->plugin->settings()->set_pruning_unit( $settings_to_enforce['pruning_unit'] );
378
  }
379
  }
380
 
381
  if ( array_key_exists( 'disabled_events', $settings_to_enforce ) ) {
382
  $disabled_event_ids = array_map( 'intval', explode( ',', $settings_to_enforce['disabled_events'] ) );
383
- $this->plugin->alerts->SetDisabledAlerts( $disabled_event_ids );
384
  }
385
 
386
  if ( array_key_exists( 'incognito_mode_enabled', $settings_to_enforce ) ) {
387
- $this->plugin->settings()->SetIncognito( $settings_to_enforce['incognito_mode_enabled'] );
388
  }
389
 
390
  if ( array_key_exists( 'login_notification_enabled', $settings_to_enforce ) ) {
@@ -398,7 +259,7 @@ class WSAL_MainWpApi {
398
  $this->plugin->settings()->delete_mainwp_enforced_settings();
399
  }
400
 
401
- $this->plugin->alerts->Trigger( 6043 );
402
 
403
  return array(
404
  'success' => 'yes',
@@ -430,7 +291,7 @@ class WSAL_MainWpApi {
430
  $limit = empty( $filters['limit'] ) ? 0 : $filters['limit'];
431
  $last_date = null;
432
 
433
- $results = $this->plugin->getConnector()->getAdapter( 'Occurrence' )->get_report_data( $args, $next_date, $limit );
434
 
435
  if ( ! empty( $results['lastDate'] ) ) {
436
  $last_date = $results['lastDate'];
@@ -475,7 +336,7 @@ class WSAL_MainWpApi {
475
  $alert_manager = $this->plugin->alerts;
476
 
477
  return array(
478
- 'events' => $alert_manager->GetAlerts(),
479
  'objects' => $alert_manager->get_event_objects_data(),
480
  'types' => $alert_manager->get_event_type_data(),
481
  );
1
  <?php
2
+ /**
3
+ * Class WSAL_MainWpApi.
4
+ *
5
+ * @package wsal
6
+ * @subpackage main-wp
7
+ * @since 4.4.0
8
+ */
9
+
10
+ // Exit if accessed directly.
11
+ if ( ! defined( 'ABSPATH' ) ) {
12
+ exit;
13
+ }
14
 
15
  /**
16
  * Handler for MainWP API endpoints.
17
  *
18
  * @package wsal
19
  * @subpackage main-wp
20
+ * @since 4.4.0
21
  */
22
  class WSAL_MainWpApi {
23
 
66
  case 'latest_event':
67
  // run the query and return it.
68
  $event = $this->query_for_latest_event();
69
+ $event = $event->get_adapter()->execute_query( $event );
70
 
71
  // Set the return object.
72
  if ( isset( $event[0] ) ) {
123
 
124
  // Initiate query occurrence object.
125
  $events_query = new WSAL_Models_OccurrenceQuery();
126
+ $events_query->add_condition( 'site_id = %s ', 1 ); // Set site id.
 
127
 
128
  // Check query arguments.
129
  if ( false !== $query_args ) {
130
  if ( isset( $query_args['get_count'] ) && $query_args['get_count'] ) {
131
+ $mwp_events->total_items = $events_query->get_adapter()->count( $events_query );
132
  } else {
133
  $mwp_events->total_items = false;
134
  }
135
  }
136
 
137
  // Set order by.
138
+ $events_query->add_order_by( 'created_on', true );
139
 
140
  // Set the limit.
141
+ $events_query->set_limit( $limit );
142
 
143
  // Set the offset.
144
  if ( false !== $offset ) {
145
+ $events_query->set_offset( $offset );
146
  }
147
 
148
  // Execute the query.
149
+ /** @var WSAL_Models_Occurrence[] $events */
150
+ $events = $events_query->get_adapter()->execute_query( $events_query );
151
 
152
  if ( ! empty( $events ) && is_array( $events ) ) {
153
  foreach ( $events as $event ) {
154
  // Get event meta.
155
+ $meta_data = $event->get_meta_array();
156
+ $meta_data['UserData'] = $this->plugin->alerts->get_event_user_data( WSAL_Utilities_UsersUtils::get_username( $meta_data ) );
157
  $mwp_events->events[ $event->id ] = new stdClass();
158
  $mwp_events->events[ $event->id ]->id = $event->id;
159
  $mwp_events->events[ $event->id ]->alert_id = $event->alert_id;
167
  return $mwp_events;
168
  }
169
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  /**
171
  * Generate report matching the filter passed.
172
  *
180
  public function get_report_data( array $filters, $report_type ) {
181
  $report = new stdClass();
182
  $report->data = array();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
  return $report;
184
  }
185
 
192
  public function query_for_latest_event() {
193
  $event_query = new WSAL_Models_OccurrenceQuery();
194
  // order by creation.
195
+ $event_query->add_order_by( 'created_on', true );
196
  // only request 1 item.
197
+ $event_query->set_limit( 1 );
198
 
199
  return $event_query;
200
  }
232
 
233
  // Change the existing settings.
234
  if ( array_key_exists( 'pruning_enabled', $settings_to_enforce ) ) {
235
+ $this->plugin->settings()->set_pruning_date_enabled( $settings_to_enforce['pruning_enabled'] );
236
  if ( array_key_exists( 'pruning_date', $settings_to_enforce ) && array_key_exists( 'pruning_unit', $settings_to_enforce ) ) {
237
+ $this->plugin->settings()->set_pruning_date( $settings_to_enforce['pruning_date'] . ' ' . $settings_to_enforce['pruning_unit'] );
238
  $this->plugin->settings()->set_pruning_unit( $settings_to_enforce['pruning_unit'] );
239
  }
240
  }
241
 
242
  if ( array_key_exists( 'disabled_events', $settings_to_enforce ) ) {
243
  $disabled_event_ids = array_map( 'intval', explode( ',', $settings_to_enforce['disabled_events'] ) );
244
+ $this->plugin->settings()->set_disabled_alerts( $disabled_event_ids );
245
  }
246
 
247
  if ( array_key_exists( 'incognito_mode_enabled', $settings_to_enforce ) ) {
248
+ $this->plugin->settings()->set_incognito( $settings_to_enforce['incognito_mode_enabled'] );
249
  }
250
 
251
  if ( array_key_exists( 'login_notification_enabled', $settings_to_enforce ) ) {
259
  $this->plugin->settings()->delete_mainwp_enforced_settings();
260
  }
261
 
262
+ $this->plugin->alerts->trigger_event( 6043 );
263
 
264
  return array(
265
  'success' => 'yes',
291
  $limit = empty( $filters['limit'] ) ? 0 : $filters['limit'];
292
  $last_date = null;
293
 
294
+ $results = $this->plugin->get_connector()->get_adapter( 'Occurrence' )->get_report_data( $args, $next_date, $limit );
295
 
296
  if ( ! empty( $results['lastDate'] ) ) {
297
  $last_date = $results['lastDate'];
336
  $alert_manager = $this->plugin->alerts;
337
 
338
  return array(
339
+ 'events' => $alert_manager->get_alerts(),
340
  'objects' => $alert_manager->get_event_objects_data(),
341
  'types' => $alert_manager->get_event_type_data(),
342
  );
classes/Models/ActiveRecord.php CHANGED
@@ -55,7 +55,7 @@ abstract class WSAL_Models_ActiveRecord {
55
  *
56
  * @var null
57
  */
58
- protected $adapterName = null;
59
 
60
  /**
61
  * Use Default Adapter.
@@ -69,25 +69,25 @@ abstract class WSAL_Models_ActiveRecord {
69
  *
70
  * @var string
71
  */
72
- protected $_state = self::STATE_UNKNOWN;
73
 
74
  /**
75
  * Cache.
76
  *
77
  * @var array
78
  */
79
- protected static $_cache = array();
80
 
81
  /**
82
  * Returns this records' fields.
83
  *
84
  * @return array
85
  */
86
- public function GetFields() {
87
  if ( ! isset( $this->_column_cache ) ) {
88
  $this->_column_cache = array();
89
  foreach ( array_keys( get_object_vars( $this ) ) as $col ) {
90
- if ( trim( $col ) && '_' != $col[0] ) {
91
  $this->_column_cache[] = $col;
92
  }
93
  }
@@ -100,7 +100,7 @@ abstract class WSAL_Models_ActiveRecord {
100
  *
101
  * @param integer $id - ID.
102
  */
103
- public function setId( $id ) {
104
  $this->id = $id;
105
  }
106
 
@@ -109,7 +109,7 @@ abstract class WSAL_Models_ActiveRecord {
109
  *
110
  * @return integer $id.
111
  */
112
- public function getId() {
113
  return $this->id;
114
  }
115
 
@@ -120,12 +120,12 @@ abstract class WSAL_Models_ActiveRecord {
120
  * @throws Exception - Requires adapterName.
121
  */
122
  public function __construct( $data = null ) {
123
- if ( ! $this->adapterName ) {
124
  throw new Exception( 'Class "' . __CLASS__ . '" requires "adapterName" to be set.' );
125
  }
126
  if ( ! is_null( $data ) ) {
127
- $this->LoadData( $data );
128
- $this->_state = self::STATE_LOADED;
129
  }
130
  }
131
 
@@ -134,15 +134,15 @@ abstract class WSAL_Models_ActiveRecord {
134
  *
135
  * @return WSAL_Connector_ConnectorInterface
136
  */
137
- protected function getConnector() {
138
  if ( ! empty( $this->connector ) ) {
139
  return $this->connector;
140
  }
141
 
142
  if ( $this->use_default_adapter ) {
143
- $this->connector = WSAL_Connector_ConnectorFactory::GetDefaultConnector();
144
  } else {
145
- $this->connector = WSAL_Connector_ConnectorFactory::GetConnector();
146
  }
147
  return $this->connector;
148
  }
@@ -153,41 +153,42 @@ abstract class WSAL_Models_ActiveRecord {
153
  *
154
  * @return WSAL_Adapters_ActiveRecordInterface
155
  */
156
- public function getAdapter() {
157
- // use forcefully set adapter if set
158
  if ( ! empty( $this->adapter ) ) {
159
  return $this->adapter;
160
  }
161
 
162
- // create adapter using the connector returned from getConnector method
163
- return $this->getConnector()->getAdapter( $this->adapterName );
164
  }
165
 
166
  /**
167
  * Allows the database adapter to be set from the outside. This is useful during data migrations.
168
  *
169
- * @param WSAL_Adapters_ActiveRecordInterface $adapter
170
  *
171
  * @since 4.4.0
172
  */
173
- public function setAdapter( $adapter ) {
174
  $this->adapter = $adapter;
175
  }
176
 
177
  /**
178
  * Load record from DB.
179
  *
180
- * @see WSAL_Adapters_MySQL_ActiveRecord::Load()
181
  * @param string $cond (Optional) Load condition.
182
  * @param array $args (Optional) Load condition arguments.
 
 
183
  */
184
- public function Load( $cond = '%d', $args = array( 1 ) ) {
185
- $this->_state = self::STATE_UNKNOWN;
186
 
187
- $data = $this->getAdapter()->Load( $cond, $args );
188
  if ( ! is_null( $data ) ) {
189
- $this->LoadData( $data );
190
- $this->_state = self::STATE_LOADED;
191
  }
192
  }
193
 
@@ -195,28 +196,28 @@ abstract class WSAL_Models_ActiveRecord {
195
  * Casts given value to a correct type based on the type of property (identified by the $key) in the $copy object.
196
  * This is to allow automatic type casting instead of handling each database column individually.
197
  *
198
- * @param object $copy
199
- * @param string $key
200
- * @param mixed $val
201
  *
202
  * @return mixed
203
  * @throws Exception
204
  */
205
- protected function cast_to_correct_type( $copy, $key, $val ){
206
  switch ( true ) {
207
  case is_string( $copy->$key ):
208
  case WSAL_Utilities_RequestUtils::is_ip_address( $val ):
209
  return (string) $val;
210
  case is_array( $copy->$key ):
211
  case is_object( $copy->$key ):
212
- $json_decoded_val = WSAL_Helpers_DataHelper::JsonDecode( $val );
213
  return is_null( $json_decoded_val ) ? $val : $json_decoded_val;
214
  case is_int( $copy->$key ):
215
  return (int) $val;
216
  case is_float( $copy->$key ):
217
  return (float) $val;
218
  case is_bool( $copy->$key ):
219
- return (bool) $val;
220
  default:
221
  throw new Exception( 'Unsupported type "' . gettype( $copy->$key ) . '"' );
222
  }
@@ -228,12 +229,12 @@ abstract class WSAL_Models_ActiveRecord {
228
  * @param array|object $data Data array or object.
229
  * @throws Exception - Unsupported type.
230
  */
231
- public function LoadData( $data ) {
232
  $copy = get_class( $this );
233
  $copy = new $copy();
234
  foreach ( (array) $data as $key => $val ) {
235
  if ( isset( $copy->$key ) ) {
236
- $this->$key = $this->cast_to_correct_type($copy, $key, $val);
237
  }
238
  }
239
  return $this;
@@ -242,21 +243,22 @@ abstract class WSAL_Models_ActiveRecord {
242
  /**
243
  * Save this active record
244
  *
245
- * @see WSAL_Adapters_MySQL_ActiveRecord::Save()
246
  * @return integer|boolean Either the number of modified/inserted rows or false on failure.
 
247
  */
248
- public function Save() {
249
- $this->_state = self::STATE_UNKNOWN;
250
 
251
  // Use today's date if not set up.
252
  if ( is_null( $this->created_on ) ) {
253
- $this->created_on = $this->GetMicrotime();
254
  }
255
- $update_id = $this->getId();
256
- $result = $this->getAdapter()->Save( $this );
 
257
 
258
  if ( false !== $result ) {
259
- $this->_state = ( ! empty( $update_id )) ? self::STATE_UPDATED : self::STATE_CREATED;
260
  }
261
  return $result;
262
  }
@@ -264,15 +266,16 @@ abstract class WSAL_Models_ActiveRecord {
264
  /**
265
  * Deletes this active record.
266
  *
267
- * @see WSAL_Adapters_MySQL_ActiveRecord::Delete()
268
  * @return int|boolean Either the amount of deleted rows or False on error.
 
269
  */
270
- public function Delete() {
271
- $this->_state = self::STATE_UNKNOWN;
272
- $result = $this->getAdapter()->Delete( $this );
273
  if ( false !== $result ) {
274
- $this->_state = self::STATE_DELETED;
275
  }
 
276
  return $result;
277
  }
278
 
@@ -281,11 +284,12 @@ abstract class WSAL_Models_ActiveRecord {
281
  *
282
  * @param string $cond - Condition.
283
  * @param array $args - Arguments.
284
- * @see WSAL_Adapters_MySQL_ActiveRecord::Count()
285
  * @return int count
 
286
  */
287
- public function Count( $cond = '%d', $args = array( 1 ) ) {
288
- return (int) $this->getAdapter()->Count( $cond, $args );
289
  }
290
 
291
  /**
@@ -293,8 +297,8 @@ abstract class WSAL_Models_ActiveRecord {
293
  *
294
  * @return bool
295
  */
296
- public function IsLoaded() {
297
- return self::STATE_LOADED === $this->_state;
298
  }
299
 
300
  /**
@@ -302,9 +306,9 @@ abstract class WSAL_Models_ActiveRecord {
302
  *
303
  * @return bool
304
  */
305
- public function IsSaved() {
306
- return self::STATE_CREATED === $this->_state
307
- || self::STATE_UPDATED === $this->_state;
308
  }
309
 
310
  /**
@@ -312,8 +316,8 @@ abstract class WSAL_Models_ActiveRecord {
312
  *
313
  * @return bool
314
  */
315
- public function IsCreated() {
316
- return self::STATE_CREATED === $this->_state;
317
  }
318
 
319
  /**
@@ -321,8 +325,8 @@ abstract class WSAL_Models_ActiveRecord {
321
  *
322
  * @return bool
323
  */
324
- public function IsUpdated() {
325
- return self::STATE_UPDATED === $this->_state;
326
  }
327
 
328
  /**
@@ -330,27 +334,27 @@ abstract class WSAL_Models_ActiveRecord {
330
  *
331
  * @return bool
332
  */
333
- public function IsDeleted() {
334
- return self::STATE_DELETED === $this->_state;
335
  }
336
 
337
  /**
338
  * Check if the Record structure is created.
339
  *
340
- * @see WSAL_Adapters_MySQL_ActiveRecord::IsInstalled()
341
  * @return bool
 
342
  */
343
- public function IsInstalled() {
344
- return $this->getAdapter()->IsInstalled();
345
  }
346
 
347
  /**
348
  * Install the Record structure.
349
  *
350
- * @see WSAL_Adapters_MySQL_ActiveRecord::Install()
351
  */
352
- public function Install() {
353
- return $this->getAdapter()->Install();
354
  }
355
 
356
  /**
@@ -361,13 +365,13 @@ abstract class WSAL_Models_ActiveRecord {
361
  * @param array $args Arguments used in condition.
362
  * @return WSAL_Models_ActiveRecord
363
  */
364
- protected static function CacheLoad( $target, $query, $args ) {
365
  $index = $target . '::' . vsprintf( $query, $args );
366
- if ( ! isset( self::$_cache[ $index ] ) ) {
367
- self::$_cache[ $index ] = new $target();
368
- self::$_cache[ $index ]->Load( $query, $args );
369
  }
370
- return self::$_cache[ $index ];
371
  }
372
 
373
  /**
@@ -377,17 +381,17 @@ abstract class WSAL_Models_ActiveRecord {
377
  * @param string $query Load condition.
378
  * @param array $args Arguments used in condition.
379
  */
380
- protected static function CacheRemove( $target, $query, $args ) {
381
  $index = $target . '::' . sprintf( $query, $args );
382
- if ( ! isset( self::$_cache[ $index ] ) ) {
383
- unset( self::$_cache[ $index ] );
384
  }
385
  }
386
 
387
  /**
388
  * Clear the cache.
389
  */
390
- protected static function CacheClear() {
391
- self::$_cache = array();
392
  }
393
  }
55
  *
56
  * @var null
57
  */
58
+ protected $adapter_name = null;
59
 
60
  /**
61
  * Use Default Adapter.
69
  *
70
  * @var string
71
  */
72
+ protected $state = self::STATE_UNKNOWN;
73
 
74
  /**
75
  * Cache.
76
  *
77
  * @var array
78
  */
79
+ protected static $cache = array();
80
 
81
  /**
82
  * Returns this records' fields.
83
  *
84
  * @return array
85
  */
86
+ public function get_fields() {
87
  if ( ! isset( $this->_column_cache ) ) {
88
  $this->_column_cache = array();
89
  foreach ( array_keys( get_object_vars( $this ) ) as $col ) {
90
+ if ( trim( $col ) && '_' != $col[0] ) { // phpcs:ignore
91
  $this->_column_cache[] = $col;
92
  }
93
  }
100
  *
101
  * @param integer $id - ID.
102
  */
103
+ public function set_id( $id ) {
104
  $this->id = $id;
105
  }
106
 
109
  *
110
  * @return integer $id.
111
  */
112
+ public function get_id() {
113
  return $this->id;
114
  }
115
 
120
  * @throws Exception - Requires adapterName.
121
  */
122
  public function __construct( $data = null ) {
123
+ if ( ! $this->adapter_name ) {
124
  throw new Exception( 'Class "' . __CLASS__ . '" requires "adapterName" to be set.' );
125
  }
126
  if ( ! is_null( $data ) ) {
127
+ $this->load_data( $data );
128
+ $this->state = self::STATE_LOADED;
129
  }
130
  }
131
 
134
  *
135
  * @return WSAL_Connector_ConnectorInterface
136
  */
137
+ protected function get_connector() {
138
  if ( ! empty( $this->connector ) ) {
139
  return $this->connector;
140
  }
141
 
142
  if ( $this->use_default_adapter ) {
143
+ $this->connector = WSAL_Connector_ConnectorFactory::get_default_connector();
144
  } else {
145
+ $this->connector = WSAL_Connector_ConnectorFactory::get_connector();
146
  }
147
  return $this->connector;
148
  }
153
  *
154
  * @return WSAL_Adapters_ActiveRecordInterface
155
  */
156
+ public function get_adapter() {
157
+ // Use forcefully set adapter if set.
158
  if ( ! empty( $this->adapter ) ) {
159
  return $this->adapter;
160
  }
161
 
162
+ // Create adapter using the connector returned from get_connector method.
163
+ return $this->get_connector()->get_adapter( $this->adapter_name );
164
  }
165
 
166
  /**
167
  * Allows the database adapter to be set from the outside. This is useful during data migrations.
168
  *
169
+ * @param WSAL_Adapters_ActiveRecordInterface $adapter Active record adapter.
170
  *
171
  * @since 4.4.0
172
  */
173
+ public function set_adapter( $adapter ) {
174
  $this->adapter = $adapter;
175
  }
176
 
177
  /**
178
  * Load record from DB.
179
  *
 
180
  * @param string $cond (Optional) Load condition.
181
  * @param array $args (Optional) Load condition arguments.
182
+ *
183
+ * @see WSAL_Adapters_MySQL_ActiveRecord::load()
184
  */
185
+ public function load( $cond = '%d', $args = array( 1 ) ) {
186
+ $this->state = self::STATE_UNKNOWN;
187
 
188
+ $data = $this->get_adapter()->load( $cond, $args );
189
  if ( ! is_null( $data ) ) {
190
+ $this->load_data( $data );
191
+ $this->state = self::STATE_LOADED;
192
  }
193
  }
194
 
196
  * Casts given value to a correct type based on the type of property (identified by the $key) in the $copy object.
197
  * This is to allow automatic type casting instead of handling each database column individually.
198
  *
199
+ * @param object $copy Model object copy to populate.
200
+ * @param string $key Column key.
201
+ * @param mixed $val Value.
202
  *
203
  * @return mixed
204
  * @throws Exception
205
  */
206
+ protected function cast_to_correct_type( $copy, $key, $val ) {
207
  switch ( true ) {
208
  case is_string( $copy->$key ):
209
  case WSAL_Utilities_RequestUtils::is_ip_address( $val ):
210
  return (string) $val;
211
  case is_array( $copy->$key ):
212
  case is_object( $copy->$key ):
213
+ $json_decoded_val = WSAL_Helpers_DataHelper::json_decode( $val );
214
  return is_null( $json_decoded_val ) ? $val : $json_decoded_val;
215
  case is_int( $copy->$key ):
216
  return (int) $val;
217
  case is_float( $copy->$key ):
218
  return (float) $val;
219
  case is_bool( $copy->$key ):
220
+ return (bool) $val;
221
  default:
222
  throw new Exception( 'Unsupported type "' . gettype( $copy->$key ) . '"' );
223
  }
229
  * @param array|object $data Data array or object.
230
  * @throws Exception - Unsupported type.
231
  */
232
+ public function load_data( $data ) {
233
  $copy = get_class( $this );
234
  $copy = new $copy();
235
  foreach ( (array) $data as $key => $val ) {
236
  if ( isset( $copy->$key ) ) {
237
+ $this->$key = $this->cast_to_correct_type( $copy, $key, $val );
238
  }
239
  }
240
  return $this;
243
  /**
244
  * Save this active record
245
  *
 
246
  * @return integer|boolean Either the number of modified/inserted rows or false on failure.
247
+ * @see WSAL_Adapters_MySQL_ActiveRecord::save()
248
  */
249
+ public function save() {
250
+ $this->state = self::STATE_UNKNOWN;
251
 
252
  // Use today's date if not set up.
253
  if ( is_null( $this->created_on ) ) {
254
+ $this->created_on = $this->get_microtime();
255
  }
256
+
257
+ $update_id = $this->get_id();
258
+ $result = $this->get_adapter()->save( $this );
259
 
260
  if ( false !== $result ) {
261
+ $this->state = ( ! empty( $update_id ) ) ? self::STATE_UPDATED : self::STATE_CREATED;
262
  }
263
  return $result;
264
  }
266
  /**
267
  * Deletes this active record.
268
  *
 
269
  * @return int|boolean Either the amount of deleted rows or False on error.
270
+ * @see WSAL_Adapters_MySQL_ActiveRecord::delete()
271
  */
272
+ public function delete() {
273
+ $this->state = self::STATE_UNKNOWN;
274
+ $result = $this->get_adapter()->delete( $this );
275
  if ( false !== $result ) {
276
+ $this->state = self::STATE_DELETED;
277
  }
278
+
279
  return $result;
280
  }
281
 
284
  *
285
  * @param string $cond - Condition.
286
  * @param array $args - Arguments.
287
+ *
288
  * @return int count
289
+ * @see WSAL_Adapters_MySQL_ActiveRecord::count()
290
  */
291
+ public function count( $cond = '%d', $args = array( 1 ) ) {
292
+ return (int) $this->get_adapter()->count( $cond, $args );
293
  }
294
 
295
  /**
297
  *
298
  * @return bool
299
  */
300
+ public function is_loaded() {
301
+ return self::STATE_LOADED === $this->state;
302
  }
303
 
304
  /**
306
  *
307
  * @return bool
308
  */
309
+ public function is_saved() {
310
+ return self::STATE_CREATED === $this->state
311
+ || self::STATE_UPDATED === $this->state;
312
  }
313
 
314
  /**
316
  *
317
  * @return bool
318
  */
319
+ public function is_created() {
320
+ return self::STATE_CREATED === $this->state;
321
  }
322
 
323
  /**
325
  *
326
  * @return bool
327
  */
328
+ public function is_updated() {
329
+ return self::STATE_UPDATED === $this->state;
330
  }
331
 
332
  /**
334
  *
335
  * @return bool
336
  */
337
+ public function is_deleted() {
338
+ return self::STATE_DELETED === $this->state;
339
  }
340
 
341
  /**
342
  * Check if the Record structure is created.
343
  *
 
344
  * @return bool
345
+ * @see WSAL_Adapters_MySQL_ActiveRecord::is_installed()
346
  */
347
+ public function is_installed() {
348
+ return $this->get_adapter()->is_installed();
349
  }
350
 
351
  /**
352
  * Install the Record structure.
353
  *
354
+ * @see WSAL_Adapters_MySQL_ActiveRecord::install()
355
  */
356
+ public function install() {
357
+ return $this->get_adapter()->install();
358
  }
359
 
360
  /**
365
  * @param array $args Arguments used in condition.
366
  * @return WSAL_Models_ActiveRecord
367
  */
368
+ protected static function cache_load( $target, $query, $args ) {
369
  $index = $target . '::' . vsprintf( $query, $args );
370
+ if ( ! isset( self::$cache[ $index ] ) ) {
371
+ self::$cache[ $index ] = new $target();
372
+ self::$cache[ $index ]->Load( $query, $args );
373
  }
374
+ return self::$cache[ $index ];
375
  }
376
 
377
  /**
381
  * @param string $query Load condition.
382
  * @param array $args Arguments used in condition.
383
  */
384
+ protected static function cache_remove( $target, $query, $args ) {
385
  $index = $target . '::' . sprintf( $query, $args );
386
+ if ( ! isset( self::$cache[ $index ] ) ) {
387
+ unset( self::$cache[ $index ] );
388
  }
389
  }
390
 
391
  /**
392
  * Clear the cache.
393
  */
394
+ protected static function cache_clear() {
395
+ self::$cache = array();
396
  }
397
  }
classes/Models/Meta.php CHANGED
@@ -54,21 +54,21 @@ class WSAL_Models_Meta extends WSAL_Models_ActiveRecord {
54
  *
55
  * @var string
56
  */
57
- protected $adapterName = 'Meta';
58
 
59
  /**
60
  * Save Metadata into Adapter.
61
  *
62
- * @see WSAL_Adapters_MySQL_ActiveRecord::Save()
63
  * @return integer|boolean Either the number of modified/inserted rows or false on failure.
 
64
  */
65
- public function SaveMeta() {
66
- $this->_state = self::STATE_UNKNOWN;
67
- $update_id = $this->getId();
68
- $result = $this->getAdapter()->Save( $this );
69
 
70
  if ( false !== $result ) {
71
- $this->_state = ( ! empty( $update_id )) ? self::STATE_UPDATED : self::STATE_CREATED;
72
  }
73
  return $result;
74
  }
@@ -76,25 +76,25 @@ class WSAL_Models_Meta extends WSAL_Models_ActiveRecord {
76
  /**
77
  * Update Metadata by name and occurrence_id.
78
  *
79
- * @param string $name - Meta name.
80
- * @param mixed $value - Meta value.
81
  * @param integer $occurrence_id - Occurrence_id.
82
  *
83
- * @see WSAL_Adapters_MySQL_Meta::LoadByNameAndOccurrenceId()
84
  */
85
- public function UpdateByNameAndOccurrenceId( $name, $value, $occurrence_id ) {
86
- $meta = $this->getAdapter()->LoadByNameAndOccurrenceId( $name, $occurrence_id );
87
  if ( ! empty( $meta ) ) {
88
- $this->id = $meta['id'];
89
  $this->occurrence_id = $meta['occurrence_id'];
90
- $this->name = $meta['name'];
91
- $this->value = maybe_serialize( $value );
92
- $this->saveMeta();
93
  } else {
94
  $this->occurrence_id = $occurrence_id;
95
- $this->name = $name;
96
- $this->value = maybe_serialize( $value );
97
- $this->SaveMeta();
98
  }
99
  }
100
  }
54
  *
55
  * @var string
56
  */
57
+ protected $adapter_name = 'Meta';
58
 
59
  /**
60
  * Save Metadata into Adapter.
61
  *
 
62
  * @return integer|boolean Either the number of modified/inserted rows or false on failure.
63
+ * @see WSAL_Adapters_MySQL_ActiveRecord::save()
64
  */
65
+ public function save_meta() {
66
+ $this->state = self::STATE_UNKNOWN;
67
+ $update_id = $this->get_id();
68
+ $result = $this->get_adapter()->save( $this );
69
 
70
  if ( false !== $result ) {
71
+ $this->state = ( ! empty( $update_id ) ) ? self::STATE_UPDATED : self::STATE_CREATED;
72
  }
73
  return $result;
74
  }
76
  /**
77
  * Update Metadata by name and occurrence_id.
78
  *
79
+ * @param string $name - Meta name.
80
+ * @param mixed $value - Meta value.
81
  * @param integer $occurrence_id - Occurrence_id.
82
  *
83
+ * @see WSAL_Adapters_MySQL_Meta::load_by_name_and_occurrence_id()
84
  */
85
+ public function update_by_name_and_occurrence_id( $name, $value, $occurrence_id ) {
86
+ $meta = $this->get_adapter()->load_by_name_and_occurrence_id( $name, $occurrence_id );
87
  if ( ! empty( $meta ) ) {
88
+ $this->id = $meta['id'];
89
  $this->occurrence_id = $meta['occurrence_id'];
90
+ $this->name = $meta['name'];
91
+ $this->value = maybe_serialize( $value );
92
+ $this->save_meta();
93
  } else {
94
  $this->occurrence_id = $occurrence_id;
95
+ $this->name = $name;
96
+ $this->value = maybe_serialize( $value );
97
+ $this->save_meta();
98
  }
99
  }
100
  }
classes/Models/Occurrence.php CHANGED
@@ -18,22 +18,29 @@ if ( ! defined( 'ABSPATH' ) ) {
18
  * used for get the alert, set the meta fields, etc.
19
  *
20
  * @package wsal
 
 
21
  */
22
  class WSAL_Models_Occurrence extends WSAL_Models_ActiveRecord {
23
 
 
 
 
 
 
24
  public static $migrated_meta = array(
25
- 'ClientIP' => 'client_ip',
26
- 'Severity' => 'severity',
27
- 'Object' => 'object',
28
- 'EventType' => 'event_type',
29
- 'UserAgent' => 'user_agent',
30
  'CurrentUserRoles' => 'user_roles',
31
- 'Username' => 'username',
32
- 'CurrentUserID' => 'user_id',
33
- 'SessionID' => 'session_id',
34
- 'PostStatus' => 'post_status',
35
- 'PostType' => 'post_type',
36
- 'PostID' => 'post_id'
37
  );
38
 
39
  /**
@@ -165,25 +172,27 @@ class WSAL_Models_Occurrence extends WSAL_Models_ActiveRecord {
165
  *
166
  * @var string
167
  */
168
- protected $adapterName = 'Occurrence';
169
 
170
  /**
 
 
171
  * @var string
172
  */
173
- public $_cachedMessage;
174
 
175
  /**
176
  * Returns the alert related to this occurrence.
177
  *
178
- * @see WSAL_AlertManager::GetAlert()
179
  * @return WSAL_Alert
 
180
  */
181
- public function GetAlert() {
182
- return WpSecurityAuditLog::GetInstance()->alerts->GetAlert(
183
  $this->alert_id,
184
  (object) array(
185
- 'mesg' => __( 'Alert message not found.', 'wp-security-audit-log' ),
186
- 'desc' => __( 'Alert description not found.', 'wp-security-audit-log' ),
187
  )
188
  );
189
  }
@@ -191,24 +200,24 @@ class WSAL_Models_Occurrence extends WSAL_Models_ActiveRecord {
191
  /**
192
  * Returns the value of a meta item.
193
  *
194
- * @param string $name - Name of meta item.
195
- * @param mixed $default - Default value returned when meta does not exist.
196
  *
197
  * @return mixed The value, if meta item does not exist $default returned.
198
- * @see WSAL_Adapters_MySQL_Occurrence::GetNamedMeta()
199
  */
200
- public function GetMetaValue( $name, $default = array() ) {
201
  $result = $default;
202
 
203
- // check if the meta is part of the occurrences table
204
- if ( in_array( $name, array_keys( self::$migrated_meta ) ) ) {
205
  $property_name = self::$migrated_meta[ $name ];
206
  if ( property_exists( $this, $property_name ) ) {
207
  $result = $this->$property_name;
208
  }
209
  } else {
210
  // Get meta adapter.
211
- $meta = $this->getAdapter()->GetNamedMeta( $this, $name );
212
  if ( is_null( $meta ) || ! array_key_exists( 'value', $meta ) ) {
213
  return $default;
214
  }
@@ -228,14 +237,14 @@ class WSAL_Models_Occurrence extends WSAL_Models_ActiveRecord {
228
  /**
229
  * Sets the value of a meta item (creates or updates meta item).
230
  *
231
- * @param string $name - Meta name.
232
- * @param mixed $value - Meta value.
233
  */
234
- public function SetMetaValue( $name, $value ) {
235
  // check explicitly for `0` string values.
236
  if ( '0' === $value || ! empty( $value ) ) {
237
- // check if the meta is part of the occurrences table
238
- if ( in_array( $name, array_keys( self::$migrated_meta ) ) ) {
239
  $property_name = self::$migrated_meta[ $name ];
240
  if ( property_exists( $this, $property_name ) ) {
241
  if ( 'CurrentUserRoles' === $name ) {
@@ -250,10 +259,10 @@ class WSAL_Models_Occurrence extends WSAL_Models_ActiveRecord {
250
  } else {
251
  // Get meta adapter.
252
  $model = new WSAL_Models_Meta();
253
- $model->occurrence_id = $this->getId();
254
  $model->name = $name;
255
  $model->value = maybe_serialize( $value );
256
- $model->SaveMeta();
257
  }
258
  }
259
  }
@@ -261,25 +270,25 @@ class WSAL_Models_Occurrence extends WSAL_Models_ActiveRecord {
261
  /**
262
  * Update Metadata of this occurrence by name.
263
  *
264
- * @param string $name - Meta name.
265
- * @param mixed $value - Meta value.
266
  *
267
- *@see WSAL_Models_Meta::UpdateByNameAndOccurrenceId()
268
  */
269
- public function UpdateMetaValue( $name, $value ) {
270
  $model = new WSAL_Models_Meta();
271
- $model->UpdateByNameAndOccurrenceId( $name, $value, $this->getId() );
272
  }
273
 
274
  /**
275
  * Returns a key-value pair of metadata.
276
  *
277
  * @return array
278
- * @see WSAL_Adapters_MySQL_Occurrence::GetMultiMeta()
279
  */
280
- public function GetMetaArray() {
281
  $result = array();
282
- $metas = $this->getAdapter()->GetMultiMeta( $this );
283
  foreach ( $metas as $meta ) {
284
  $result[ $meta->name ] = maybe_unserialize( $meta->value );
285
  }
@@ -298,39 +307,38 @@ class WSAL_Models_Occurrence extends WSAL_Models_ActiveRecord {
298
  */
299
  public function SetMeta( $data ) {
300
  foreach ( (array) $data as $key => $val ) {
301
- $this->SetMetaValue( $key, $val );
302
  }
303
 
304
- // the occurrence object itself needs to be saved again as some metadata is stored as its properties
305
- $this->Save();
306
  }
307
 
308
  /**
309
  * Gets alert message.
310
  *
311
- * @param array $meta - Occurrence meta array.
312
  * @param string $context Message context.
313
  *
314
  * @return string Full-formatted message.
315
- * @throws Freemius_Exception
316
- * @see WSAL_Alert::GetMessage()
317
- */
318
- public function GetMessage( $meta = null, $context = false ) {
319
- if ( ! isset( $this->_cachedMessage ) ) {
320
- // message caching
321
- if ( ! $this->_cachedMessage ) {
322
- $this->_cachedMessage = $this->GetAlert()->mesg;
323
  }
324
  // Fill variables in message.
325
- $meta_array = null === $meta ? $this->GetMetaArray() : $meta;
326
- $alert_object = $this->GetAlert();
327
- if ( null !== $alert_object && method_exists( $alert_object, 'GetMessage' ) ) {
328
- $this->_cachedMessage = $alert_object->GetMessage( $meta_array, $this->_cachedMessage, $this->getId(), $context );
329
  } else {
330
  // Filter to allow items to be added elsewhere.
331
  $addon_event_codes = apply_filters( 'wsal_addon_event_codes', $addon_event_codes );
332
 
333
- $installer_nonce = wp_create_nonce( 'wsal-install-addon' );
334
  foreach ( $addon_event_codes as $key => $addon ) {
335
  if ( in_array( $this->alert_id, $addon['event_ids'], true ) ) {
336
  // check key and update message here.
@@ -345,7 +353,7 @@ class WSAL_Models_Occurrence extends WSAL_Models_ActiveRecord {
345
  return $message;
346
  }
347
  }
348
- $this->_cachedMessage = isset( $cached_message ) ? $cached_message : sprintf(
349
  /* Translators: 1: html that opens a link, 2: html that closes a link. */
350
  __( 'This type of activity / change is no longer monitored. You can create your own custom event IDs to keep a log of such change. Read more about custom events %1$shere%2$s.', 'wp-security-audit-log' ),
351
  '<a href="https://wpactivitylog.com/support/kb/create-custom-events-wordpress-activity-log/" rel="noopener noreferrer" target="_blank">',
@@ -353,22 +361,24 @@ class WSAL_Models_Occurrence extends WSAL_Models_ActiveRecord {
353
  );
354
  }
355
  }
356
- return $this->_cachedMessage;
357
  }
358
 
359
  /**
360
  * Delete occurrence as well as associated meta data.
361
  *
362
- * @see WSAL_Adapters_ActiveRecordInterface::Delete()
363
  * @return boolean True on success, false on failure.
 
 
364
  */
365
- public function Delete() {
366
  /** @var WSAL_Adapters_MySQL_Occurrence $adapter */
367
- $adapter= $this->getAdapter();
368
- foreach ( $adapter->GetMultiMeta() as $meta ) {
369
- $meta->Delete();
370
  }
371
- return parent::Delete();
372
  }
373
 
374
  /**
@@ -387,8 +397,8 @@ class WSAL_Models_Occurrence extends WSAL_Models_ActiveRecord {
387
  *
388
  * @return string IP address of request.
389
  */
390
- public function GetSourceIP() {
391
- return $this->GetMetaValue( 'ClientIP', array() );
392
  }
393
 
394
  /**
@@ -396,9 +406,9 @@ class WSAL_Models_Occurrence extends WSAL_Models_ActiveRecord {
396
  *
397
  * @return string IP address of request (from proxies etc).
398
  */
399
- public function GetOtherIPs() {
400
  $result = array();
401
- $data = (array) $this->GetMetaValue( 'OtherIPs', array() );
402
  foreach ( $data as $ips ) {
403
  foreach ( $ips as $ip ) {
404
  $result[] = $ip;
@@ -412,12 +422,17 @@ class WSAL_Models_Occurrence extends WSAL_Models_ActiveRecord {
412
  *
413
  * @return array Array of user roles.
414
  */
415
- public function GetUserRoles() {
416
- return $this->GetMetaValue( 'CurrentUserRoles', array() );
417
  }
418
 
419
- public function SetUserRoles( $roles ) {
420
- $this->user_roles = is_array($roles) ? implode( ',', $roles ) : $roles;
 
 
 
 
 
421
  }
422
 
423
  /**
@@ -425,8 +440,8 @@ class WSAL_Models_Occurrence extends WSAL_Models_ActiveRecord {
425
  *
426
  * @return string User's username.
427
  */
428
- public function GetUsername() {
429
- return WSAL_Utilities_UsersUtils::GetUsername( $this->GetMetaArray() );
430
  }
431
 
432
  /**
@@ -435,8 +450,8 @@ class WSAL_Models_Occurrence extends WSAL_Models_ActiveRecord {
435
  * @return float - Number of seconds (and milliseconds as fraction) since unix Day 0.
436
  * @todo This needs some caching.
437
  */
438
- protected function GetMicrotime() {
439
- return microtime( true );// + get_option('gmt_offset') * HOUR_IN_SECONDS;
440
  }
441
 
442
  /**
@@ -445,8 +460,8 @@ class WSAL_Models_Occurrence extends WSAL_Models_ActiveRecord {
445
  * @param array $args - Query args.
446
  * @return WSAL_Models_Occurrence[]
447
  */
448
- public function CheckKnownUsers( $args = array() ) {
449
- return $this->getAdapter()->CheckKnownUsers( $args );
450
  }
451
 
452
  /**
@@ -455,8 +470,8 @@ class WSAL_Models_Occurrence extends WSAL_Models_ActiveRecord {
455
  * @param array $args - Query args.
456
  * @return WSAL_Models_Occurrence[]
457
  */
458
- public function CheckUnknownUsers( $args = array() ) {
459
- return $this->getAdapter()->CheckUnknownUsers( $args );
460
  }
461
 
462
  /**
@@ -466,47 +481,60 @@ class WSAL_Models_Occurrence extends WSAL_Models_ActiveRecord {
466
  * @return WSAL_Models_Occurrence[]
467
  */
468
  public function check_alert_1003( $args = array() ) {
469
- return $this->getAdapter()->check_alert_1003( $args );
470
  }
471
 
472
  /**
473
  * Gets occurrence by Post_id
474
  *
475
- * @see WSAL_Adapters_MySQL_Occurrence::GetByPostID()
476
  * @param integer $post_id - Post ID.
 
477
  * @return WSAL_Models_Occurrence[]
 
478
  */
479
- public function GetByPostID( $post_id ) {
480
- return $this->getAdapter()->GetByPostID( $post_id );
481
  }
482
 
483
  /**
484
- * @inheritDoc
485
  *
486
  * Extends the default mechanism for loading data to handle the migrated meta fields in version 4.4.0.
487
  *
488
  * @since 4.4.0
489
  */
490
- public function LoadData( $data ) {
491
  $copy = get_class( $this );
492
  $copy = new $copy();
493
  foreach ( (array) $data as $key => $val ) {
494
- if ( ! is_null( $val ) && in_array($key, ['user_id', 'username'])) {
495
- // username and user_id cannot have the default value set because some database queries rely on having
496
- // null values in the database
497
  if ( 'user_id' === $key ) {
498
  $this->user_id = intval( $val );
499
- } else if ( 'username' === $key ) {
500
  $this->username = (string) $val;
501
  }
502
- } else if ( 'roles' === $key ) {
503
- $this->SetUserRoles($val);
504
- } else if ( isset( $copy->$key ) ) {
505
- // default type casting is applied to the rest of the fields
506
  $this->$key = $this->cast_to_correct_type( $copy, $key, $val );
507
  }
508
  }
509
 
510
  return $this;
511
  }
 
 
 
 
 
 
 
 
 
 
 
 
512
  }
18
  * used for get the alert, set the meta fields, etc.
19
  *
20
  * @package wsal
21
+ *
22
+ * phpcs:disable PSR2.Classes.PropertyDeclaration.Underscore
23
  */
24
  class WSAL_Models_Occurrence extends WSAL_Models_ActiveRecord {
25
 
26
+ /**
27
+ * List of migrated metadata fields.
28
+ *
29
+ * @var string[]
30
+ */
31
  public static $migrated_meta = array(
32
+ 'ClientIP' => 'client_ip',
33
+ 'Severity' => 'severity',
34
+ 'Object' => 'object',
35
+ 'EventType' => 'event_type',
36
+ 'UserAgent' => 'user_agent',
37
  'CurrentUserRoles' => 'user_roles',
38
+ 'Username' => 'username',
39
+ 'CurrentUserID' => 'user_id',
40
+ 'SessionID' => 'session_id',
41
+ 'PostStatus' => 'post_status',
42
+ 'PostType' => 'post_type',
43
+ 'PostID' => 'post_id',
44
  );
45
 
46
  /**
172
  *
173
  * @var string
174
  */
175
+ protected $adapter_name = 'Occurrence';
176
 
177
  /**
178
+ * Cached message.
179
+ *
180
  * @var string
181
  */
182
+ public $_cached_message;
183
 
184
  /**
185
  * Returns the alert related to this occurrence.
186
  *
 
187
  * @return WSAL_Alert
188
+ * @see WSAL_AlertManager::get_alert()
189
  */
190
+ public function get_alert() {
191
+ return WpSecurityAuditLog::get_instance()->alerts->get_alert(
192
  $this->alert_id,
193
  (object) array(
194
+ 'mesg' => esc_html__( 'Alert message not found.', 'wp-security-audit-log' ),
195
+ 'desc' => esc_html__( 'Alert description not found.', 'wp-security-audit-log' ),
196
  )
197
  );
198
  }
200
  /**
201
  * Returns the value of a meta item.
202
  *
203
+ * @param string $name - Name of meta item.
204
+ * @param mixed $default - Default value returned when meta does not exist.
205
  *
206
  * @return mixed The value, if meta item does not exist $default returned.
207
+ * @see WSAL_Adapters_MySQL_Occurrence::get_named_meta()
208
  */
209
+ public function get_meta_value( $name, $default = array() ) {
210
  $result = $default;
211
 
212
+ // Check if the meta is part of the occurrences table.
213
+ if ( in_array( $name, array_keys( self::$migrated_meta ), true ) ) {
214
  $property_name = self::$migrated_meta[ $name ];
215
  if ( property_exists( $this, $property_name ) ) {
216
  $result = $this->$property_name;
217
  }
218
  } else {
219
  // Get meta adapter.
220
+ $meta = $this->get_adapter()->get_named_meta( $this, $name );
221
  if ( is_null( $meta ) || ! array_key_exists( 'value', $meta ) ) {
222
  return $default;
223
  }
237
  /**
238
  * Sets the value of a meta item (creates or updates meta item).
239
  *
240
+ * @param string $name - Meta name.
241
+ * @param mixed $value - Meta value.
242
  */
243
+ public function set_meta_value( $name, $value ) {
244
  // check explicitly for `0` string values.
245
  if ( '0' === $value || ! empty( $value ) ) {
246
+ // Check if the meta is part of the occurrences table.
247
+ if ( in_array( $name, array_keys( self::$migrated_meta ), true ) ) {
248
  $property_name = self::$migrated_meta[ $name ];
249
  if ( property_exists( $this, $property_name ) ) {
250
  if ( 'CurrentUserRoles' === $name ) {
259
  } else {
260
  // Get meta adapter.
261
  $model = new WSAL_Models_Meta();
262
+ $model->occurrence_id = $this->get_id();
263
  $model->name = $name;
264
  $model->value = maybe_serialize( $value );
265
+ $model->save_meta();
266
  }
267
  }
268
  }
270
  /**
271
  * Update Metadata of this occurrence by name.
272
  *
273
+ * @param string $name - Meta name.
274
+ * @param mixed $value - Meta value.
275
  *
276
+ * @see WSAL_Models_Meta::update_by_name_and_occurrence_id()
277
  */
278
+ public function update_meta_value( $name, $value ) {
279
  $model = new WSAL_Models_Meta();
280
+ $model->update_by_name_and_occurrence_id( $name, $value, $this->get_id() );
281
  }
282
 
283
  /**
284
  * Returns a key-value pair of metadata.
285
  *
286
  * @return array
287
+ * @see WSAL_Adapters_MySQL_Occurrence::get_multi_meta()
288
  */
289
+ public function get_meta_array() {
290
  $result = array();
291
+ $metas = $this->get_adapter()->get_multi_meta( $this );
292
  foreach ( $metas as $meta ) {
293
  $result[ $meta->name ] = maybe_unserialize( $meta->value );
294
  }
307
  */
308
  public function SetMeta( $data ) {
309
  foreach ( (array) $data as $key => $val ) {
310
+ $this->set_meta_value( $key, $val );
311
  }
312
 
313
+ // The occurrence object itself needs to be saved again as some metadata is stored as its properties.
314
+ $this->save();
315
  }
316
 
317
  /**
318
  * Gets alert message.
319
  *
320
+ * @param array $meta - Occurrence meta array.
321
  * @param string $context Message context.
322
  *
323
  * @return string Full-formatted message.
324
+ * @see WSAL_Alert::get_message()
325
+ */
326
+ public function get_message( $meta = null, $context = false ) {
327
+ if ( ! isset( $this->_cached_message ) ) {
328
+ // Message caching.
329
+ if ( ! $this->_cached_message ) {
330
+ $this->_cached_message = $this->get_alert()->mesg;
 
331
  }
332
  // Fill variables in message.
333
+ $meta_array = null === $meta ? $this->get_meta_array() : $meta;
334
+ $alert_object = $this->get_alert();
335
+ if ( null !== $alert_object && method_exists( $alert_object, 'get_message' ) ) {
336
+ $this->_cached_message = $alert_object->get_message( $meta_array, $this->_cached_message, $this->get_id(), $context );
337
  } else {
338
  // Filter to allow items to be added elsewhere.
339
  $addon_event_codes = apply_filters( 'wsal_addon_event_codes', $addon_event_codes );
340
 
341
+ $installer_nonce = wp_create_nonce( 'wsal-install-addon' );
342
  foreach ( $addon_event_codes as $key => $addon ) {
343
  if ( in_array( $this->alert_id, $addon['event_ids'], true ) ) {
344
  // check key and update message here.
353
  return $message;
354
  }
355
  }
356
+ $this->_cached_message = isset( $cached_message ) ? $cached_message : sprintf(
357
  /* Translators: 1: html that opens a link, 2: html that closes a link. */
358
  __( 'This type of activity / change is no longer monitored. You can create your own custom event IDs to keep a log of such change. Read more about custom events %1$shere%2$s.', 'wp-security-audit-log' ),
359
  '<a href="https://wpactivitylog.com/support/kb/create-custom-events-wordpress-activity-log/" rel="noopener noreferrer" target="_blank">',
361
  );
362
  }
363
  }
364
+ return $this->_cached_message;
365
  }
366
 
367
  /**
368
  * Delete occurrence as well as associated meta data.
369
  *
370
+ * @see WSAL_Adapters_ActiveRecordInterface::delete()
371
  * @return boolean True on success, false on failure.
372
+ *
373
+ * @phpcs:disable Generic.Commenting.DocComment.MissingShort
374
  */
375
+ public function delete() {
376
  /** @var WSAL_Adapters_MySQL_Occurrence $adapter */
377
+ $adapter = $this->get_adapter();
378
+ foreach ( $adapter->get_multi_meta() as $meta ) {
379
+ $meta->delete();
380
  }
381
+ return parent::delete();
382
  }
383
 
384
  /**
397
  *
398
  * @return string IP address of request.
399
  */
400
+ public function get_source_ip() {
401
+ return $this->get_meta_value( 'ClientIP', array() );
402
  }
403
 
404
  /**
406
  *
407
  * @return string IP address of request (from proxies etc).
408
  */
409
+ public function get_other_ips() {
410
  $result = array();
411
+ $data = (array) $this->get_meta_value( 'OtherIPs', array() );
412
  foreach ( $data as $ips ) {
413
  foreach ( $ips as $ip ) {
414
  $result[] = $ip;
422
  *
423
  * @return array Array of user roles.
424
  */
425
+ public function get_user_roles() {
426
+ return $this->get_meta_value( 'CurrentUserRoles', array() );
427
  }
428
 
429
+ /**
430
+ * Sets the user roles.
431
+ *
432
+ * @param string $roles Array of user roles.
433
+ */
434
+ public function set_user_roles( $roles ) {
435
+ $this->user_roles = is_array( $roles ) ? implode( ',', $roles ) : $roles;
436
  }
437
 
438
  /**
440
  *
441
  * @return string User's username.
442
  */
443
+ public function get_username() {
444
+ return WSAL_Utilities_UsersUtils::get_username( $this->get_meta_array() );
445
  }
446
 
447
  /**
450
  * @return float - Number of seconds (and milliseconds as fraction) since unix Day 0.
451
  * @todo This needs some caching.
452
  */
453
+ protected function get_microtime() {
454
+ return microtime( true );
455
  }
456
 
457
  /**
460
  * @param array $args - Query args.
461
  * @return WSAL_Models_Occurrence[]
462
  */
463
+ public function check_known_users( $args = array() ) {
464
+ return $this->get_adapter()->check_known_users( $args );
465
  }
466
 
467
  /**
470
  * @param array $args - Query args.
471
  * @return WSAL_Models_Occurrence[]
472
  */
473
+ public function check_unknown_users( $args = array() ) {
474
+ return $this->get_adapter()->check_unknown_users( $args );
475
  }
476
 
477
  /**
481
  * @return WSAL_Models_Occurrence[]
482
  */
483
  public function check_alert_1003( $args = array() ) {
484
+ return $this->get_adapter()->check_alert_1003( $args );
485
  }
486
 
487
  /**
488
  * Gets occurrence by Post_id
489
  *
 
490
  * @param integer $post_id - Post ID.
491
+ *
492
  * @return WSAL_Models_Occurrence[]
493
+ * @see WSAL_Adapters_MySQL_Occurrence::get_by_post_id()
494
  */
495
+ public function get_by_post_id( $post_id ) {
496
+ return $this->get_adapter()->get_by_post_id( $post_id );
497
  }
498
 
499
  /**
500
+ * {@inheritDoc}
501
  *
502
  * Extends the default mechanism for loading data to handle the migrated meta fields in version 4.4.0.
503
  *
504
  * @since 4.4.0
505
  */
506
+ public function load_data( $data ) {
507
  $copy = get_class( $this );
508
  $copy = new $copy();
509
  foreach ( (array) $data as $key => $val ) {
510
+ if ( ! is_null( $val ) && in_array( $key, array( 'user_id', 'username' ), true ) ) {
511
+ // Username and user_id cannot have the default value set because some database queries rely on having
512
+ // null values in the database.
513
  if ( 'user_id' === $key ) {
514
  $this->user_id = intval( $val );
515
+ } elseif ( 'username' === $key ) {
516
  $this->username = (string) $val;
517
  }
518
+ } elseif ( 'roles' === $key ) {
519
+ $this->set_user_roles( $val );
520
+ } elseif ( isset( $copy->$key ) ) {
521
+ // Default type casting is applied to the rest of the fields.
522
  $this->$key = $this->cast_to_correct_type( $copy, $key, $val );
523
  }
524
  }
525
 
526
  return $this;
527
  }
528
+
529
+ /**
530
+ * Deprecated placeholder function.
531
+ *
532
+ * @return array
533
+ *
534
+ * @deprecated 4.4.1 Replaced by function get_meta_array.
535
+ * @see WSAL_Models_Occurrence::get_meta_array()
536
+ */
537
+ public function GetMetaArray() {
538
+ return $this->get_meta_array();
539
+ }
540
  }
classes/Models/OccurrenceQuery.php CHANGED
@@ -57,6 +57,6 @@ class WSAL_Models_OccurrenceQuery extends WSAL_Models_Query {
57
  parent::__construct();
58
 
59
  // TO DO: Consider if Get Table is the right method to call given that this is mysql specific.
60
- $this->addFrom( $this->getConnector()->getAdapter( 'Occurrence' )->GetTable() );
61
  }
62
  }
57
  parent::__construct();
58
 
59
  // TO DO: Consider if Get Table is the right method to call given that this is mysql specific.
60
+ $this->add_from( $this->get_connector()->get_adapter( 'Occurrence' )->get_table() );
61
  }
62
  }
classes/Models/Query.php CHANGED
@@ -40,7 +40,7 @@ class WSAL_Models_Query {
40
  *
41
  * @var array
42
  */
43
- protected $orderBy = array();
44
 
45
  /**
46
  * Offset.
@@ -75,7 +75,7 @@ class WSAL_Models_Query {
75
  *
76
  * @var mixed
77
  */
78
- protected $searchCondition = null;
79
 
80
  /**
81
  * Use Default Adapter.
@@ -97,15 +97,15 @@ class WSAL_Models_Query {
97
  *
98
  * @return WSAL_Connector_ConnectorInterface
99
  */
100
- public function getConnector() {
101
  if ( ! empty( $this->connector ) ) {
102
  return $this->connector;
103
  }
104
 
105
  if ( $this->use_default_adapter ) {
106
- $this->connector = WSAL_Connector_ConnectorFactory::GetDefaultConnector();
107
  } else {
108
- $this->connector = WSAL_Connector_ConnectorFactory::GetConnector();
109
  }
110
  return $this->connector;
111
  }
@@ -115,8 +115,8 @@ class WSAL_Models_Query {
115
  *
116
  * @return WSAL_Adapters_QueryInterface
117
  */
118
- public function getAdapter() {
119
- return $this->getConnector()->getAdapter( 'Query' );
120
  }
121
 
122
  /**
@@ -125,7 +125,7 @@ class WSAL_Models_Query {
125
  * @param mixed $column - Column value.
126
  * @return self
127
  */
128
- public function addColumn( $column ) {
129
  $this->columns[] = $column;
130
  return $this;
131
  }
@@ -135,7 +135,7 @@ class WSAL_Models_Query {
135
  *
136
  * @return self
137
  */
138
- public function clearColumns() {
139
  $this->columns = array();
140
  return $this;
141
  }
@@ -145,7 +145,7 @@ class WSAL_Models_Query {
145
  *
146
  * @return array $columns
147
  */
148
- public function getColumns() {
149
  return $this->columns;
150
  }
151
 
@@ -155,7 +155,7 @@ class WSAL_Models_Query {
155
  * @param array $columns - Columns values.
156
  * @return self
157
  */
158
- public function setColumns( $columns ) {
159
  $this->columns = $columns;
160
  return $this;
161
  }
@@ -167,7 +167,7 @@ class WSAL_Models_Query {
167
  * @param mixed $value - Condition value.
168
  * @return self
169
  */
170
- public function addCondition( $field, $value ) {
171
  $this->conditions[ $field ] = $value;
172
  return $this;
173
  }
@@ -177,7 +177,7 @@ class WSAL_Models_Query {
177
  *
178
  * @param array $add_conditions - Multi conditions.
179
  */
180
- public function addORCondition( $add_conditions ) {
181
  $this->conditions[] = $add_conditions;
182
  }
183
 
@@ -186,7 +186,7 @@ class WSAL_Models_Query {
186
  *
187
  * @return self
188
  */
189
- public function clearConditions() {
190
  $this->conditions = array();
191
  return $this;
192
  }
@@ -196,20 +196,22 @@ class WSAL_Models_Query {
196
  *
197
  * @return array $conditions
198
  */
199
- public function getConditions() {
200
  return $this->conditions;
201
  }
202
 
203
  /**
204
  * Add order by.
205
  *
206
- * @param string $field - Field name.
207
  * @param boolean $is_descending - (Optional) Ascending/descending.
 
208
  * @return self
209
  */
210
- public function addOrderBy( $field, $is_descending = false ) {
211
- $order = ($is_descending) ? 'DESC' : 'ASC';
212
- $this->orderBy[ $field ] = $order;
 
213
  return $this;
214
  }
215
 
@@ -218,8 +220,8 @@ class WSAL_Models_Query {
218
  *
219
  * @return self
220
  */
221
- public function clearOrderBy() {
222
- $this->orderBy = array();
223
  return $this;
224
  }
225
 
@@ -228,8 +230,8 @@ class WSAL_Models_Query {
228
  *
229
  * @return array $orderBy
230
  */
231
- public function getOrderBy() {
232
- return $this->orderBy;
233
  }
234
 
235
  /**
@@ -238,7 +240,7 @@ class WSAL_Models_Query {
238
  * @param string $from_data_set - Data set.
239
  * @return self
240
  */
241
- public function addFrom( $from_data_set ) {
242
  $this->from[] = $from_data_set;
243
  return $this;
244
  }
@@ -248,7 +250,7 @@ class WSAL_Models_Query {
248
  *
249
  * @return self
250
  */
251
- public function clearFrom() {
252
  $this->from = array();
253
  return $this;
254
  }
@@ -258,7 +260,7 @@ class WSAL_Models_Query {
258
  *
259
  * @return string $from data set
260
  */
261
- public function getFrom() {
262
  return $this->from;
263
  }
264
 
@@ -267,7 +269,7 @@ class WSAL_Models_Query {
267
  *
268
  * @return mixed
269
  */
270
- public function getLimit() {
271
  return $this->limit;
272
  }
273
 
@@ -277,7 +279,7 @@ class WSAL_Models_Query {
277
  * @param mixed $limit - The limit.
278
  * @return self
279
  */
280
- public function setLimit( $limit ) {
281
  $this->limit = $limit;
282
  return $this;
283
  }
@@ -287,7 +289,7 @@ class WSAL_Models_Query {
287
  *
288
  * @return mixed
289
  */
290
- public function getOffset() {
291
  return $this->offset;
292
  }
293
 
@@ -297,7 +299,7 @@ class WSAL_Models_Query {
297
  * @param mixed $offset - The offset.
298
  * @return self
299
  */
300
- public function setOffset( $offset ) {
301
  $this->offset = $offset;
302
  return $this;
303
  }
@@ -308,8 +310,8 @@ class WSAL_Models_Query {
308
  * @param mixed $value - Condition.
309
  * @return self
310
  */
311
- public function addSearchCondition( $value ) {
312
- $this->searchCondition = $value;
313
  return $this;
314
  }
315
 
@@ -318,8 +320,8 @@ class WSAL_Models_Query {
318
  *
319
  * @return self
320
  */
321
- public function getSearchCondition() {
322
- return $this->searchCondition;
323
  }
324
 
325
  /**
@@ -327,7 +329,7 @@ class WSAL_Models_Query {
327
  *
328
  * @return boolean
329
  */
330
- public function hasMetaJoin() {
331
  return $this->meta_join;
332
  }
333
 
@@ -336,8 +338,49 @@ class WSAL_Models_Query {
336
  *
337
  * @return self
338
  */
339
- public function addMetaJoin() {
340
  $this->meta_join = true;
341
  return $this;
342
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
343
  }
40
  *
41
  * @var array
42
  */
43
+ protected $order_by = array();
44
 
45
  /**
46
  * Offset.
75
  *
76
  * @var mixed
77
  */
78
+ protected $search_condition = null;
79
 
80
  /**
81
  * Use Default Adapter.
97
  *
98
  * @return WSAL_Connector_ConnectorInterface
99
  */
100
+ public function get_connector() {
101
  if ( ! empty( $this->connector ) ) {
102
  return $this->connector;
103
  }
104
 
105
  if ( $this->use_default_adapter ) {
106
+ $this->connector = WSAL_Connector_ConnectorFactory::get_default_connector();
107
  } else {
108
+ $this->connector = WSAL_Connector_ConnectorFactory::get_connector();
109
  }
110
  return $this->connector;
111
  }
115
  *
116
  * @return WSAL_Adapters_QueryInterface
117
  */
118
+ public function get_adapter() {
119
+ return $this->get_connector()->get_adapter( 'Query' );
120
  }
121
 
122
  /**
125
  * @param mixed $column - Column value.
126
  * @return self
127
  */
128
+ public function add_column( $column ) {
129
  $this->columns[] = $column;
130
  return $this;
131
  }
135
  *
136
  * @return self
137
  */
138
+ public function clear_columns() {
139
  $this->columns = array();
140
  return $this;
141
  }
145
  *
146
  * @return array $columns
147
  */
148
+ public function get_columns() {
149
  return $this->columns;
150
  }
151
 
155
  * @param array $columns - Columns values.
156
  * @return self
157
  */
158
+ public function set_columns( $columns ) {
159
  $this->columns = $columns;
160
  return $this;
161
  }
167
  * @param mixed $value - Condition value.
168
  * @return self
169
  */
170
+ public function add_condition( $field, $value ) {
171
  $this->conditions[ $field ] = $value;
172
  return $this;
173
  }
177
  *
178
  * @param array $add_conditions - Multi conditions.
179
  */
180
+ public function add_or_condition( $add_conditions ) {
181
  $this->conditions[] = $add_conditions;
182
  }
183
 
186
  *
187
  * @return self
188
  */
189
+ public function clear_conditions() {
190
  $this->conditions = array();
191
  return $this;
192
  }
196
  *
197
  * @return array $conditions
198
  */
199
+ public function get_conditions() {
200
  return $this->conditions;
201
  }
202
 
203
  /**
204
  * Add order by.
205
  *
206
+ * @param string $field - Field name.
207
  * @param boolean $is_descending - (Optional) Ascending/descending.
208
+ *
209
  * @return self
210
  */
211
+ public function add_order_by( $field, $is_descending = false ) {
212
+ $order = ( $is_descending ) ? 'DESC' : 'ASC';
213
+ $this->order_by[ $field ] = $order;
214
+
215
  return $this;
216
  }
217
 
220
  *
221
  * @return self
222
  */
223
+ public function clear_order_by() {
224
+ $this->order_by = array();
225
  return $this;
226
  }
227
 
230
  *
231
  * @return array $orderBy
232
  */
233
+ public function get_order_by() {
234
+ return $this->order_by;
235
  }
236
 
237
  /**
240
  * @param string $from_data_set - Data set.
241
  * @return self
242
  */
243
+ public function add_from( $from_data_set ) {
244
  $this->from[] = $from_data_set;
245
  return $this;
246
  }
250
  *
251
  * @return self
252
  */
253
+ public function clear_from() {
254
  $this->from = array();
255
  return $this;
256
  }
260
  *
261
  * @return string $from data set
262
  */
263
+ public function get_from() {
264
  return $this->from;
265
  }
266
 
269
  *
270
  * @return mixed
271
  */
272
+ public function get_limit() {
273
  return $this->limit;
274
  }
275
 
279
  * @param mixed $limit - The limit.
280
  * @return self
281
  */
282
+ public function set_limit( $limit ) {
283
  $this->limit = $limit;
284
  return $this;
285
  }
289
  *
290
  * @return mixed
291
  */
292
+ public function get_offset() {
293
  return $this->offset;
294
  }
295
 
299
  * @param mixed $offset - The offset.
300
  * @return self
301
  */
302
+ public function set_offset( $offset ) {
303
  $this->offset = $offset;
304
  return $this;
305
  }
310
  * @param mixed $value - Condition.
311
  * @return self
312
  */
313
+ public function add_search_condition( $value ) {
314
+ $this->search_condition = $value;
315
  return $this;
316
  }
317
 
320
  *
321
  * @return self
322
  */
323
+ public function get_search_condition() {
324
+ return $this->search_condition;
325
  }
326
 
327
  /**
329
  *
330
  * @return boolean
331
  */
332
+ public function has_meta_join() {
333
  return $this->meta_join;
334
  }
335
 
338
  *
339
  * @return self
340
  */
341
+ public function add_meta_join() {
342
  $this->meta_join = true;
343
  return $this;
344
  }
345
+
346
+ /**
347
+ * Deprecated placeholder function.
348
+ *
349
+ * @return WSAL_Adapters_QueryInterface
350
+ * @see WSAL_Models_Query::get_adapter()
351
+ *
352
+ * @deprecated 4.4.1 Replaced by function get_adapter.
353
+ */
354
+ public function getAdapter() {
355
+ return $this->get_adapter();
356
+ }
357
+
358
+ /**
359
+ * Deprecated placeholder function.
360
+ *
361
+ * @param string $field - Field name.
362
+ * @param boolean $is_descending - (Optional) Ascending/descending.
363
+ *
364
+ * @return self
365
+ * @see WSAL_Models_Query::add_order_by()
366
+ *
367
+ * @deprecated 4.4.1 Replaced by function add_order_by.
368
+ */
369
+ public function addOrderBy( $field, $is_descending = false ) {
370
+ return $this->add_order_by( $field, $is_descending );
371
+ }
372
+
373
+ /**
374
+ * Deprecated placeholder function.
375
+ *
376
+ * @param mixed $limit - The limit.
377
+ *
378
+ * @return self
379
+ * @see WSAL_Models_Query::set_limit()
380
+ *
381
+ * @deprecated 4.4.1 Replaced by function set_limit.
382
+ */
383
+ public function setLimit( $limit ) {
384
+ return $this->set_limit( $limit );
385
+ }
386
  }
classes/Models/TmpUser.php CHANGED
@@ -40,5 +40,5 @@ class WSAL_Models_TmpUser extends WSAL_Models_ActiveRecord {
40
  *
41
  * @var string
42
  */
43
- protected $adapterName = 'TmpUser';
44
  }
40
  *
41
  * @var string
42
  */
43
+ protected $adapter_name = 'TmpUser';
44
  }
classes/Nicer.php CHANGED
@@ -1,4 +1,13 @@
1
  <?php
 
 
 
 
 
 
 
 
 
2
  /**
3
  * Inspects and prints out PHP values as HTML in a nicer way than print_r().
4
  *
@@ -9,6 +18,7 @@
9
  * @version 2.0
10
  * @since 2.0
11
  * @package wsal
 
12
  */
13
  class WSAL_Nicer {
14
 
1
  <?php
2
+ /**
3
+ * WSAL_Nicer class.
4
+ *
5
+ * @since 2.0
6
+ * @package wsal
7
+ */
8
+
9
+ // phpcs:disable
10
+
11
  /**
12
  * Inspects and prints out PHP values as HTML in a nicer way than print_r().
13
  *
18
  * @version 2.0
19
  * @since 2.0
20
  * @package wsal
21
+ *
22
  */
23
  class WSAL_Nicer {
24
 
classes/Ref.php CHANGED
@@ -1,4 +1,5 @@
1
  <?php
 
2
  /**
3
  * Inspects and prints out PHP values as HTML in a nicer way than print_r().
4
  *
1
  <?php
2
+ // phpcs:ignoreFile
3
  /**
4
  * Inspects and prints out PHP values as HTML in a nicer way than print_r().
5
  *
classes/ReportArgs.php CHANGED
@@ -1,4 +1,13 @@
1
  <?php
 
 
 
 
 
 
 
 
 
2
 
3
  // Exit if accessed directly.
4
  if ( ! defined( 'ABSPATH' ) ) {
@@ -175,9 +184,11 @@ class WSAL_ReportArgs {
175
  public $post_status__not_in;
176
 
177
  /**
178
- * @param array $filters
 
 
179
  *
180
- * @return WSAL_ReportArgs
181
  */
182
  public static function build_from_alternative_filters( $filters ) {
183
  $_filters = array();
@@ -191,14 +202,16 @@ class WSAL_ReportArgs {
191
  }
192
  }
193
 
194
- return self::build_from_extension_filters( $_filters, WpSecurityAuditLog::GetInstance()->reports_util );
195
  }
196
 
197
  /**
 
 
198
  * @param array $filters An array of filters as defined in the Reports extension form.
199
  * @param WSAL_Rep_Common $report_utils Reporting utils.
200
  *
201
- * @return WSAL_ReportArgs
202
  */
203
  public static function build_from_extension_filters( $filters, $report_utils ) {
204
 
@@ -343,7 +356,7 @@ class WSAL_ReportArgs {
343
  $groups = self::is_field_present_and_non_empty_array( $groups_key, $array ) ? $array[ $groups_key ] : array();
344
  $alerts = self::is_field_present_and_non_empty_array( $codes_key, $array ) ? $array[ $codes_key ] : array();
345
 
346
- $result = $report_utils->GetCodesByGroups( $groups, $alerts, false );
347
  if ( false === $result ) {
348
  return array();
349
  }
1
  <?php
2
+ /**
3
+ * Report arguments class.
4
+ *
5
+ * @package wsal
6
+ * @subpackage reports
7
+ *
8
+ * @author Martin Krcho <martin@wpwhitesecurity.com>
9
+ * @since 4.3.2
10
+ */
11
 
12
  // Exit if accessed directly.
13
  if ( ! defined( 'ABSPATH' ) ) {
184
  public $post_status__not_in;
185
 
186
  /**
187
+ * Builds the object from alternative filters data.
188
+ *
189
+ * @param array $filters Filters data.
190
  *
191
+ * @return WSAL_ReportArgs Report args object.
192
  */
193
  public static function build_from_alternative_filters( $filters ) {
194
  $_filters = array();
202
  }
203
  }
204
 
205
+ return self::build_from_extension_filters( $_filters, WpSecurityAuditLog::get_instance()->reports_util );
206
  }
207
 
208
  /**
209
+ * Builds the object from extension filters data.
210
+ *
211
  * @param array $filters An array of filters as defined in the Reports extension form.
212
  * @param WSAL_Rep_Common $report_utils Reporting utils.
213
  *
214
+ * @return WSAL_ReportArgs Report args object.
215
  */
216
  public static function build_from_extension_filters( $filters, $report_utils ) {
217
 
356
  $groups = self::is_field_present_and_non_empty_array( $groups_key, $array ) ? $array[ $groups_key ] : array();
357
  $alerts = self::is_field_present_and_non_empty_array( $codes_key, $array ) ? $array[ $codes_key ] : array();
358
 
359
+ $result = $report_utils->get_codes_by_groups( $groups, $alerts, false );
360
  if ( false === $result ) {
361
  return array();
362
  }
classes/SensorManager.php CHANGED
@@ -4,7 +4,7 @@
4
  *
5
  * Sensor manager class file.
6
  *
7
- * @since 1.0.0
8
  * @package wsal
9
  */
10
 
@@ -38,7 +38,7 @@ final class WSAL_SensorManager extends WSAL_AbstractSensor {
38
  // Check sensors before loading for optimization.
39
  add_filter( 'wsal_before_sensor_load', array( $this, 'check_sensor_before_load' ), 10, 2 );
40
  foreach ( WSAL_Utilities_FileSystemUtils::read_files_in_folder( dirname( __FILE__ ) . '/Sensors', '*.php' ) as $file ) {
41
- $this->AddFromFile( $file );
42
  }
43
 
44
  /*
@@ -53,6 +53,7 @@ final class WSAL_SensorManager extends WSAL_AbstractSensor {
53
  foreach ( $paths as $inc_path ) {
54
  // Check directory.
55
  if ( is_dir( $inc_path ) && is_readable( $inc_path ) ) {
 
56
  foreach ( WSAL_Utilities_FileSystemUtils::read_files_in_folder( $inc_path, '*.php' ) as $file ) {
57
  // Include custom sensor file.
58
  require_once $file;
@@ -72,7 +73,7 @@ final class WSAL_SensorManager extends WSAL_AbstractSensor {
72
  * is retained for back-compat.
73
  */
74
  $class = ( class_exists( $sensor ) ) ? $sensor : 'WSAL_Sensors_' . $sensor;
75
- $this->AddFromClass( $class );
76
  }
77
  }
78
  }
@@ -81,16 +82,16 @@ final class WSAL_SensorManager extends WSAL_AbstractSensor {
81
  /**
82
  * {@inheritDoc}
83
  */
84
- public function HookEvents() {
85
  foreach ( $this->sensors as $sensor ) {
86
- $sensor->HookEvents();
87
  }
88
  }
89
 
90
  /**
91
  * Method: Get the sensors.
92
  */
93
- public function GetSensors() {
94
  return $this->sensors;
95
  }
96
 
@@ -99,7 +100,7 @@ final class WSAL_SensorManager extends WSAL_AbstractSensor {
99
  *
100
  * @param string $file Path to file.
101
  */
102
- public function AddFromFile( $file ) {
103
  /**
104
  * Filter: `wsal_before_sensor_load`
105
  *
@@ -112,7 +113,7 @@ final class WSAL_SensorManager extends WSAL_AbstractSensor {
112
 
113
  // Initiate the sensor if $load_sensor is true.
114
  if ( $load_sensor ) {
115
- $this->AddFromClass( $this->plugin->GetClassFileClassName( $file ) );
116
  }
117
  }
118
 
@@ -121,8 +122,8 @@ final class WSAL_SensorManager extends WSAL_AbstractSensor {
121
  *
122
  * @param string $class Class name.
123
  */
124
- public function AddFromClass( $class ) {
125
- $this->AddInstance( new $class( $this->plugin ) );
126
  }
127
 
128
  /**
@@ -130,7 +131,7 @@ final class WSAL_SensorManager extends WSAL_AbstractSensor {
130
  *
131
  * @param WSAL_AbstractSensor $sensor The new sensor.
132
  */
133
- public function AddInstance( WSAL_AbstractSensor $sensor ) {
134
  $this->sensors[] = $sensor;
135
  }
136
 
@@ -143,7 +144,7 @@ final class WSAL_SensorManager extends WSAL_AbstractSensor {
143
  */
144
  public function check_sensor_before_load( $load_sensor, $filepath ) {
145
  global $pagenow;
146
- if ( ! $this->plugin->IsMultisite() ) {
147
  $admin_page = $pagenow;
148
  } else {
149
  /**
@@ -189,14 +190,14 @@ final class WSAL_SensorManager extends WSAL_AbstractSensor {
189
 
190
  // Only LogInOut and Register sensors should load on login page.
191
  if ( WpSecurityAuditLog::is_login_screen() ) {
192
- if ( in_array( $filename, array( 'Register', 'LogInOut' ) ) ) {
193
  return true;
194
  }
195
  return false; // Any other sensor should not load here.
196
  }
197
 
198
  $default_public_sensors = array( 'Register', 'LogInOut' );
199
- if ( $this->plugin->IsMultisite() ) {
200
  // Multisite sign-up is happening on front-end.
201
  array_push( $default_public_sensors, 'MultisiteSignUp' );
202
  }
@@ -256,7 +257,7 @@ final class WSAL_SensorManager extends WSAL_AbstractSensor {
256
 
257
  case 'Multisite':
258
  // If site is not multisite then don't load it.
259
- if ( ! $this->plugin->IsMultisite() ) {
260
  $load_sensor = false;
261
  }
262
  break;
4
  *
5
  * Sensor manager class file.
6
  *
7
+ * @since 1.0.0
8
  * @package wsal
9
  */
10
 
38
  // Check sensors before loading for optimization.
39
  add_filter( 'wsal_before_sensor_load', array( $this, 'check_sensor_before_load' ), 10, 2 );
40
  foreach ( WSAL_Utilities_FileSystemUtils::read_files_in_folder( dirname( __FILE__ ) . '/Sensors', '*.php' ) as $file ) {
41
+ $this->add_from_file( $file );
42
  }
43
 
44
  /*
53
  foreach ( $paths as $inc_path ) {
54
  // Check directory.
55
  if ( is_dir( $inc_path ) && is_readable( $inc_path ) ) {
56
+ $inc_path = trailingslashit( $inc_path );
57
  foreach ( WSAL_Utilities_FileSystemUtils::read_files_in_folder( $inc_path, '*.php' ) as $file ) {
58
  // Include custom sensor file.
59
  require_once $file;
73
  * is retained for back-compat.
74
  */
75
  $class = ( class_exists( $sensor ) ) ? $sensor : 'WSAL_Sensors_' . $sensor;
76
+ $this->add_from_class( $class );
77
  }
78
  }
79
  }
82
  /**
83
  * {@inheritDoc}
84
  */
85
+ public function hook_events() {
86
  foreach ( $this->sensors as $sensor ) {
87
+ $sensor->hook_events();
88
  }
89
  }
90
 
91
  /**
92
  * Method: Get the sensors.
93
  */
94
+ public function get_sensors() {
95
  return $this->sensors;
96
  }
97
 
100
  *
101
  * @param string $file Path to file.
102
  */
103
+ public function add_from_file( $file ) {
104
  /**
105
  * Filter: `wsal_before_sensor_load`
106
  *
113
 
114
  // Initiate the sensor if $load_sensor is true.
115
  if ( $load_sensor ) {
116
+ $this->add_from_class( $this->plugin->autoloader->get_class_file_class_name( $file ) );
117
  }
118
  }
119
 
122
  *
123
  * @param string $class Class name.
124
  */
125
+ public function add_from_class( $class ) {
126
+ $this->add_instance( new $class( $this->plugin ) );
127
  }
128
 
129
  /**
131
  *
132
  * @param WSAL_AbstractSensor $sensor The new sensor.
133
  */
134
+ public function add_instance( $sensor ) {
135
  $this->sensors[] = $sensor;
136
  }
137
 
144
  */
145
  public function check_sensor_before_load( $load_sensor, $filepath ) {
146
  global $pagenow;
147
+ if ( ! $this->plugin->is_multisite() ) {
148
  $admin_page = $pagenow;
149
  } else {
150
  /**
190
 
191
  // Only LogInOut and Register sensors should load on login page.
192
  if ( WpSecurityAuditLog::is_login_screen() ) {
193
+ if ( in_array( $filename, array( 'Register', 'LogInOut' ), true ) ) {
194
  return true;
195
  }
196
  return false; // Any other sensor should not load here.
197
  }
198
 
199
  $default_public_sensors = array( 'Register', 'LogInOut' );
200
+ if ( $this->plugin->is_multisite() ) {
201
  // Multisite sign-up is happening on front-end.
202
  array_push( $default_public_sensors, 'MultisiteSignUp' );
203
  }
257
 
258
  case 'Multisite':
259
  // If site is not multisite then don't load it.
260
+ if ( ! $this->plugin->is_multisite() ) {
261
  $load_sensor = false;
262
  }
263
  break;
classes/Sensors/ACFMeta.php CHANGED
@@ -4,7 +4,7 @@
4
  *
5
  * Advanced Custom Fields sensor file.
6
  *
7
- * @since 4.1.3
8
  * @package wsal
9
  */
10
 
@@ -19,9 +19,9 @@ if ( ! defined( 'ABSPATH' ) ) {
19
  * 2131 ACF relationship added
20
  * 2132 ACF relationship removed
21
  *
22
- * @package wsal
23
  * @subpackage sensors
24
- * @since 4.1.3
25
  */
26
  class WSAL_Sensors_ACFMeta extends WSAL_AbstractMetaDataSensor {
27
 
@@ -35,32 +35,32 @@ class WSAL_Sensors_ACFMeta extends WSAL_AbstractMetaDataSensor {
35
  /**
36
  * Listening to events using WP hooks.
37
  */
38
- public function HookEvents() {
39
- add_filter( "acf/pre_update_value", array( $this, 'prepare_relationship_update_check' ), 10, 4 );
40
 
41
- // relationship field is only available for posts to we don't need to check other meta types (comment, term, or user)
42
- add_action( "updated_post_meta", array( $this, 'on_field_updated' ), 10, 4 );
43
- add_action( "deleted_post_meta", array( $this, 'on_field_updated' ), 10, 4 );
44
  }
45
 
46
  /**
47
  * Runs before an ACF field value is updated. It stores locally information
48
  * about relationship fields that are being updated.
49
  *
50
- * @param mixed $check
51
- * @param mixed $value
52
- * @param int $post_id
53
- * @param array $field
54
  *
55
  * @return mixed
56
  */
57
  public function prepare_relationship_update_check( $check, $value, $post_id, $field ) {
58
- if ( 'relationship' == $field['type'] ) {
59
- $this->old_meta[ $field['name'] ] = [
60
  'field' => $field,
61
  'value' => get_field( $field['name'] ),
62
- 'post_id' => $post_id
63
- ];
64
  }
65
 
66
  return $check;
@@ -69,14 +69,14 @@ class WSAL_Sensors_ACFMeta extends WSAL_AbstractMetaDataSensor {
69
  /**
70
  * Fires immediately after updating metadata of a specific type.
71
  *
72
- * @param int $meta_id ID of updated metadata entry.
73
- * @param int $object_id ID of the object metadata is for.
74
  * @param string $meta_key Metadata key.
75
- * @param mixed $_meta_value Metadata value. Serialized if non-scalar.
76
  */
77
  public function on_field_updated( $meta_id, $object_id, $meta_key, $_meta_value ) {
78
- if ( in_array( $meta_key, array_keys( $this->old_meta ) ) ) {
79
- if ( $this->CanLogMetaKey( 'post', $object_id, $meta_key ) ) {
80
  $old_value = $this->convert_to_array_of_post_ids( $this->old_meta[ $meta_key ]['value'] );
81
  $new_value = $this->convert_to_array_of_post_ids( $_meta_value );
82
  $removed = array_diff( $old_value, $new_value );
@@ -101,11 +101,14 @@ class WSAL_Sensors_ACFMeta extends WSAL_AbstractMetaDataSensor {
101
  * @return int[]
102
  */
103
  private function convert_to_array_of_post_ids( $value ) {
104
- $result = [];
105
  if ( is_array( $value ) ) {
106
- $result = array_map( function ( $item ) {
107
- return ( $item instanceof WP_Post ) ? $item->ID : intval( $item );
108
- }, $value );
 
 
 
109
  }
110
 
111
  return $result;
@@ -114,16 +117,16 @@ class WSAL_Sensors_ACFMeta extends WSAL_AbstractMetaDataSensor {
114
  /**
115
  * Log event related to ACF relationship field.
116
  *
117
- * @param int $event_id
118
- * @param int[]|WP_Post[] $relationship_post_ids
119
- * @param int $object_id
120
- * @param string $meta_key
121
- * @param int $meta_id
122
  */
123
  private function log_event( $event_id, $relationship_post_ids, $object_id, $meta_key, $meta_id ) {
124
  $post = get_post( $object_id );
125
- $editor_link = $this->GetEditorLink( $object_id );
126
- $this->plugin->alerts->Trigger(
127
  $event_id,
128
  array(
129
  'PostID' => $object_id,
@@ -144,13 +147,19 @@ class WSAL_Sensors_ACFMeta extends WSAL_AbstractMetaDataSensor {
144
  /**
145
  * Formats the relationship label for the activity log entry.
146
  *
147
- * @param int[] $post_ids
148
  *
149
  * @return string
150
  */
151
  private function format_relationships_label( $post_ids ) {
152
- return implode( ', ', array_map( function ( $post_id ) {
153
- return get_the_title( $post_id ) . ' (' . $post_id . ')';
154
- }, $post_ids ) );
 
 
 
 
 
 
155
  }
156
  }
4
  *
5
  * Advanced Custom Fields sensor file.
6
  *
7
+ * @since 4.1.3
8
  * @package wsal
9
  */
10
 
19
  * 2131 ACF relationship added
20
  * 2132 ACF relationship removed
21
  *
22
+ * @package wsal
23
  * @subpackage sensors
24
+ * @since 4.1.3
25
  */
26
  class WSAL_Sensors_ACFMeta extends WSAL_AbstractMetaDataSensor {
27
 
35
  /**
36
  * Listening to events using WP hooks.
37
  */
38
+ public function hook_events() {
39
+ add_filter( 'acf/pre_update_value', array( $this, 'prepare_relationship_update_check' ), 10, 4 );
40
 
41
+ // Relationship field is only available for posts to we don't need to check other meta types (comment, term, or user).
42
+ add_action( 'updated_post_meta', array( $this, 'on_field_updated' ), 10, 4 );
43
+ add_action( 'deleted_post_meta', array( $this, 'on_field_updated' ), 10, 4 );
44
  }
45
 
46
  /**
47
  * Runs before an ACF field value is updated. It stores locally information
48
  * about relationship fields that are being updated.
49
  *
50
+ * @param mixed $check Variable allowing short-circuiting of update_value logic.
51
+ * @param mixed $value The new value.
52
+ * @param int|string $post_id The post id.
53
+ * @param array $field The field array.
54
  *
55
  * @return mixed
56
  */
57
  public function prepare_relationship_update_check( $check, $value, $post_id, $field ) {
58
+ if ( 'relationship' === $field['type'] ) {
59
+ $this->old_meta[ $field['name'] ] = array(
60
  'field' => $field,
61
  'value' => get_field( $field['name'] ),
62
+ 'post_id' => $post_id,
63
+ );
64
  }
65
 
66
  return $check;
69
  /**
70
  * Fires immediately after updating metadata of a specific type.
71
  *
72
+ * @param int $meta_id ID of updated metadata entry.
73
+ * @param int $object_id ID of the object metadata is for.
74
  * @param string $meta_key Metadata key.
75
+ * @param mixed $_meta_value Metadata value. Serialized if non-scalar.
76
  */
77
  public function on_field_updated( $meta_id, $object_id, $meta_key, $_meta_value ) {
78
+ if ( in_array( $meta_key, array_keys( $this->old_meta ) ) ) { // phpcs:ignore
79
+ if ( $this->can_log_meta_key( 'post', $object_id, $meta_key ) ) {
80
  $old_value = $this->convert_to_array_of_post_ids( $this->old_meta[ $meta_key ]['value'] );
81
  $new_value = $this->convert_to_array_of_post_ids( $_meta_value );
82
  $removed = array_diff( $old_value, $new_value );
101
  * @return int[]
102
  */
103
  private function convert_to_array_of_post_ids( $value ) {
104
+ $result = array();
105
  if ( is_array( $value ) ) {
106
+ $result = array_map(
107
+ function ( $item ) {
108
+ return ( $item instanceof WP_Post ) ? $item->ID : intval( $item );
109
+ },
110
+ $value
111
+ );
112
  }
113
 
114
  return $result;
117
  /**
118
  * Log event related to ACF relationship field.
119
  *
120
+ * @param int $event_id Event ID.
121
+ * @param int[]|WP_Post[] $relationship_post_ids Posts or post IDs.
122
+ * @param int $object_id Object ID.
123
+ * @param string $meta_key Meta key.
124
+ * @param int $meta_id Meta ID.
125
  */
126
  private function log_event( $event_id, $relationship_post_ids, $object_id, $meta_key, $meta_id ) {
127
  $post = get_post( $object_id );
128
+ $editor_link = $this->get_editor_link( $object_id );
129
+ $this->plugin->alerts->trigger_event(
130
  $event_id,
131
  array(
132
  'PostID' => $object_id,
147
  /**
148
  * Formats the relationship label for the activity log entry.
149
  *
150
+ * @param int[] $post_ids List of post IDs.
151
  *
152
  * @return string
153
  */
154
  private function format_relationships_label( $post_ids ) {
155
+ return implode(
156
+ ', ',
157
+ array_map(
158
+ function ( $post_id ) {
159
+ return get_the_title( $post_id ) . ' (' . $post_id . ')';
160
+ },
161
+ $post_ids
162
+ )
163
+ );
164
  }
165
  }
classes/Sensors/Comments.php CHANGED
@@ -4,8 +4,9 @@
4
  *
5
  * Comments sensor class file.
6
  *
7
- * @since 1.0.0
8
- * @package wsal
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -27,23 +28,23 @@ if ( ! defined( 'ABSPATH' ) ) {
27
  * 2098 User permanently deleted a comment
28
  * 2099 User posted a comment
29
  *
30
- * @package wsal
31
  * @subpackage sensors
32
  */
33
  class WSAL_Sensors_Comments extends WSAL_AbstractSensor {
34
 
35
  /**
36
- * Listening to events using WP hooks.
37
  */
38
- public function HookEvents() {
39
- add_action( 'edit_comment', array( $this, 'EventCommentEdit' ), 10, 1 );
40
- add_action( 'transition_comment_status', array( $this, 'EventCommentApprove' ), 10, 3 );
41
- add_action( 'spammed_comment', array( $this, 'EventCommentSpam' ), 10, 1 );
42
- add_action( 'unspammed_comment', array( $this, 'EventCommentUnspam' ), 10, 1 );
43
- add_action( 'trashed_comment', array( $this, 'EventCommentTrash' ), 10, 1 );
44
- add_action( 'untrashed_comment', array( $this, 'EventCommentUntrash' ), 10, 1 );
45
- add_action( 'deleted_comment', array( $this, 'EventCommentDeleted' ), 10, 1 );
46
- add_action( 'comment_post', array( $this, 'EventComment' ), 10, 3 );
47
  }
48
 
49
  /**
@@ -51,7 +52,7 @@ class WSAL_Sensors_Comments extends WSAL_AbstractSensor {
51
  *
52
  * @param integer $comment_id - Comment ID.
53
  */
54
- public function EventCommentEdit( $comment_id ) {
55
  $this->EventGeneric( $comment_id, 2093 );
56
  }
57
 
@@ -62,7 +63,7 @@ class WSAL_Sensors_Comments extends WSAL_AbstractSensor {
62
  * @param string $old_status - Old status.
63
  * @param stdClass $comment - Comment.
64
  */
65
- public function EventCommentApprove( $new_status, $old_status, $comment ) {
66
  if ( ! empty( $comment ) && $old_status !== $new_status ) {
67
  $post = get_post( $comment->comment_post_ID );
68
  $comment_link = get_permalink( $post->ID ) . '#comment-' . $comment->comment_ID;
@@ -78,10 +79,10 @@ class WSAL_Sensors_Comments extends WSAL_AbstractSensor {
78
  );
79
 
80
  if ( 'approved' === $new_status ) {
81
- $this->plugin->alerts->Trigger( 2090, $fields );
82
  }
83
  if ( 'unapproved' === $new_status ) {
84
- $this->plugin->alerts->Trigger( 2091, $fields );
85
  }
86
  }
87
  }
@@ -91,7 +92,7 @@ class WSAL_Sensors_Comments extends WSAL_AbstractSensor {
91
  *
92
  * @param integer $comment_id - Comment ID.
93
  */
94
- public function EventCommentSpam( $comment_id ) {
95
  $this->EventGeneric( $comment_id, 2094 );
96
  }
97
 
@@ -100,7 +101,7 @@ class WSAL_Sensors_Comments extends WSAL_AbstractSensor {
100
  *
101
  * @param integer $comment_id - Comment ID.
102
  */
103
- public function EventCommentUnspam( $comment_id ) {
104
  $this->EventGeneric( $comment_id, 2095 );
105
  }
106
 
@@ -109,7 +110,7 @@ class WSAL_Sensors_Comments extends WSAL_AbstractSensor {
109
  *
110
  * @param integer $comment_id - Comment ID.
111
  */
112
- public function EventCommentTrash( $comment_id ) {
113
  $this->EventGeneric( $comment_id, 2096 );
114
  }
115
 
@@ -118,7 +119,7 @@ class WSAL_Sensors_Comments extends WSAL_AbstractSensor {
118
  *
119
  * @param integer $comment_id comment ID.
120
  */
121
- public function EventCommentUntrash( $comment_id ) {
122
  $this->EventGeneric( $comment_id, 2097 );
123
  }
124
 
@@ -127,7 +128,7 @@ class WSAL_Sensors_Comments extends WSAL_AbstractSensor {
127
  *
128
  * @param integer $comment_id comment ID.
129
  */
130
- public function EventCommentDeleted( $comment_id ) {
131
  $this->EventGeneric( $comment_id, 2098 );
132
  }
133
 
@@ -138,7 +139,7 @@ class WSAL_Sensors_Comments extends WSAL_AbstractSensor {
138
  * @param int|string $comment_approved 1 if the comment is approved, 0 if not, 'spam' if spam.
139
  * @param array $comment_data Comment data.
140
  */
141
- public function EventComment( $comment_id, $comment_approved, $comment_data ) {
142
  // Check if the comment is response to another comment.
143
  if ( isset( $comment_data['comment_parent'] ) && $comment_data['comment_parent'] ) {
144
  $this->EventGeneric( $comment_id, 2092 );
@@ -157,7 +158,7 @@ class WSAL_Sensors_Comments extends WSAL_AbstractSensor {
157
  'PostStatus' => $post->post_status,
158
  'CommentID' => $comment->comment_ID,
159
  'Date' => $comment->comment_date,
160
- 'CommentLink' => $comment_link
161
  );
162
 
163
  // Get user data.
@@ -175,7 +176,7 @@ class WSAL_Sensors_Comments extends WSAL_AbstractSensor {
175
  // Set the fields.
176
  $fields['Username'] = $user_data->user_login;
177
  $fields['CurrentUserRoles'] = $user_roles;
178
- $this->plugin->alerts->Trigger( 2099, $fields );
179
  }
180
  }
181
  }
@@ -205,7 +206,7 @@ class WSAL_Sensors_Comments extends WSAL_AbstractSensor {
205
  );
206
 
207
  if ( 'shop_order' !== $post->post_type ) {
208
- $this->plugin->alerts->Trigger( $alert_code, $fields );
209
  }
210
  }
211
  }
4
  *
5
  * Comments sensor class file.
6
  *
7
+ * @since 1.0.0
8
+ * @package wsal
9
+ * @subpachae sensors
10
  */
11
 
12
  // Exit if accessed directly.
28
  * 2098 User permanently deleted a comment
29
  * 2099 User posted a comment
30
  *
31
+ * @package wsal
32
  * @subpackage sensors
33
  */
34
  class WSAL_Sensors_Comments extends WSAL_AbstractSensor {
35
 
36
  /**
37
+ * {@inheritDoc}
38
  */
39
+ public function hook_events() {
40
+ add_action( 'edit_comment', array( $this, 'event_comment_edit' ), 10, 1 );
41
+ add_action( 'transition_comment_status', array( $this, 'event_comment_approve' ), 10, 3 );
42
+ add_action( 'spammed_comment', array( $this, 'event_comment_spam' ), 10, 1 );
43
+ add_action( 'unspammed_comment', array( $this, 'event_comment_unspam' ), 10, 1 );
44
+ add_action( 'trashed_comment', array( $this, 'event_comment_trash' ), 10, 1 );
45
+ add_action( 'untrashed_comment', array( $this, 'event_comment_untrash' ), 10, 1 );
46
+ add_action( 'deleted_comment', array( $this, 'event_comment_deleted' ), 10, 1 );
47
+ add_action( 'comment_post', array( $this, 'event_comment' ), 10, 3 );
48
  }
49
 
50
  /**
52
  *
53
  * @param integer $comment_id - Comment ID.
54
  */
55
+ public function event_comment_edit( $comment_id ) {
56
  $this->EventGeneric( $comment_id, 2093 );
57
  }
58
 
63
  * @param string $old_status - Old status.
64
  * @param stdClass $comment - Comment.
65
  */
66
+ public function event_comment_approve( $new_status, $old_status, $comment ) {
67
  if ( ! empty( $comment ) && $old_status !== $new_status ) {
68
  $post = get_post( $comment->comment_post_ID );
69
  $comment_link = get_permalink( $post->ID ) . '#comment-' . $comment->comment_ID;
79
  );
80
 
81
  if ( 'approved' === $new_status ) {
82
+ $this->plugin->alerts->trigger_event( 2090, $fields );
83
  }
84
  if ( 'unapproved' === $new_status ) {
85
+ $this->plugin->alerts->trigger_event( 2091, $fields );
86
  }
87
  }
88
  }
92
  *
93
  * @param integer $comment_id - Comment ID.
94
  */
95
+ public function event_comment_spam( $comment_id ) {
96
  $this->EventGeneric( $comment_id, 2094 );
97
  }
98
 
101
  *
102
  * @param integer $comment_id - Comment ID.
103
  */
104
+ public function event_comment_unspam( $comment_id ) {
105
  $this->EventGeneric( $comment_id, 2095 );
106
  }
107
 
110
  *
111
  * @param integer $comment_id - Comment ID.
112
  */
113
+ public function event_comment_trash( $comment_id ) {
114
  $this->EventGeneric( $comment_id, 2096 );
115
  }
116
 
119
  *
120
  * @param integer $comment_id comment ID.
121
  */
122
+ public function event_comment_untrash( $comment_id ) {
123
  $this->EventGeneric( $comment_id, 2097 );
124
  }
125
 
128
  *
129
  * @param integer $comment_id comment ID.
130
  */
131
+ public function event_comment_deleted( $comment_id ) {
132
  $this->EventGeneric( $comment_id, 2098 );
133
  }
134
 
139
  * @param int|string $comment_approved 1 if the comment is approved, 0 if not, 'spam' if spam.
140
  * @param array $comment_data Comment data.
141
  */
142
+ public function event_comment( $comment_id, $comment_approved, $comment_data ) {
143
  // Check if the comment is response to another comment.
144
  if ( isset( $comment_data['comment_parent'] ) && $comment_data['comment_parent'] ) {
145
  $this->EventGeneric( $comment_id, 2092 );
158
  'PostStatus' => $post->post_status,
159
  'CommentID' => $comment->comment_ID,
160
  'Date' => $comment->comment_date,
161
+ 'CommentLink' => $comment_link,
162
  );
163
 
164
  // Get user data.
176
  // Set the fields.
177
  $fields['Username'] = $user_data->user_login;
178
  $fields['CurrentUserRoles'] = $user_roles;
179
+ $this->plugin->alerts->trigger_event( 2099, $fields );
180
  }
181
  }
182
  }
206
  );
207
 
208
  if ( 'shop_order' !== $post->post_type ) {
209
+ $this->plugin->alerts->trigger_event( $alert_code, $fields );
210
  }
211
  }
212
  }
classes/Sensors/Content.php CHANGED
@@ -4,8 +4,9 @@
4
  *
5
  * Content sensor class file.
6
  *
7
- * @since 1.0.0
8
- * @package wsal
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -20,7 +21,8 @@ if ( ! defined( 'ABSPATH' ) ) {
20
  * 5019 A plugin created a post
21
  * 5025 A plugin deleted a post
22
  *
23
- * @package wsal
 
24
  */
25
  class WSAL_Sensors_Content extends WSAL_AbstractSensor {
26
 
@@ -29,42 +31,42 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
29
  *
30
  * @var stdClass
31
  */
32
- protected $_old_post = null;
33
 
34
  /**
35
  * Old permalink.
36
  *
37
  * @var string
38
  */
39
- protected $_old_link = null;
40
 
41
  /**
42
  * Old categories.
43
  *
44
  * @var array
45
  */
46
- protected $_old_cats = null;
47
 
48
  /**
49
  * Old tags.
50
  *
51
  * @var array
52
  */
53
- protected $_old_tags = null;
54
 
55
  /**
56
  * Old path to file.
57
  *
58
  * @var string
59
  */
60
- protected $_old_tmpl = null;
61
 
62
  /**
63
  * Old post is marked as sticky.
64
  *
65
  * @var boolean
66
  */
67
- protected $_old_stky = null;
68
 
69
  /**
70
  * Old Post Status.
@@ -81,9 +83,9 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
81
  protected $old_meta = null;
82
 
83
  /**
84
- * Listening to events using WP hooks.
85
  */
86
- public function HookEvents() {
87
  add_action( 'pre_post_update', array( $this, 'get_before_post_edit_data' ), 10, 2 );
88
  add_action( 'save_post', array( $this, 'post_changed' ), 10, 3 );
89
  add_action( 'set_object_terms', array( $this, 'post_terms_changed' ), 10, 4 );
@@ -123,12 +125,12 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
123
 
124
  // If post exists.
125
  if ( ! empty( $post ) && $post instanceof WP_Post ) {
126
- $this->_old_post = $post;
127
- $this->_old_link = get_permalink( $post_id );
128
- $this->_old_tmpl = $this->get_post_template( $this->_old_post );
129
- $this->_old_cats = $this->get_post_categories( $this->_old_post );
130
- $this->_old_tags = $this->get_post_tags( $this->_old_post );
131
- $this->_old_stky = in_array( $post_id, get_option( 'sticky_posts' ), true );
132
  $this->old_status = $post->post_status;
133
  $this->old_meta = get_post_meta( $post_id );
134
  }
@@ -155,8 +157,8 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
155
  // Ignorable states.
156
  if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
157
  // Check post creation event.
158
- if ( $this->_old_post && 'auto-draft' === $this->_old_post->post_status && 'draft' === $post->post_status ) {
159
- $this->check_post_creation( $this->_old_post, $post );
160
  }
161
  return;
162
  }
@@ -191,28 +193,28 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
191
  }
192
 
193
  if ( $update ) {
194
- $status_event = $this->check_status_change( $this->_old_post, $post );
195
 
196
- if ( 2001 !== $status_event && 'auto-draft' !== $this->_old_post->post_status ) {
197
  // Handle update post events.
198
  $changes = 0;
199
- $changes = $this->check_author_change( $this->_old_post, $post )
200
- + $this->check_parent_change( $this->_old_post, $post )
201
- + $this->check_visibility_change( $this->_old_post, $post, $this->old_status, $post->post_status )
202
- + $this->check_date_change( $this->_old_post, $post )
203
- + $this->check_permalink_change( $this->_old_link, get_permalink( $post->ID ), $post )
204
- + $this->check_comments_pings( $this->_old_post, $post );
205
 
206
  // If a status change event has occurred, then don't log event 2002 (post modified).
207
  $changes = $status_event ? true : $changes;
208
  if ( '1' === $changes ) {
209
  remove_action( 'save_post', array( $this, 'post_changed' ), 10, 3 );
210
  }
211
- $this->check_modification_change( $post->ID, $this->_old_post, $post, $changes );
212
  }
213
  } else {
214
  // If not update then check post creation.
215
- $this->check_post_creation( $this->_old_post, $post );
216
  }
217
  }
218
 
@@ -246,10 +248,10 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
246
 
247
  if ( 'post_tag' === $taxonomy ) {
248
  // Check tags change event.
249
- $this->check_tags_change( $this->_old_tags, $this->get_post_tags( $post ), $post );
250
  } else {
251
  // Check categories change event.
252
- $this->check_categories_change( $this->_old_cats, $this->get_post_categories( $post ), $post );
253
  }
254
  }
255
 
@@ -303,7 +305,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
303
  );
304
  }
305
 
306
- $this->plugin->alerts->Trigger( $event, $event_data ); // Log event.
307
  }
308
  }
309
 
@@ -317,7 +319,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
317
  if ( ! in_array( $post->post_type, $this->plugin->alerts->ignored_cpts, true ) ) {
318
  $editor_link = $this->get_editor_link( $post );
319
 
320
- $this->plugin->alerts->Trigger(
321
  2012,
322
  array(
323
  'PostID' => $post->ID,
@@ -342,7 +344,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
342
  if ( ! in_array( $post->post_type, $this->plugin->alerts->ignored_cpts, true ) ) {
343
  $editor_link = $this->get_editor_link( $post );
344
 
345
- $this->plugin->alerts->Trigger(
346
  2014,
347
  array(
348
  'PostID' => $post->ID,
@@ -369,7 +371,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
369
  if ( ! in_array( $post->post_type, $this->plugin->alerts->ignored_cpts, true ) ) {
370
  $editor_link = $this->get_editor_link( $post );
371
 
372
- $this->plugin->alerts->Trigger(
373
  2001,
374
  array(
375
  'PostID' => $post->ID,
@@ -397,9 +399,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
397
  return;
398
  }
399
 
400
- // @codingStandardsIgnoreStart
401
- $post_id = isset( $_GET['post'] ) ? (int) sanitize_text_field( wp_unslash( $_GET['post'] ) ) : false;
402
- // @codingStandardsIgnoreEnd
403
 
404
  // Check post id.
405
  if ( empty( $post_id ) ) {
@@ -454,14 +454,14 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
454
  $post_data = $this->get_post_event_data( $post ); // Get event post data.
455
 
456
  // Update post URL based on current actual path.
457
- if ( $this->plugin->IsMultisite() && ! is_subdomain_install() ) {
458
  // For multisite using subfolders, remove the subfolder.
459
- $subdir_path = parse_url( home_url(), PHP_URL_PATH );
460
- $escaped = str_replace( '/', '\/', preg_quote( $subdir_path ) );
461
  $current_path = preg_replace( '/' . $escaped . '/', '', $current_path );
462
  }
463
 
464
- // Bail if this dont have this, as its probably an archive.
465
  if ( ! isset( $post_data['PostUrl'] ) ) {
466
  return;
467
  }
@@ -473,7 +473,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
473
 
474
  // Set editor link.
475
  $post_data[ $edit_link['name'] ] = $edit_link['value'];
476
- $this->plugin->alerts->Trigger( 2101, $post_data );
477
  }
478
  }
479
  }
@@ -486,7 +486,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
486
  public function event_category_creation( $category_id ) {
487
  $category = get_category( $category_id );
488
  $category_link = $this->get_taxonomy_edit_link( $category_id, 'category' );
489
- $this->plugin->alerts->Trigger(
490
  2023,
491
  array(
492
  'CategoryName' => $category->name,
@@ -504,7 +504,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
504
  public function event_tag_creation( $tag_id ) {
505
  $tag = get_tag( $tag_id );
506
  $tag_link = $this->get_taxonomy_edit_link( $tag_id );
507
- $this->plugin->alerts->Trigger(
508
  2121,
509
  array(
510
  'TagName' => $tag->name,
@@ -523,7 +523,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
523
  public function check_taxonomy_term_deletion( $term_id, $taxonomy ) {
524
  if ( 'post_tag' === $taxonomy ) {
525
  $tag = get_tag( $term_id );
526
- $this->plugin->alerts->Trigger(
527
  2122,
528
  array(
529
  'TagID' => $term_id,
@@ -534,7 +534,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
534
  } elseif ( 'category' === $taxonomy ) {
535
  $category = get_category( $term_id );
536
  $category_link = $this->get_taxonomy_edit_link( $term_id, $taxonomy );
537
- $this->plugin->alerts->Trigger(
538
  2024,
539
  array(
540
  'CategoryID' => $term_id,
@@ -573,7 +573,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
573
  if ( 'post_tag' === $taxonomy ) {
574
  // Update if both names are not same.
575
  if ( $old_name !== $new_name ) {
576
- $this->plugin->alerts->Trigger(
577
  2123,
578
  array(
579
  'old_name' => $old_name,
@@ -586,7 +586,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
586
 
587
  // Update if both slugs are not same.
588
  if ( $old_slug !== $new_slug ) {
589
- $this->plugin->alerts->Trigger(
590
  2124,
591
  array(
592
  'tag' => $new_name,
@@ -599,7 +599,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
599
 
600
  // Update if both descriptions are not same.
601
  if ( $old_desc !== $new_desc ) {
602
- $this->plugin->alerts->Trigger(
603
  2125,
604
  array(
605
  'tag' => $new_name,
@@ -612,7 +612,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
612
  } elseif ( 'category' === $taxonomy ) { // Check if the taxonomy is `category`.
613
  // Log event if both names are not same.
614
  if ( $old_name !== $new_name ) {
615
- $this->plugin->alerts->Trigger(
616
  2127,
617
  array(
618
  'old_name' => $old_name,
@@ -625,7 +625,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
625
 
626
  // Log event if both slugs are not same.
627
  if ( $old_slug !== $new_slug ) {
628
- $this->plugin->alerts->Trigger(
629
  2128,
630
  array(
631
  'CategoryName' => $new_name,
@@ -650,7 +650,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
650
  }
651
 
652
  if ( $old_parent_name !== $new_parent_name ) {
653
- $this->plugin->alerts->Trigger(
654
  2052,
655
  array(
656
  'CategoryName' => $new_name,
@@ -752,11 +752,11 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
752
  */
753
  public function check_template_change( $post_id, $meta_value ) {
754
  $post = get_post( $post_id );
755
- $old_tmpl = ( $this->_old_tmpl && 'page' !== basename( $this->_old_tmpl, '.php' ) ) ? ucwords( str_replace( array( '-', '_' ), ' ', basename( $this->_old_tmpl, '.php' ) ) ) : __( 'Default template', 'wp-security-audit-log' );
756
  $new_tmpl = ( $meta_value ) ? ucwords( str_replace( array( '-', '_' ), ' ', basename( $meta_value ) ) ) : __( 'Default', 'wp-security-audit-log' );
757
  if ( $old_tmpl !== $new_tmpl ) {
758
  $editor_link = $this->get_editor_link( $post );
759
- $this->plugin->alerts->Trigger(
760
  2048,
761
  array(
762
  'PostID' => $post->ID,
@@ -799,7 +799,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
799
 
800
  $post = get_post( $post_id );
801
  $editor_link = $this->get_editor_link( $post );
802
- $this->plugin->alerts->Trigger(
803
  2130,
804
  array(
805
  'PostID' => $post->ID,
@@ -833,12 +833,12 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
833
 
834
  // If post exists.
835
  if ( ! empty( $post ) ) {
836
- $this->_old_post = $post;
837
- $this->_old_link = get_permalink( $post_id );
838
- $this->_old_tmpl = $this->get_post_template( $this->_old_post );
839
- $this->_old_cats = $this->get_post_categories( $this->_old_post );
840
- $this->_old_tags = $this->get_post_tags( $this->_old_post );
841
- $this->_old_stky = in_array( $post_id, get_option( 'sticky_posts' ), true );
842
  }
843
  }
844
  }
@@ -931,7 +931,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
931
 
932
  if ( $is_scheduled ) {
933
  $event_data['PublishingDate'] = $new_post->post_date;
934
- $this->plugin->alerts->Trigger( $event, $event_data );
935
  } else {
936
 
937
  // So far we assume that the action is initiated by a user, let's check if it was actually initiated
@@ -952,7 +952,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
952
  );
953
  }
954
 
955
- $this->plugin->alerts->Trigger( $event, $event_data );
956
  }
957
  }
958
  }
@@ -962,6 +962,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
962
  * Get editor link.
963
  *
964
  * @param stdClass $post - The post.
 
965
  * @return array $editor_link - Name and value link.
966
  */
967
  private function get_editor_link( $post ) {
@@ -1008,7 +1009,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1008
  $old_author = ( is_object( $old_author ) ) ? $old_author->user_login : 'N/A';
1009
  $new_author = get_userdata( $newpost->post_author );
1010
  $new_author = ( is_object( $new_author ) ) ? $new_author->user_login : 'N/A';
1011
- $this->plugin->alerts->Trigger(
1012
  2019,
1013
  array(
1014
  'PostID' => $oldpost->ID,
@@ -1060,14 +1061,14 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1060
 
1061
  if ( $is_scheduled ) {
1062
  $event_data['PublishingDate'] = $newpost->post_date;
1063
- $this->plugin->alerts->Trigger( $event, $event_data );
1064
  } elseif ( 2021 === $event ) {
1065
  $event_data['OldStatus'] = $oldpost->post_status;
1066
  $event_data['NewStatus'] = $newpost->post_status;
1067
- $this->plugin->alerts->Trigger( $event, $event_data );
1068
  } else {
1069
  // NOTE: this triggers if NOT firing event 5019.
1070
- $this->plugin->alerts->TriggerIf( $event, $event_data, array( $this, 'plugin_not_created_post' ) );
1071
  }
1072
  }
1073
 
@@ -1084,7 +1085,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1084
  protected function check_parent_change( $oldpost, $newpost ) {
1085
  if ( $oldpost->post_parent !== $newpost->post_parent && 'page' === $newpost->post_type ) {
1086
  $editor_link = $this->get_editor_link( $oldpost );
1087
- $this->plugin->alerts->Trigger(
1088
  2047,
1089
  array(
1090
  'PostID' => $oldpost->ID,
@@ -1112,13 +1113,13 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1112
  */
1113
  protected function check_permalink_change( $old_link, $new_link, $post ) {
1114
  if ( in_array( $post->post_status, array( 'draft', 'pending' ), true ) ) {
1115
- $old_link = $this->_old_post->post_name;
1116
  $new_link = $post->post_name;
1117
  }
1118
 
1119
  if ( $old_link !== $new_link ) {
1120
  $editor_link = $this->get_editor_link( $post );
1121
- $this->plugin->alerts->Trigger(
1122
  2017,
1123
  array(
1124
  'PostID' => $post->ID,
@@ -1149,24 +1150,24 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1149
  $new_visibility = '';
1150
 
1151
  if ( $oldpost->post_password ) {
1152
- $old_visibility = __( 'Password Protected', 'wp-security-audit-log' );
1153
  } elseif ( 'private' === $oldpost->post_status ) {
1154
- $old_visibility = __( 'Private', 'wp-security-audit-log' );
1155
  } else {
1156
- $old_visibility = __( 'Public', 'wp-security-audit-log' );
1157
  }
1158
 
1159
  if ( $newpost->post_password ) {
1160
- $new_visibility = __( 'Password Protected', 'wp-security-audit-log' );
1161
  } elseif ( 'private' === $newpost->post_status ) {
1162
- $new_visibility = __( 'Private', 'wp-security-audit-log' );
1163
  } else {
1164
- $new_visibility = __( 'Public', 'wp-security-audit-log' );
1165
  }
1166
 
1167
  if ( $old_visibility && $new_visibility && ( $old_visibility !== $new_visibility ) ) {
1168
  $editor_link = $this->get_editor_link( $oldpost );
1169
- $this->plugin->alerts->Trigger(
1170
  2025,
1171
  array(
1172
  'PostID' => $oldpost->ID,
@@ -1207,7 +1208,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1207
 
1208
  if ( $from !== $to ) {
1209
  $editor_link = $this->get_editor_link( $oldpost );
1210
- $this->plugin->alerts->Trigger(
1211
  2027,
1212
  array(
1213
  'PostID' => $oldpost->ID,
@@ -1238,7 +1239,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1238
 
1239
  // Comments.
1240
  if ( $oldpost->comment_status !== $newpost->comment_status ) {
1241
- $this->plugin->alerts->Trigger(
1242
  2111,
1243
  array(
1244
  'PostID' => $newpost->ID,
@@ -1257,7 +1258,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1257
 
1258
  // Trackbacks and Pingbacks.
1259
  if ( $oldpost->ping_status !== $newpost->ping_status ) {
1260
- $this->plugin->alerts->Trigger(
1261
  2112,
1262
  array(
1263
  'PostID' => $newpost->ID,
@@ -1278,9 +1279,9 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1278
  /**
1279
  * Categories changed.
1280
  *
1281
- * @param array $old_cats - Old categories.
1282
- * @param array $new_cats - New categories.
1283
- * @param WP_Post $post - The post.
1284
  */
1285
  protected function check_categories_change( $old_cats, $new_cats, $post ) {
1286
  $old_cats = implode( ', ', (array) $old_cats );
@@ -1299,23 +1300,23 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1299
  'NewCategories' => $new_cats ? $new_cats : 'no categories',
1300
  $editor_link['name'] => $editor_link['value'],
1301
  );
1302
- $this->plugin->alerts->Trigger( 2016, $alert_data );
1303
  }
1304
  }
1305
 
1306
  /**
1307
  * Reports tags change event. This could be tags addition, removal and possibly other in the future.
1308
  *
1309
- * @since 4.1.5
 
 
1310
  *
1311
- * @param int $event_code
1312
- * @param WP_Post $post
1313
- * @param string[] $tags_changed
1314
  */
1315
  private function report_tags_change_event( $event_code, $post, $tags_changed ) {
1316
  $editor_link = $this->get_editor_link( $post );
1317
  $post_status = ( 'publish' === $post->post_status ) ? 'published' : $post->post_status;
1318
- $this->plugin->alerts->Trigger(
1319
  $event_code,
1320
  array(
1321
  'PostID' => $post->ID,
@@ -1324,7 +1325,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1324
  'PostTitle' => $post->post_title,
1325
  'PostDate' => $post->post_date,
1326
  'PostUrl' => get_permalink( $post->ID ),
1327
- 'tag' => ! empty( $tags_changed ) ? implode( ', ', $tags_changed ) : __('no tags', 'wp-security-audit-log'),
1328
  $editor_link['name'] => $editor_link['value'],
1329
  )
1330
  );
@@ -1340,11 +1341,11 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1340
  protected function check_tags_change( $old_tags, $new_tags, $post ) {
1341
  // Ensure old_tags is not null.
1342
  if ( ! $old_tags ) {
1343
- $old_tags = [];
1344
  }
1345
  $intersection = array_intersect( $old_tags, $new_tags );
1346
  if ( count( $intersection ) === count( $old_tags ) && count( $old_tags ) === count( $new_tags ) ) {
1347
- // no change, let's leave
1348
  return;
1349
  }
1350
 
@@ -1364,10 +1365,10 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1364
  /**
1365
  * Post modified content.
1366
  *
1367
- * @param integer $post_id – Post ID.
1368
  * @param stdClass $oldpost – Old post.
1369
  * @param stdClass $newpost – New post.
1370
- * @param int $modified – Set to 0 if no changes done to the post.
1371
  *
1372
  * @return int|void
1373
  */
@@ -1376,7 +1377,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1376
  return;
1377
  }
1378
 
1379
- $content_changed = $oldpost->post_content != $newpost->post_content;
1380
 
1381
  /*
1382
  * If the content hasn't changed and this looks to be a draft resave
@@ -1403,7 +1404,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1403
  $yoast_alerts = $yoast_alerts + $yoast_metabox_alerts;
1404
  // Check all alerts.
1405
  foreach ( $yoast_alerts as $alert_code => $alert ) {
1406
- if ( $this->plugin->alerts->WillOrHasTriggered( $alert_code ) ) {
1407
  return 0; // Return if any Yoast alert has or will trigger.
1408
  }
1409
  }
@@ -1427,18 +1428,19 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1427
  }
1428
 
1429
  if ( $old_post_excerpt !== $post_excerpt ) {
1430
- $event = 2129;
1431
- // We are purposfully showing an empty, not NULL value.
1432
  $event_data['old_post_excerpt'] = ( $old_post_excerpt ) ? $old_post_excerpt : ' ';
1433
  $event_data['post_excerpt'] = ( $post_excerpt ) ? $post_excerpt : ' ';
1434
  }
1435
 
1436
  if ( 2002 === $event ) {
1437
- // If we reach this point, we no longer need to check if the content has changed as we already have an event to handle it.
1438
- // So trigger 2002 regardless and "something" has changed in the post, we just dont detect it elsewhere.
1439
- $this->plugin->alerts->TriggerIf( $event, $event_data, array( $this, 'ignore_other_post_events' ) );
 
1440
  } else {
1441
- $this->plugin->alerts->Trigger( $event, $event_data );
1442
  }
1443
  }
1444
  }
@@ -1455,7 +1457,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1455
  $post_events = array_keys( $this->plugin->alerts->get_alerts_by_sub_category( 'Content' ) );
1456
 
1457
  foreach ( $post_events as $event ) {
1458
- if ( $manager->WillOrHasTriggered( $event) || $this->was_triggered_recently( $event ) ) {
1459
  return false;
1460
  }
1461
  }
@@ -1472,7 +1474,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1472
  private function check_title_change( $oldpost, $newpost ) {
1473
  if ( $oldpost->post_title !== $newpost->post_title ) {
1474
  $editor_link = $this->get_editor_link( $oldpost );
1475
- $this->plugin->alerts->Trigger(
1476
  2086,
1477
  array(
1478
  'PostID' => $newpost->ID,
@@ -1534,7 +1536,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1534
  $event_data = $this->get_post_event_data( $post ); // Event data.
1535
 
1536
  $event_data[ $editor_link['name'] ] = $editor_link['value'];
1537
- $this->plugin->alerts->Trigger( $event, $event_data );
1538
  }
1539
 
1540
  /**
@@ -1547,26 +1549,11 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1547
  private function check_auto_draft( $code, $title ) {
1548
  $ignore = 0;
1549
  if ( 2008 === $code && ( 'auto-draft' === $title || 'Auto Draft' === $title ) ) {
1550
- $ignore = ! $this->plugin->settings()->IsWPBackend();
1551
  }
1552
  return $ignore;
1553
  }
1554
 
1555
- /**
1556
- * Comments/Trackbacks and Pingbacks event code.
1557
- *
1558
- * @param stdClass $post - The post.
1559
- * @param string $status - The status.
1560
- */
1561
- private function get_comments_pings_event( $post, $status ) {
1562
- if ( 'disable' === $status ) {
1563
- $event = 2111;
1564
- } else {
1565
- $event = 2112;
1566
- }
1567
- return $event;
1568
- }
1569
-
1570
  /**
1571
  * Post Opened for Editing in WP Editors.
1572
  *
@@ -1600,7 +1587,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1600
  $event = 2100;
1601
  if ( ! $this->was_triggered( $event ) ) {
1602
  $editor_link = $this->get_editor_link( $post );
1603
- $this->plugin->alerts->Trigger(
1604
  $event,
1605
  array(
1606
  'PostID' => $post->ID,
@@ -1624,14 +1611,14 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1624
  */
1625
  private function was_triggered( $alert_id ) {
1626
  $query = new WSAL_Models_OccurrenceQuery();
1627
- $query->addOrderBy( 'created_on', true );
1628
- $query->setLimit( 1 );
1629
- $last_occurence = $query->getAdapter()->Execute( $query );
1630
 
1631
- if ( ! empty( $last_occurence ) ) {
1632
- if ( ! is_array( $alert_id ) && $last_occurence[0]->alert_id === $alert_id ) {
1633
  return true;
1634
- } elseif ( is_array( $alert_id ) && in_array( $last_occurence[0]->alert_id, $alert_id, true ) ) {
1635
  return true;
1636
  }
1637
  }
@@ -1690,7 +1677,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1690
  * @return boolean
1691
  */
1692
  public function plugin_not_created_post( $manager ) {
1693
- $triggered = $manager->WillOrHasTriggered( 5019 );
1694
  // inverting value here to account for the double NOT in _CommitItem().
1695
  return ! $triggered;
1696
  }
@@ -1698,29 +1685,29 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1698
  /**
1699
  * Check if the alert was triggered recently.
1700
  *
1701
- * Checks last 5 events if they occured less than 20 seconds ago.
1702
  *
1703
  * @param integer|array $alert_id - Alert code.
1704
  * @return boolean
1705
  */
1706
  private function was_triggered_recently( $alert_id ) {
1707
  // if we have already checked this don't check again.
1708
- if ( isset( $this->cached_alert_checks ) && array_key_exists( $alert_id, $this->cached_alert_checks ) && $this->cached_alert_checks[$alert_id] ) {
1709
  return true;
1710
  }
1711
  $query = new WSAL_Models_OccurrenceQuery();
1712
- $query->addOrderBy( 'created_on', true );
1713
- $query->setLimit( 5 );
1714
- $last_occurences = $query->getAdapter()->Execute( $query );
1715
  $known_to_trigger = false;
1716
- foreach ( $last_occurences as $last_occurence ) {
1717
  if ( $known_to_trigger ) {
1718
  break;
1719
  }
1720
- if ( ! empty( $last_occurence ) && ( $last_occurence->created_on + 5 ) > time() ) {
1721
- if ( ! is_array( $alert_id ) && $last_occurence->alert_id === $alert_id ) {
1722
  $known_to_trigger = true;
1723
- } elseif ( is_array( $alert_id ) && in_array( $last_occurence[0]->alert_id, $alert_id, true ) ) {
1724
  $known_to_trigger = true;
1725
  }
1726
  }
4
  *
5
  * Content sensor class file.
6
  *
7
+ * @since 1.0.0
8
+ * @package wsal
9
+ * @subpackage sensors
10
  */
11
 
12
  // Exit if accessed directly.
21
  * 5019 A plugin created a post
22
  * 5025 A plugin deleted a post
23
  *
24
+ * @package wsal
25
+ * @subpackage sensors
26
  */
27
  class WSAL_Sensors_Content extends WSAL_AbstractSensor {
28
 
31
  *
32
  * @var stdClass
33
  */
34
+ protected $old_post = null;
35
 
36
  /**
37
  * Old permalink.
38
  *
39
  * @var string
40
  */
41
+ protected $old_link = null;
42
 
43
  /**
44
  * Old categories.
45
  *
46
  * @var array
47
  */
48
+ protected $old_cats = null;
49
 
50
  /**
51
  * Old tags.
52
  *
53
  * @var array
54
  */
55
+ protected $old_tags = null;
56
 
57
  /**
58
  * Old path to file.
59
  *
60
  * @var string
61
  */
62
+ protected $old_tmpl = null;
63
 
64
  /**
65
  * Old post is marked as sticky.
66
  *
67
  * @var boolean
68
  */
69
+ protected $old_stky = null;
70
 
71
  /**
72
  * Old Post Status.
83
  protected $old_meta = null;
84
 
85
  /**
86
+ * {@inheritDoc}
87
  */
88
+ public function hook_events() {
89
  add_action( 'pre_post_update', array( $this, 'get_before_post_edit_data' ), 10, 2 );
90
  add_action( 'save_post', array( $this, 'post_changed' ), 10, 3 );
91
  add_action( 'set_object_terms', array( $this, 'post_terms_changed' ), 10, 4 );
125
 
126
  // If post exists.
127
  if ( ! empty( $post ) && $post instanceof WP_Post ) {
128
+ $this->old_post = $post;
129
+ $this->old_link = get_permalink( $post_id );
130
+ $this->old_tmpl = $this->get_post_template( $this->old_post );
131
+ $this->old_cats = $this->get_post_categories( $this->old_post );
132
+ $this->old_tags = $this->get_post_tags( $this->old_post );
133
+ $this->old_stky = in_array( $post_id, get_option( 'sticky_posts' ), true );
134
  $this->old_status = $post->post_status;
135
  $this->old_meta = get_post_meta( $post_id );
136
  }
157
  // Ignorable states.
158
  if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
159
  // Check post creation event.
160
+ if ( $this->old_post && 'auto-draft' === $this->old_post->post_status && 'draft' === $post->post_status ) {
161
+ $this->check_post_creation( $this->old_post, $post );
162
  }
163
  return;
164
  }
193
  }
194
 
195
  if ( $update ) {
196
+ $status_event = $this->check_status_change( $this->old_post, $post );
197
 
198
+ if ( 2001 !== $status_event && 'auto-draft' !== $this->old_post->post_status ) {
199
  // Handle update post events.
200
  $changes = 0;
201
+ $changes = $this->check_author_change( $this->old_post, $post )
202
+ + $this->check_parent_change( $this->old_post, $post )
203
+ + $this->check_visibility_change( $this->old_post, $post, $this->old_status, $post->post_status )
204
+ + $this->check_date_change( $this->old_post, $post )
205
+ + $this->check_permalink_change( $this->old_link, get_permalink( $post->ID ), $post )
206
+ + $this->check_comments_pings( $this->old_post, $post );
207
 
208
  // If a status change event has occurred, then don't log event 2002 (post modified).
209
  $changes = $status_event ? true : $changes;
210
  if ( '1' === $changes ) {
211
  remove_action( 'save_post', array( $this, 'post_changed' ), 10, 3 );
212
  }
213
+ $this->check_modification_change( $post->ID, $this->old_post, $post, $changes );
214
  }
215
  } else {
216
  // If not update then check post creation.
217
+ $this->check_post_creation( $this->old_post, $post );
218
  }
219
  }
220
 
248
 
249
  if ( 'post_tag' === $taxonomy ) {
250
  // Check tags change event.
251
+ $this->check_tags_change( $this->old_tags, $this->get_post_tags( $post ), $post );
252
  } else {
253
  // Check categories change event.
254
+ $this->check_categories_change( $this->old_cats, $this->get_post_categories( $post ), $post );
255
  }
256
  }
257
 
305
  );
306
  }
307
 
308
+ $this->plugin->alerts->trigger_event( $event, $event_data ); // Log event.
309
  }
310
  }
311
 
319
  if ( ! in_array( $post->post_type, $this->plugin->alerts->ignored_cpts, true ) ) {
320
  $editor_link = $this->get_editor_link( $post );
321
 
322
+ $this->plugin->alerts->trigger_event(
323
  2012,
324
  array(
325
  'PostID' => $post->ID,
344
  if ( ! in_array( $post->post_type, $this->plugin->alerts->ignored_cpts, true ) ) {
345
  $editor_link = $this->get_editor_link( $post );
346
 
347
+ $this->plugin->alerts->trigger_event(
348
  2014,
349
  array(
350
  'PostID' => $post->ID,
371
  if ( ! in_array( $post->post_type, $this->plugin->alerts->ignored_cpts, true ) ) {
372
  $editor_link = $this->get_editor_link( $post );
373
 
374
+ $this->plugin->alerts->trigger_event(
375
  2001,
376
  array(
377
  'PostID' => $post->ID,
399
  return;
400
  }
401
 
402
+ $post_id = isset( $_GET['post'] ) ? (int) sanitize_text_field( wp_unslash( $_GET['post'] ) ) : false; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
 
 
403
 
404
  // Check post id.
405
  if ( empty( $post_id ) ) {
454
  $post_data = $this->get_post_event_data( $post ); // Get event post data.
455
 
456
  // Update post URL based on current actual path.
457
+ if ( $this->plugin->is_multisite() && ! is_subdomain_install() ) {
458
  // For multisite using subfolders, remove the subfolder.
459
+ $subdir_path = parse_url( home_url(), PHP_URL_PATH ); // phpcs:ignore WordPress.WP.AlternativeFunctions.parse_url_parse_url
460
+ $escaped = str_replace( '/', '\/', preg_quote( $subdir_path ) ); // phpcs:ignore WordPress.PHP.PregQuoteDelimiter.Missing
461
  $current_path = preg_replace( '/' . $escaped . '/', '', $current_path );
462
  }
463
 
464
+ // Bail if this don't have this, as it's probably an archive.
465
  if ( ! isset( $post_data['PostUrl'] ) ) {
466
  return;
467
  }
473
 
474
  // Set editor link.
475
  $post_data[ $edit_link['name'] ] = $edit_link['value'];
476
+ $this->plugin->alerts->trigger_event( 2101, $post_data );
477
  }
478
  }
479
  }
486
  public function event_category_creation( $category_id ) {
487
  $category = get_category( $category_id );
488
  $category_link = $this->get_taxonomy_edit_link( $category_id, 'category' );
489
+ $this->plugin->alerts->trigger_event(
490
  2023,
491
  array(
492
  'CategoryName' => $category->name,
504
  public function event_tag_creation( $tag_id ) {
505
  $tag = get_tag( $tag_id );
506
  $tag_link = $this->get_taxonomy_edit_link( $tag_id );
507
+ $this->plugin->alerts->trigger_event(
508
  2121,
509
  array(
510
  'TagName' => $tag->name,
523
  public function check_taxonomy_term_deletion( $term_id, $taxonomy ) {
524
  if ( 'post_tag' === $taxonomy ) {
525
  $tag = get_tag( $term_id );
526
+ $this->plugin->alerts->trigger_event(
527
  2122,
528
  array(
529
  'TagID' => $term_id,
534
  } elseif ( 'category' === $taxonomy ) {
535
  $category = get_category( $term_id );
536
  $category_link = $this->get_taxonomy_edit_link( $term_id, $taxonomy );
537
+ $this->plugin->alerts->trigger_event(
538
  2024,
539
  array(
540
  'CategoryID' => $term_id,
573
  if ( 'post_tag' === $taxonomy ) {
574
  // Update if both names are not same.
575
  if ( $old_name !== $new_name ) {
576
+ $this->plugin->alerts->trigger_event(
577
  2123,
578
  array(
579
  'old_name' => $old_name,
586
 
587
  // Update if both slugs are not same.
588
  if ( $old_slug !== $new_slug ) {
589
+ $this->plugin->alerts->trigger_event(
590
  2124,
591
  array(
592
  'tag' => $new_name,
599
 
600
  // Update if both descriptions are not same.
601
  if ( $old_desc !== $new_desc ) {
602
+ $this->plugin->alerts->trigger_event(
603
  2125,
604
  array(
605
  'tag' => $new_name,
612
  } elseif ( 'category' === $taxonomy ) { // Check if the taxonomy is `category`.
613
  // Log event if both names are not same.
614
  if ( $old_name !== $new_name ) {
615
+ $this->plugin->alerts->trigger_event(
616
  2127,
617
  array(
618
  'old_name' => $old_name,
625
 
626
  // Log event if both slugs are not same.
627
  if ( $old_slug !== $new_slug ) {
628
+ $this->plugin->alerts->trigger_event(
629
  2128,
630
  array(
631
  'CategoryName' => $new_name,
650
  }
651
 
652
  if ( $old_parent_name !== $new_parent_name ) {
653
+ $this->plugin->alerts->trigger_event(
654
  2052,
655
  array(
656
  'CategoryName' => $new_name,
752
  */
753
  public function check_template_change( $post_id, $meta_value ) {
754
  $post = get_post( $post_id );
755
+ $old_tmpl = ( $this->old_tmpl && 'page' !== basename( $this->old_tmpl, '.php' ) ) ? ucwords( str_replace( array( '-', '_' ), ' ', basename( $this->old_tmpl, '.php' ) ) ) : __( 'Default template', 'wp-security-audit-log' );
756
  $new_tmpl = ( $meta_value ) ? ucwords( str_replace( array( '-', '_' ), ' ', basename( $meta_value ) ) ) : __( 'Default', 'wp-security-audit-log' );
757
  if ( $old_tmpl !== $new_tmpl ) {
758
  $editor_link = $this->get_editor_link( $post );
759
+ $this->plugin->alerts->trigger_event(
760
  2048,
761
  array(
762
  'PostID' => $post->ID,
799
 
800
  $post = get_post( $post_id );
801
  $editor_link = $this->get_editor_link( $post );
802
+ $this->plugin->alerts->trigger_event(
803
  2130,
804
  array(
805
  'PostID' => $post->ID,
833
 
834
  // If post exists.
835
  if ( ! empty( $post ) ) {
836
+ $this->old_post = $post;
837
+ $this->old_link = get_permalink( $post_id );
838
+ $this->old_tmpl = $this->get_post_template( $this->old_post );
839
+ $this->old_cats = $this->get_post_categories( $this->old_post );
840
+ $this->old_tags = $this->get_post_tags( $this->old_post );
841
+ $this->old_stky = in_array( $post_id, get_option( 'sticky_posts' ), true );
842
  }
843
  }
844
  }
931
 
932
  if ( $is_scheduled ) {
933
  $event_data['PublishingDate'] = $new_post->post_date;
934
+ $this->plugin->alerts->trigger_event( $event, $event_data );
935
  } else {
936
 
937
  // So far we assume that the action is initiated by a user, let's check if it was actually initiated
952
  );
953
  }
954
 
955
+ $this->plugin->alerts->trigger_event( $event, $event_data );
956
  }
957
  }
958
  }
962
  * Get editor link.
963
  *
964
  * @param stdClass $post - The post.
965
+ *
966
  * @return array $editor_link - Name and value link.
967
  */
968
  private function get_editor_link( $post ) {
1009
  $old_author = ( is_object( $old_author ) ) ? $old_author->user_login : 'N/A';
1010
  $new_author = get_userdata( $newpost->post_author );
1011
  $new_author = ( is_object( $new_author ) ) ? $new_author->user_login : 'N/A';
1012
+ $this->plugin->alerts->trigger_event(
1013
  2019,
1014
  array(
1015
  'PostID' => $oldpost->ID,
1061
 
1062
  if ( $is_scheduled ) {
1063
  $event_data['PublishingDate'] = $newpost->post_date;
1064
+ $this->plugin->alerts->trigger_event( $event, $event_data );
1065
  } elseif ( 2021 === $event ) {
1066
  $event_data['OldStatus'] = $oldpost->post_status;
1067
  $event_data['NewStatus'] = $newpost->post_status;
1068
+ $this->plugin->alerts->trigger_event( $event, $event_data );
1069
  } else {
1070
  // NOTE: this triggers if NOT firing event 5019.
1071
+ $this->plugin->alerts->trigger_event_if( $event, $event_data, array( $this, 'plugin_not_created_post' ) );
1072
  }
1073
  }
1074
 
1085
  protected function check_parent_change( $oldpost, $newpost ) {
1086
  if ( $oldpost->post_parent !== $newpost->post_parent && 'page' === $newpost->post_type ) {
1087
  $editor_link = $this->get_editor_link( $oldpost );
1088
+ $this->plugin->alerts->trigger_event(
1089
  2047,
1090
  array(
1091
  'PostID' => $oldpost->ID,
1113
  */
1114
  protected function check_permalink_change( $old_link, $new_link, $post ) {
1115
  if ( in_array( $post->post_status, array( 'draft', 'pending' ), true ) ) {
1116
+ $old_link = $this->old_post->post_name;
1117
  $new_link = $post->post_name;
1118
  }
1119
 
1120
  if ( $old_link !== $new_link ) {
1121
  $editor_link = $this->get_editor_link( $post );
1122
+ $this->plugin->alerts->trigger_event(
1123
  2017,
1124
  array(
1125
  'PostID' => $post->ID,
1150
  $new_visibility = '';
1151
 
1152
  if ( $oldpost->post_password ) {
1153
+ $old_visibility = esc_html__( 'Password Protected', 'wp-security-audit-log' );
1154
  } elseif ( 'private' === $oldpost->post_status ) {
1155
+ $old_visibility = esc_html__( 'Private', 'wp-security-audit-log' );
1156
  } else {
1157
+ $old_visibility = esc_html__( 'Public', 'wp-security-audit-log' );
1158
  }
1159
 
1160
  if ( $newpost->post_password ) {
1161
+ $new_visibility = esc_html__( 'Password Protected', 'wp-security-audit-log' );
1162
  } elseif ( 'private' === $newpost->post_status ) {
1163
+ $new_visibility = esc_html__( 'Private', 'wp-security-audit-log' );
1164
  } else {
1165
+ $new_visibility = esc_html__( 'Public', 'wp-security-audit-log' );
1166
  }
1167
 
1168
  if ( $old_visibility && $new_visibility && ( $old_visibility !== $new_visibility ) ) {
1169
  $editor_link = $this->get_editor_link( $oldpost );
1170
+ $this->plugin->alerts->trigger_event(
1171
  2025,
1172
  array(
1173
  'PostID' => $oldpost->ID,
1208
 
1209
  if ( $from !== $to ) {
1210
  $editor_link = $this->get_editor_link( $oldpost );
1211
+ $this->plugin->alerts->trigger_event(
1212
  2027,
1213
  array(
1214
  'PostID' => $oldpost->ID,
1239
 
1240
  // Comments.
1241
  if ( $oldpost->comment_status !== $newpost->comment_status ) {
1242
+ $this->plugin->alerts->trigger_event(
1243
  2111,
1244
  array(
1245
  'PostID' => $newpost->ID,
1258
 
1259
  // Trackbacks and Pingbacks.
1260
  if ( $oldpost->ping_status !== $newpost->ping_status ) {
1261
+ $this->plugin->alerts->trigger_event(
1262
  2112,
1263
  array(
1264
  'PostID' => $newpost->ID,
1279
  /**
1280
  * Categories changed.
1281
  *
1282
+ * @param array $old_cats - Old categories.
1283
+ * @param array $new_cats - New categories.
1284
+ * @param WP_Post $post - The post.
1285
  */
1286
  protected function check_categories_change( $old_cats, $new_cats, $post ) {
1287
  $old_cats = implode( ', ', (array) $old_cats );
1300
  'NewCategories' => $new_cats ? $new_cats : 'no categories',
1301
  $editor_link['name'] => $editor_link['value'],
1302
  );
1303
+ $this->plugin->alerts->trigger_event( 2016, $alert_data );
1304
  }
1305
  }
1306
 
1307
  /**
1308
  * Reports tags change event. This could be tags addition, removal and possibly other in the future.
1309
  *
1310
+ * @param int $event_code Event code.
1311
+ * @param WP_Post $post WordPress post object.
1312
+ * @param string[] $tags_changed Changed tags.
1313
  *
1314
+ * @since 4.1.5
 
 
1315
  */
1316
  private function report_tags_change_event( $event_code, $post, $tags_changed ) {
1317
  $editor_link = $this->get_editor_link( $post );
1318
  $post_status = ( 'publish' === $post->post_status ) ? 'published' : $post->post_status;
1319
+ $this->plugin->alerts->trigger_event(
1320
  $event_code,
1321
  array(
1322
  'PostID' => $post->ID,
1325
  'PostTitle' => $post->post_title,
1326
  'PostDate' => $post->post_date,
1327
  'PostUrl' => get_permalink( $post->ID ),
1328
+ 'tag' => ! empty( $tags_changed ) ? implode( ', ', $tags_changed ) : esc_html__( 'no tags', 'wp-security-audit-log' ),
1329
  $editor_link['name'] => $editor_link['value'],
1330
  )
1331
  );
1341
  protected function check_tags_change( $old_tags, $new_tags, $post ) {
1342
  // Ensure old_tags is not null.
1343
  if ( ! $old_tags ) {
1344
+ $old_tags = array();
1345
  }
1346
  $intersection = array_intersect( $old_tags, $new_tags );
1347
  if ( count( $intersection ) === count( $old_tags ) && count( $old_tags ) === count( $new_tags ) ) {
1348
+ // No change, let's leave.
1349
  return;
1350
  }
1351
 
1365
  /**
1366
  * Post modified content.
1367
  *
1368
+ * @param integer $post_id – Post ID.
1369
  * @param stdClass $oldpost – Old post.
1370
  * @param stdClass $newpost – New post.
1371
+ * @param int $modified – Set to 0 if no changes done to the post.
1372
  *
1373
  * @return int|void
1374
  */
1377
  return;
1378
  }
1379
 
1380
+ $content_changed = $oldpost->post_content !== $newpost->post_content;
1381
 
1382
  /*
1383
  * If the content hasn't changed and this looks to be a draft resave
1404
  $yoast_alerts = $yoast_alerts + $yoast_metabox_alerts;
1405
  // Check all alerts.
1406
  foreach ( $yoast_alerts as $alert_code => $alert ) {
1407
+ if ( $this->plugin->alerts->will_or_has_triggered( $alert_code ) ) {
1408
  return 0; // Return if any Yoast alert has or will trigger.
1409
  }
1410
  }
1428
  }
1429
 
1430
  if ( $old_post_excerpt !== $post_excerpt ) {
1431
+ $event = 2129;
1432
+ // We are purposefully showing an empty, not NULL value.
1433
  $event_data['old_post_excerpt'] = ( $old_post_excerpt ) ? $old_post_excerpt : ' ';
1434
  $event_data['post_excerpt'] = ( $post_excerpt ) ? $post_excerpt : ' ';
1435
  }
1436
 
1437
  if ( 2002 === $event ) {
1438
+ // If we reach this point, we no longer need to check if the content has changed as we already have
1439
+ // an event to handle it. So trigger 2002 regardless and "something" has changed in the post, we
1440
+ // just don't detect it elsewhere.
1441
+ $this->plugin->alerts->trigger_event_if( $event, $event_data, array( $this, 'ignore_other_post_events' ) );
1442
  } else {
1443
+ $this->plugin->alerts->trigger_event( $event, $event_data );
1444
  }
1445
  }
1446
  }
1457
  $post_events = array_keys( $this->plugin->alerts->get_alerts_by_sub_category( 'Content' ) );
1458
 
1459
  foreach ( $post_events as $event ) {
1460
+ if ( $manager->will_or_has_triggered( $event ) || $this->was_triggered_recently( $event ) ) {
1461
  return false;
1462
  }
1463
  }
1474
  private function check_title_change( $oldpost, $newpost ) {
1475
  if ( $oldpost->post_title !== $newpost->post_title ) {
1476
  $editor_link = $this->get_editor_link( $oldpost );
1477
+ $this->plugin->alerts->trigger_event(
1478
  2086,
1479
  array(
1480
  'PostID' => $newpost->ID,
1536
  $event_data = $this->get_post_event_data( $post ); // Event data.
1537
 
1538
  $event_data[ $editor_link['name'] ] = $editor_link['value'];
1539
+ $this->plugin->alerts->trigger_event( $event, $event_data );
1540
  }
1541
 
1542
  /**
1549
  private function check_auto_draft( $code, $title ) {
1550
  $ignore = 0;
1551
  if ( 2008 === $code && ( 'auto-draft' === $title || 'Auto Draft' === $title ) ) {
1552
+ $ignore = ! $this->plugin->settings()->is_wp_backend();
1553
  }
1554
  return $ignore;
1555
  }
1556
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1557
  /**
1558
  * Post Opened for Editing in WP Editors.
1559
  *
1587
  $event = 2100;
1588
  if ( ! $this->was_triggered( $event ) ) {
1589
  $editor_link = $this->get_editor_link( $post );
1590
+ $this->plugin->alerts->trigger_event(
1591
  $event,
1592
  array(
1593
  'PostID' => $post->ID,
1611
  */
1612
  private function was_triggered( $alert_id ) {
1613
  $query = new WSAL_Models_OccurrenceQuery();
1614
+ $query->add_order_by( 'created_on', true );
1615
+ $query->set_limit( 1 );
1616
+ $last_occurrence = $query->get_adapter()->execute_query( $query );
1617
 
1618
+ if ( ! empty( $last_occurrence ) ) {
1619
+ if ( ! is_array( $alert_id ) && $last_occurrence[0]->alert_id === $alert_id ) {
1620
  return true;
1621
+ } elseif ( is_array( $alert_id ) && in_array( $last_occurrence[0]->alert_id, $alert_id, true ) ) {
1622
  return true;
1623
  }
1624
  }
1677
  * @return boolean
1678
  */
1679
  public function plugin_not_created_post( $manager ) {
1680
+ $triggered = $manager->will_or_has_triggered( 5019 );
1681
  // inverting value here to account for the double NOT in _CommitItem().
1682
  return ! $triggered;
1683
  }
1685
  /**
1686
  * Check if the alert was triggered recently.
1687
  *
1688
+ * Checks last 5 events if they occurred less than 20 seconds ago.
1689
  *
1690
  * @param integer|array $alert_id - Alert code.
1691
  * @return boolean
1692
  */
1693
  private function was_triggered_recently( $alert_id ) {
1694
  // if we have already checked this don't check again.
1695
+ if ( isset( $this->cached_alert_checks ) && array_key_exists( $alert_id, $this->cached_alert_checks ) && $this->cached_alert_checks[ $alert_id ] ) {
1696
  return true;
1697
  }
1698
  $query = new WSAL_Models_OccurrenceQuery();
1699
+ $query->add_order_by( 'created_on', true );
1700
+ $query->set_limit( 5 );
1701
+ $last_occurrences = $query->get_adapter()->execute_query( $query );
1702
  $known_to_trigger = false;
1703
+ foreach ( $last_occurrences as $last_occurrence ) {
1704
  if ( $known_to_trigger ) {
1705
  break;
1706
  }
1707
+ if ( ! empty( $last_occurrence ) && ( $last_occurrence->created_on + 5 ) > time() ) {
1708
+ if ( ! is_array( $alert_id ) && $last_occurrence->alert_id === $alert_id ) {
1709
  $known_to_trigger = true;
1710
+ } elseif ( is_array( $alert_id ) && in_array( $last_occurrence[0]->alert_id, $alert_id, true ) ) {
1711
  $known_to_trigger = true;
1712
  }
1713
  }
classes/Sensors/Database.php CHANGED
@@ -4,8 +4,9 @@
4
  *
5
  * Database sensors class file.
6
  *
7
- * @since 1.0.0
8
- * @package wsal
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -29,13 +30,13 @@ if ( ! defined( 'ABSPATH' ) ) {
29
  * 5023 WordPress modified tables structure
30
  * 5024 WordPress deleted tables
31
  *
32
- * @package wsal
33
  * @subpackage sensors
34
  */
35
  class WSAL_Sensors_Database extends WSAL_AbstractSensor {
36
 
37
  /**
38
- * Local cache for basename of current script. It used used to improve performance
39
  * of determining the actor of current action.
40
  *
41
  * @var string|bool
@@ -58,14 +59,14 @@ class WSAL_Sensors_Database extends WSAL_AbstractSensor {
58
  * @var string[]
59
  * @since 4.1.5
60
  */
61
- private static $already_logged = [];
62
 
63
  /**
64
  * Listening to events using WP hooks.
65
  */
66
- public function HookEvents() {
67
- add_action( 'dbdelta_queries', array( $this, 'EventDBDeltaQuery' ) );
68
- add_filter( 'query', array( $this, 'EventDropQuery' ) );
69
  }
70
 
71
  /**
@@ -75,7 +76,7 @@ class WSAL_Sensors_Database extends WSAL_AbstractSensor {
75
  *
76
  * @return string
77
  */
78
- public function EventDropQuery( $query ) {
79
  if ( ! self::$enabled ) {
80
  return $query;
81
  }
@@ -85,16 +86,16 @@ class WSAL_Sensors_Database extends WSAL_AbstractSensor {
85
  $query_type = '';
86
  if ( preg_match( '|DROP TABLE( IF EXISTS)? ([^ ]*)|', $query ) ) {
87
  $table_name = empty( $str[4] ) ? $str[2] : $str[4];
88
- // only log when the table exists as some plugins try to delete tables even if they don't exist
89
- if ( $this->is_table_operation_check_enabled($table_name, 'delete')
90
- && $this->check_if_table_exists( $table_name ) ) {
91
  array_push( $table_names, $table_name );
92
  $query_type = 'delete';
93
  }
94
  } elseif ( preg_match( '/CREATE TABLE( IF NOT EXISTS)? ([^ ]*)/i', $query, $matches ) || preg_match( '/CREATE TABLE ([^ ]*)/i', $query, $matches ) ) {
95
- $table_name = $matches[count($matches) - 1];
96
- if ( $this->is_table_operation_check_enabled($table_name, 'create')
97
- && ! $this->check_if_table_exists($table_name) ) {
98
  /**
99
  * Some plugins keep trying to create tables even
100
  * when they already exist - would result in too
@@ -105,7 +106,7 @@ class WSAL_Sensors_Database extends WSAL_AbstractSensor {
105
  }
106
  }
107
 
108
- $this->MaybeTriggerEvent( $query_type, $table_names );
109
 
110
  return $query;
111
  }
@@ -114,28 +115,28 @@ class WSAL_Sensors_Database extends WSAL_AbstractSensor {
114
  * Triggers an event if the list of tables is not empty. It also checks if
115
  * the event should be logged for events originated by WordPress.
116
  *
117
- * @param string $query_type
118
- * @param string[] $table_names
119
  */
120
- private function MaybeTriggerEvent( $query_type, $table_names ) {
121
  if ( ! empty( $table_names ) ) {
122
- $actor = $this->GetActor( $table_names );
123
- if ( 'wordpress' === $actor && ! $this->plugin->settings()->IsWPBackend() ) {
124
- // event is not fired if the monitoring of background events is disabled
125
  return;
126
  }
127
 
128
  // Loop through each item to report event per table.
129
  foreach ( $table_names as $table_name ) {
130
- $alert_options = $this->GetEventOptions( $actor );
131
- $event_code = $this->GetEventCode( $actor, $query_type );
132
- $db_op_key = $query_type . '_' . $table_name;
133
- if ( in_array( $db_op_key, self::$already_logged ) ) {
134
  continue;
135
  }
136
 
137
  $alert_options['TableNames'] = $table_name;
138
- $this->plugin->alerts->Trigger( $event_code, $alert_options );
139
  array_push( self::$already_logged, $db_op_key );
140
  }
141
  }
@@ -148,36 +149,42 @@ class WSAL_Sensors_Database extends WSAL_AbstractSensor {
148
  *
149
  * @return bool|string Theme, plugin or false if unknown.
150
  */
151
- private function GetActor( $table_names ) {
152
- // default actor (treated as an unknown component)
153
  $result = false;
154
 
155
- // use current script name to determine if the actor is theme or a plugin
156
-
157
  if ( is_null( $this->script_basename ) ) {
158
  $this->script_basename = isset( $_SERVER['SCRIPT_NAME'] ) ? basename( sanitize_text_field( wp_unslash( $_SERVER['SCRIPT_NAME'] ) ), '.php' ) : false;
159
  }
160
 
161
  $result = $this->script_basename;
162
 
163
- // check table names for default WordPress table names (including network tables)
164
- if ( $this->ContainsWordPressTable( $table_names ) ) {
165
- $result = 'wordpress';
166
  }
167
 
168
  return $result;
169
  }
170
 
171
- private function ContainsWordPressTable( $tables ) {
 
 
 
 
 
 
 
172
  if ( ! empty( $tables ) ) {
173
  global $wpdb;
174
- $prefix = preg_quote( $wpdb->prefix );
175
  $site_regex = '/\b' . $prefix . '(\d+_)?(commentmeta|comments|links|options|postmeta|posts|terms|termmeta|term_relationships|term_relationships|term_taxonomy|usermeta|users)\b/';
176
  $network_regex = '/\b' . $prefix . '(blogs|blog_versions|registration_log|signups|site|sitemeta|users|usermeta)\b/';
177
 
178
  foreach ( $tables as $table ) {
179
  if ( preg_match( $site_regex, $table ) || preg_match( $network_regex, $table ) ) {
180
- // stop as soon as the first WordPress table is found
181
  return true;
182
  }
183
  }
@@ -192,22 +199,23 @@ class WSAL_Sensors_Database extends WSAL_AbstractSensor {
192
  * @param string $actor - Plugins, themes, WordPress or unknown.
193
  *
194
  * @return array
 
 
 
195
  */
196
- protected function GetEventOptions( $actor ) {
197
- // Check the actor
198
  $alert_options = array();
199
  switch ( $actor ) {
200
  case 'plugins':
201
  // Action Plugin Component.
202
  $plugin_file = '';
203
 
204
- // @codingStandardsIgnoreStart
205
  if ( isset( $_GET['plugin'] ) ) {
206
  $plugin_file = sanitize_text_field( wp_unslash( $_GET['plugin'] ) );
207
  } elseif ( isset( $_GET['checked'] ) ) {
208
  $plugin_file = sanitize_text_field( wp_unslash( $_GET['checked'][0] ) );
209
  }
210
- // @codingStandardsIgnoreEnd
211
 
212
  // Get plugin data.
213
  $plugins = get_plugins();
@@ -221,9 +229,9 @@ class WSAL_Sensors_Database extends WSAL_AbstractSensor {
221
  'Version' => $plugin['Version'],
222
  );
223
  } else {
224
- $plugin_name = basename( $plugin_file, '.php' );
225
- $plugin_name = str_replace( array( '_', '-', ' ' ), ' ', $plugin_name );
226
- $plugin_name = ucwords( $plugin_name );
227
 
228
  // If this is still empty at this point, lets check recent events.
229
  if ( empty( $plugin_file ) ) {
@@ -236,21 +244,18 @@ class WSAL_Sensors_Database extends WSAL_AbstractSensor {
236
  case 'themes':
237
  // Action Theme Component.
238
  $theme_name = '';
239
-
240
- // @codingStandardsIgnoreStart
241
  if ( isset( $_GET['theme'] ) ) {
242
  $theme_name = sanitize_text_field( wp_unslash( $_GET['theme'] ) );
243
  } elseif ( isset( $_GET['checked'] ) ) {
244
  $theme_name = sanitize_text_field( wp_unslash( $_GET['checked'][0] ) );
245
  }
246
- // @codingStandardsIgnoreEnd
247
 
248
  $theme_name = str_replace( array( '_', '-', ' ' ), ' ', $theme_name );
249
  $theme_name = ucwords( $theme_name );
250
  $alert_options['Theme'] = (object) array( 'Name' => $theme_name );
251
  break;
252
 
253
- case 'wordpress':
254
  $alert_options['Component'] = 'WordPress';
255
  break;
256
 
@@ -271,7 +276,7 @@ class WSAL_Sensors_Database extends WSAL_AbstractSensor {
271
  *
272
  * @return int Event code.
273
  */
274
- protected function GetEventCode( $actor, $query_type ) {
275
  switch ( $actor ) {
276
  case 'plugins':
277
  if ( 'create' === $query_type ) {
@@ -293,7 +298,7 @@ class WSAL_Sensors_Database extends WSAL_AbstractSensor {
293
  }
294
  break;
295
 
296
- case 'wordpress':
297
  if ( 'create' === $query_type ) {
298
  return 5022;
299
  } elseif ( 'update' === $query_type ) {
@@ -321,7 +326,7 @@ class WSAL_Sensors_Database extends WSAL_AbstractSensor {
321
  *
322
  * @return array
323
  */
324
- public function EventDBDeltaQuery( $queries ) {
325
  if ( ! self::$enabled ) {
326
  return $queries;
327
  }
@@ -336,9 +341,9 @@ class WSAL_Sensors_Database extends WSAL_AbstractSensor {
336
  $qry = str_replace( '`', '', $qry );
337
  $str = explode( ' ', $qry );
338
  if ( preg_match( '/CREATE TABLE( IF NOT EXISTS)? ([^ ]*)/i', $qry, $matches ) ) {
339
- $table_name = $matches[count($matches) - 1];
340
- if ( $this->is_table_operation_check_enabled($table_name, 'create')
341
- && ! $this->check_if_table_exists( $table_name ) ) {
342
  /**
343
  * Some plugins keep trying to create tables even
344
  * when they already exist- would result in too
@@ -350,9 +355,9 @@ class WSAL_Sensors_Database extends WSAL_AbstractSensor {
350
  array_push( $query_types['update'], $str[2] );
351
  } elseif ( preg_match( '|DROP TABLE( IF EXISTS)? ([^ ]*)|', $qry ) ) {
352
  $table_name = empty( $str[4] ) ? $str[2] : $str[4];
353
- // only log when the table exists as some plugins try to delete tables even if they don't exist
354
- if ( $this->is_table_operation_check_enabled($table_name, 'delete')
355
- && $this->check_if_table_exists( $table_name ) ) {
356
  array_push( $query_types['delete'], $table_name );
357
  }
358
  }
@@ -360,7 +365,7 @@ class WSAL_Sensors_Database extends WSAL_AbstractSensor {
360
 
361
  if ( ! empty( $query_types['create'] ) || ! empty( $query_types['update'] ) || ! empty( $query_types['delete'] ) ) {
362
  foreach ( $query_types as $query_type => $table_names ) {
363
- $this->MaybeTriggerEvent( $query_type, $table_names );
364
  }
365
  }
366
 
@@ -378,8 +383,8 @@ class WSAL_Sensors_Database extends WSAL_AbstractSensor {
378
  $latest_events = $this->plugin->alerts->get_latest_events( 25 );
379
 
380
  foreach ( $latest_events as $latest_event ) {
381
- if ( $alert_id === intval( $latest_event->alert_id ) ) {
382
- $event_meta = $latest_event ? $latest_event->GetMetaArray() : false;
383
  $plugin_name = $event_meta['PluginData']->Name;
384
  }
385
  }
@@ -402,13 +407,13 @@ class WSAL_Sensors_Database extends WSAL_AbstractSensor {
402
  try {
403
  global $wpdb;
404
 
405
- // output buffering is here to prevent from error log messages that would be fired if the table didn't exist
406
  ob_start();
407
- $db_result = $wpdb->query( "SELECT COUNT(1) FROM {$table_name};" );
408
  ob_clean();
409
 
410
  return ( 1 === $db_result );
411
- } catch (Exception $e) {
412
  return false;
413
  }
414
  }
@@ -420,16 +425,17 @@ class WSAL_Sensors_Database extends WSAL_AbstractSensor {
420
  * if a specific alert is not enabled. Unfortunately if the alert is enabled or not is being checked
421
  * too late.
422
  *
423
- * @param string $table_name
424
- * @param string $query_type
425
  *
426
  * @return bool
427
- * @see WSAL_AlertManager::_CommitItem()
428
  * @since 4.2.0
429
  */
430
  private function is_table_operation_check_enabled( $table_name, $query_type ) {
431
- $actor = $this->GetActor( [ $table_name ] );
432
- $eventCode = $this->GetEventCode( $actor, $query_type );
433
- return $this->plugin->alerts->IsEnabled( $eventCode );
 
434
  }
435
  }
4
  *
5
  * Database sensors class file.
6
  *
7
+ * @since 1.0.0
8
+ * @package wsal
9
+ * @subpackage sensors
10
  */
11
 
12
  // Exit if accessed directly.
30
  * 5023 WordPress modified tables structure
31
  * 5024 WordPress deleted tables
32
  *
33
+ * @package wsal
34
  * @subpackage sensors
35
  */
36
  class WSAL_Sensors_Database extends WSAL_AbstractSensor {
37
 
38
  /**
39
+ * Local cache for basename of current script. It is used to improve performance
40
  * of determining the actor of current action.
41
  *
42
  * @var string|bool
59
  * @var string[]
60
  * @since 4.1.5
61
  */
62
+ private static $already_logged = array();
63
 
64
  /**
65
  * Listening to events using WP hooks.
66
  */
67
+ public function hook_events() {
68
+ add_action( 'dbdelta_queries', array( $this, 'event_db_delta_query' ) );
69
+ add_filter( 'query', array( $this, 'event_drop_query' ) );
70
  }
71
 
72
  /**
76
  *
77
  * @return string
78
  */
79
+ public function event_drop_query( $query ) {
80
  if ( ! self::$enabled ) {
81
  return $query;
82
  }
86
  $query_type = '';
87
  if ( preg_match( '|DROP TABLE( IF EXISTS)? ([^ ]*)|', $query ) ) {
88
  $table_name = empty( $str[4] ) ? $str[2] : $str[4];
89
+ // Only log when the table exists as some plugins try to delete tables even if they don't exist.
90
+ if ( $this->is_table_operation_check_enabled( $table_name, 'delete' )
91
+ && $this->check_if_table_exists( $table_name ) ) {
92
  array_push( $table_names, $table_name );
93
  $query_type = 'delete';
94
  }
95
  } elseif ( preg_match( '/CREATE TABLE( IF NOT EXISTS)? ([^ ]*)/i', $query, $matches ) || preg_match( '/CREATE TABLE ([^ ]*)/i', $query, $matches ) ) {
96
+ $table_name = $matches[ count( $matches ) - 1 ];
97
+ if ( $this->is_table_operation_check_enabled( $table_name, 'create' )
98
+ && ! $this->check_if_table_exists( $table_name ) ) {
99
  /**
100
  * Some plugins keep trying to create tables even
101
  * when they already exist - would result in too
106
  }
107
  }
108
 
109
+ $this->maybe_trigger_event( $query_type, $table_names );
110
 
111
  return $query;
112
  }
115
  * Triggers an event if the list of tables is not empty. It also checks if
116
  * the event should be logged for events originated by WordPress.
117
  *
118
+ * @param string $query_type Query type.
119
+ * @param string[] $table_names Table names.
120
  */
121
+ private function maybe_trigger_event( $query_type, $table_names ) {
122
  if ( ! empty( $table_names ) ) {
123
+ $actor = $this->get_actor( $table_names );
124
+ if ( 'WordPress' === $actor && ! $this->plugin->settings()->is_wp_backend() ) {
125
+ // Event is not fired if the monitoring of background events is disabled.
126
  return;
127
  }
128
 
129
  // Loop through each item to report event per table.
130
  foreach ( $table_names as $table_name ) {
131
+ $alert_options = $this->get_event_options( $actor );
132
+ $event_code = $this->get_event_code( $actor, $query_type );
133
+ $db_op_key = $query_type . '_' . $table_name;
134
+ if ( in_array( $db_op_key, self::$already_logged ) ) { // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
135
  continue;
136
  }
137
 
138
  $alert_options['TableNames'] = $table_name;
139
+ $this->plugin->alerts->trigger_event( $event_code, $alert_options );
140
  array_push( self::$already_logged, $db_op_key );
141
  }
142
  }
149
  *
150
  * @return bool|string Theme, plugin or false if unknown.
151
  */
152
+ private function get_actor( $table_names ) {
153
+ // Default actor (treated as an unknown component).
154
  $result = false;
155
 
156
+ // Use current script name to determine if the actor is theme or a plugin.
 
157
  if ( is_null( $this->script_basename ) ) {
158
  $this->script_basename = isset( $_SERVER['SCRIPT_NAME'] ) ? basename( sanitize_text_field( wp_unslash( $_SERVER['SCRIPT_NAME'] ) ), '.php' ) : false;
159
  }
160
 
161
  $result = $this->script_basename;
162
 
163
+ // Check table names for default WordPress table names (including network tables).
164
+ if ( $this->contains_wordpress_table( $table_names ) ) {
165
+ $result = 'WordPress';
166
  }
167
 
168
  return $result;
169
  }
170
 
171
+ /**
172
+ * Checks if the list of tables contains a WordPress table.
173
+ *
174
+ * @param string $tables List of table names.
175
+ *
176
+ * @return bool True if the list contains a WordPress table.
177
+ */
178
+ private function contains_wordpress_table( $tables ) {
179
  if ( ! empty( $tables ) ) {
180
  global $wpdb;
181
+ $prefix = preg_quote( $wpdb->prefix ); // phpcs:ignore WordPress.PHP.PregQuoteDelimiter.Missing
182
  $site_regex = '/\b' . $prefix . '(\d+_)?(commentmeta|comments|links|options|postmeta|posts|terms|termmeta|term_relationships|term_relationships|term_taxonomy|usermeta|users)\b/';
183
  $network_regex = '/\b' . $prefix . '(blogs|blog_versions|registration_log|signups|site|sitemeta|users|usermeta)\b/';
184
 
185
  foreach ( $tables as $table ) {
186
  if ( preg_match( $site_regex, $table ) || preg_match( $network_regex, $table ) ) {
187
+ // Stop as soon as the first WordPress table is found.
188
  return true;
189
  }
190
  }
199
  * @param string $actor - Plugins, themes, WordPress or unknown.
200
  *
201
  * @return array
202
+ *
203
+ * phpcs:disable WordPress.Security.NonceVerification.Recommended
204
+ * phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotValidated
205
  */
206
+ protected function get_event_options( $actor ) {
207
+ // Check the actor.
208
  $alert_options = array();
209
  switch ( $actor ) {
210
  case 'plugins':
211
  // Action Plugin Component.
212
  $plugin_file = '';
213
 
 
214
  if ( isset( $_GET['plugin'] ) ) {
215
  $plugin_file = sanitize_text_field( wp_unslash( $_GET['plugin'] ) );
216
  } elseif ( isset( $_GET['checked'] ) ) {
217
  $plugin_file = sanitize_text_field( wp_unslash( $_GET['checked'][0] ) );
218
  }
 
219
 
220
  // Get plugin data.
221
  $plugins = get_plugins();
229
  'Version' => $plugin['Version'],
230
  );
231
  } else {
232
+ $plugin_name = basename( $plugin_file, '.php' );
233
+ $plugin_name = str_replace( array( '_', '-', ' ' ), ' ', $plugin_name );
234
+ $plugin_name = ucwords( $plugin_name );
235
 
236
  // If this is still empty at this point, lets check recent events.
237
  if ( empty( $plugin_file ) ) {
244
  case 'themes':
245
  // Action Theme Component.
246
  $theme_name = '';
 
 
247
  if ( isset( $_GET['theme'] ) ) {
248
  $theme_name = sanitize_text_field( wp_unslash( $_GET['theme'] ) );
249
  } elseif ( isset( $_GET['checked'] ) ) {
250
  $theme_name = sanitize_text_field( wp_unslash( $_GET['checked'][0] ) );
251
  }
 
252
 
253
  $theme_name = str_replace( array( '_', '-', ' ' ), ' ', $theme_name );
254
  $theme_name = ucwords( $theme_name );
255
  $alert_options['Theme'] = (object) array( 'Name' => $theme_name );
256
  break;
257
 
258
+ case 'WordPress':
259
  $alert_options['Component'] = 'WordPress';
260
  break;
261
 
276
  *
277
  * @return int Event code.
278
  */
279
+ protected function get_event_code( $actor, $query_type ) {
280
  switch ( $actor ) {
281
  case 'plugins':
282
  if ( 'create' === $query_type ) {
298
  }
299
  break;
300
 
301
+ case 'WordPress':
302
  if ( 'create' === $query_type ) {
303
  return 5022;
304
  } elseif ( 'update' === $query_type ) {
326
  *
327
  * @return array
328
  */
329
+ public function event_db_delta_query( $queries ) {
330
  if ( ! self::$enabled ) {
331
  return $queries;
332
  }
341
  $qry = str_replace( '`', '', $qry );
342
  $str = explode( ' ', $qry );
343
  if ( preg_match( '/CREATE TABLE( IF NOT EXISTS)? ([^ ]*)/i', $qry, $matches ) ) {
344
+ $table_name = $matches[ count( $matches ) - 1 ];
345
+ if ( $this->is_table_operation_check_enabled( $table_name, 'create' )
346
+ && ! $this->check_if_table_exists( $table_name ) ) {
347
  /**
348
  * Some plugins keep trying to create tables even
349
  * when they already exist- would result in too
355
  array_push( $query_types['update'], $str[2] );
356
  } elseif ( preg_match( '|DROP TABLE( IF EXISTS)? ([^ ]*)|', $qry ) ) {
357
  $table_name = empty( $str[4] ) ? $str[2] : $str[4];
358
+ // Only log when the table exists as some plugins try to delete tables even if they don't exist.
359
+ if ( $this->is_table_operation_check_enabled( $table_name, 'delete' )
360
+ && $this->check_if_table_exists( $table_name ) ) {
361
  array_push( $query_types['delete'], $table_name );
362
  }
363
  }
365
 
366
  if ( ! empty( $query_types['create'] ) || ! empty( $query_types['update'] ) || ! empty( $query_types['delete'] ) ) {
367
  foreach ( $query_types as $query_type => $table_names ) {
368
+ $this->maybe_trigger_event( $query_type, $table_names );
369
  }
370
  }
371
 
383
  $latest_events = $this->plugin->alerts->get_latest_events( 25 );
384
 
385
  foreach ( $latest_events as $latest_event ) {
386
+ if ( intval( $latest_event->alert_id ) === $alert_id ) {
387
+ $event_meta = $latest_event ? $latest_event->get_meta_array() : false;
388
  $plugin_name = $event_meta['PluginData']->Name;
389
  }
390
  }
407
  try {
408
  global $wpdb;
409
 
410
+ // Output buffering is here to prevent from error log messages that would be fired if the table didn't exist.
411
  ob_start();
412
+ $db_result = $wpdb->query( "SELECT COUNT(1) FROM {$table_name};" ); // phpcs:ignore
413
  ob_clean();
414
 
415
  return ( 1 === $db_result );
416
+ } catch ( Exception $e ) {
417
  return false;
418
  }
419
  }
425
  * if a specific alert is not enabled. Unfortunately if the alert is enabled or not is being checked
426
  * too late.
427
  *
428
+ * @param string $table_name Table name.
429
+ * @param string $query_type Query type.
430
  *
431
  * @return bool
432
+ * @see WSAL_AlertManager::commit_item()
433
  * @since 4.2.0
434
  */
435
  private function is_table_operation_check_enabled( $table_name, $query_type ) {
436
+ $actor = $this->get_actor( array( $table_name ) );
437
+ $event_code = $this->get_event_code( $actor, $query_type );
438
+
439
+ return $this->plugin->alerts->is_enabled( $event_code );
440
  }
441
  }
classes/Sensors/Files.php CHANGED
@@ -4,8 +4,9 @@
4
  *
5
  * Files sensors class file.
6
  *
7
- * @since 1.0.0
8
- * @package wsal
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -21,7 +22,7 @@ if ( ! defined( 'ABSPATH' ) ) {
21
  * 2046 User changed a file using the theme editor
22
  * 2051 User changed a file using the plugin editor
23
  *
24
- * @package wsal
25
  * @subpackage sensors
26
  */
27
  class WSAL_Sensors_Files extends WSAL_AbstractSensor {
@@ -34,12 +35,12 @@ class WSAL_Sensors_Files extends WSAL_AbstractSensor {
34
  protected $is_file_uploaded = false;
35
 
36
  /**
37
- * Listening to events using WP hooks.
38
  */
39
- public function HookEvents() {
40
- add_action( 'add_attachment', array( $this, 'EventFileUploaded' ) );
41
- add_action( 'delete_attachment', array( $this, 'EventFileUploadedDeleted' ) );
42
- add_action( 'admin_init', array( $this, 'EventAdminInit' ) );
43
  }
44
 
45
  /**
@@ -47,15 +48,16 @@ class WSAL_Sensors_Files extends WSAL_AbstractSensor {
47
  *
48
  * @param integer $attachment_id - Attachment ID.
49
  */
50
- public function EventFileUploaded( $attachment_id ) {
51
  // Filter $_POST array for security.
52
  $post_array = filter_input_array( INPUT_POST );
53
 
54
  $action = isset( $post_array['action'] ) ? $post_array['action'] : '';
55
- if ( 'upload-theme' !== $action && 'upload-plugin' !== $action ) {
56
  $file = get_attached_file( $attachment_id );
57
- $this->plugin->alerts->Trigger(
58
- 2010, array(
 
59
  'AttachmentID' => $attachment_id,
60
  'FileName' => basename( $file ),
61
  'FilePath' => dirname( $file ),
@@ -71,13 +73,14 @@ class WSAL_Sensors_Files extends WSAL_AbstractSensor {
71
  *
72
  * @param integer $attachment_id - Attachment ID.
73
  */
74
- public function EventFileUploadedDeleted( $attachment_id ) {
75
  if ( $this->is_file_uploaded ) {
76
  return;
77
  }
78
  $file = get_attached_file( $attachment_id );
79
- $this->plugin->alerts->Trigger(
80
- 2011, array(
 
81
  'AttachmentID' => $attachment_id,
82
  'FileName' => basename( $file ),
83
  'FilePath' => dirname( $file ),
@@ -90,7 +93,7 @@ class WSAL_Sensors_Files extends WSAL_AbstractSensor {
90
  *
91
  * Detect file changes in plugins/themes using plugin/theme editor.
92
  */
93
- public function EventAdminInit() {
94
  // @codingStandardsIgnoreStart
95
  $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : false;
96
  $file = isset( $_POST['file'] ) ? sanitize_text_field( wp_unslash( $_POST['file'] ) ) : false;
@@ -103,8 +106,9 @@ class WSAL_Sensors_Files extends WSAL_AbstractSensor {
103
  if ( 'edit-theme-plugin-file' === $action ) {
104
  if ( 'plugin-editor' === $referer && wp_verify_nonce( $nonce, 'edit-plugin_' . $file ) ) {
105
  $plugin = isset( $_POST['plugin'] ) ? sanitize_text_field( wp_unslash( $_POST['plugin'] ) ) : false;
106
- $this->plugin->alerts->Trigger(
107
- 2051, array(
 
108
  'File' => $file,
109
  'Plugin' => $plugin,
110
  )
@@ -116,8 +120,9 @@ class WSAL_Sensors_Files extends WSAL_AbstractSensor {
116
  return;
117
  }
118
 
119
- $this->plugin->alerts->Trigger(
120
- 2046, array(
 
121
  'File' => $file,
122
  'Theme' => trailingslashit( get_theme_root() ) . $stylesheet,
123
  )
4
  *
5
  * Files sensors class file.
6
  *
7
+ * @since 1.0.0
8
+ * @package wsal
9
+ * @subpackage sensors
10
  */
11
 
12
  // Exit if accessed directly.
22
  * 2046 User changed a file using the theme editor
23
  * 2051 User changed a file using the plugin editor
24
  *
25
+ * @package wsal
26
  * @subpackage sensors
27
  */
28
  class WSAL_Sensors_Files extends WSAL_AbstractSensor {
35
  protected $is_file_uploaded = false;
36
 
37
  /**
38
+ * {@inheritDoc}
39
  */
40
+ public function hook_events() {
41
+ add_action( 'add_attachment', array( $this, 'event_file_uploaded' ) );
42
+ add_action( 'delete_attachment', array( $this, 'event_file_uploaded_deleted' ) );
43
+ add_action( 'admin_init', array( $this, 'event_admin_init' ) );
44
  }
45
 
46
  /**
48
  *
49
  * @param integer $attachment_id - Attachment ID.
50
  */
51
+ public function event_file_uploaded( $attachment_id ) {
52
  // Filter $_POST array for security.
53
  $post_array = filter_input_array( INPUT_POST );
54
 
55
  $action = isset( $post_array['action'] ) ? $post_array['action'] : '';
56
+ if ( 'upload-theme' !== $action && 'upload-plugin' !== $action ) {
57
  $file = get_attached_file( $attachment_id );
58
+ $this->plugin->alerts->trigger_event(
59
+ 2010,
60
+ array(
61
  'AttachmentID' => $attachment_id,
62
  'FileName' => basename( $file ),
63
  'FilePath' => dirname( $file ),
73
  *
74
  * @param integer $attachment_id - Attachment ID.
75
  */
76
+ public function event_file_uploaded_deleted( $attachment_id ) {
77
  if ( $this->is_file_uploaded ) {
78
  return;
79
  }
80
  $file = get_attached_file( $attachment_id );
81
+ $this->plugin->alerts->trigger_event(
82
+ 2011,
83
+ array(
84
  'AttachmentID' => $attachment_id,
85
  'FileName' => basename( $file ),
86
  'FilePath' => dirname( $file ),
93
  *
94
  * Detect file changes in plugins/themes using plugin/theme editor.
95
  */
96
+ public function event_admin_init() {
97
  // @codingStandardsIgnoreStart
98
  $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : false;
99
  $file = isset( $_POST['file'] ) ? sanitize_text_field( wp_unslash( $_POST['file'] ) ) : false;
106
  if ( 'edit-theme-plugin-file' === $action ) {
107
  if ( 'plugin-editor' === $referer && wp_verify_nonce( $nonce, 'edit-plugin_' . $file ) ) {
108
  $plugin = isset( $_POST['plugin'] ) ? sanitize_text_field( wp_unslash( $_POST['plugin'] ) ) : false;
109
+ $this->plugin->alerts->trigger_event(
110
+ 2051,
111
+ array(
112
  'File' => $file,
113
  'Plugin' => $plugin,
114
  )
120
  return;
121
  }
122
 
123
+ $this->plugin->alerts->trigger_event(
124
+ 2046,
125
+ array(
126
  'File' => $file,
127
  'Theme' => trailingslashit( get_theme_root() ) . $stylesheet,
128
  )
classes/Sensors/LogInOut.php CHANGED
@@ -4,8 +4,9 @@
4
  *
5
  * Log In & Out sensor class file.
6
  *
7
- * @since 1.0.0
8
- * @package wsal
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -23,7 +24,7 @@ if ( ! defined( 'ABSPATH' ) ) {
23
  * 1004 Login blocked
24
  * 4003 User has changed his or her password
25
  *
26
- * @package wsal
27
  * @subpackage sensors
28
  */
29
  class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
@@ -40,18 +41,17 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
40
  *
41
  * @var WP_User
42
  */
43
- protected $_current_user = null;
44
 
45
  /**
46
- * Listening to events using WP hooks.
47
  */
48
- public function HookEvents() {
49
- add_action( 'set_auth_cookie', array( $this, 'EventLogin' ), 10, 6 );
50
- add_action( 'wp_logout', array( $this, 'EventLogout' ), 5 );
51
- add_action( 'password_reset', array( $this, 'EventPasswordReset' ), 10, 2 );
52
- add_action( 'wp_login_failed', array( $this, 'EventLoginFailure' ) );
53
- add_action( 'clear_auth_cookie', array( $this, 'GetCurrentUser' ), 10 );
54
- add_filter( 'wp_login_blocked', array( $this, 'EventLoginBlocked' ), 10, 1 );
55
  add_action( 'lostpassword_post', array( $this, 'event_user_requested_pw_reset' ), 10, 2 );
56
 
57
  if ( WpSecurityAuditLog::is_twofactor_active() ) {
@@ -61,14 +61,13 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
61
  if ( WpSecurityAuditLog::is_plugin_active( 'user-switching/user-switching.php' ) ) {
62
  add_action( 'switch_to_user', array( $this, 'user_switched_event' ), 10, 2 );
63
  }
64
-
65
  }
66
 
67
  /**
68
  * Sets current user.
69
  */
70
- public function GetCurrentUser() {
71
- $this->_current_user = wp_get_current_user();
72
  }
73
 
74
  /**
@@ -97,13 +96,13 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
97
  // If provider and user are set and provider is known then log the event.
98
  if ( $provider && $user && in_array( $provider, $providers_2fa, true ) ) {
99
  // Get user roles.
100
- $user_roles = $this->plugin->settings()->GetCurrentUserRoles( $user->roles );
101
 
102
- if ( $this->plugin->settings()->IsLoginSuperAdmin( $user->user_login ) ) {
103
  $user_roles[] = 'superadmin';
104
  }
105
 
106
- $this->plugin->alerts->Trigger(
107
  1000,
108
  array(
109
  'Username' => $user->user_login,
@@ -128,7 +127,7 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
128
  * @param string $scheme Authentication scheme. Values include 'auth' or 'secure_auth'.
129
  * @param string $token User's session token to use for this cookie.
130
  */
131
- public function EventLogin( $auth_cookie, $expire, $expiration, $user_id, $scheme, $token ) {
132
  // Get global POST array.
133
  $post_array = filter_input_array( INPUT_POST );
134
 
@@ -158,8 +157,8 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
158
 
159
  // Log user changed password alert.
160
  if ( ! empty( $user ) ) {
161
- $user_roles = $this->plugin->settings()->GetCurrentUserRoles( $user->roles );
162
- $this->plugin->alerts->Trigger(
163
  4003,
164
  array(
165
  'Username' => $user->user_login,
@@ -178,9 +177,9 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
178
  return;
179
  }
180
  $user_login = $user->data->user_login;
181
- $user_roles = $this->plugin->settings()->GetCurrentUserRoles( $user->roles );
182
 
183
- if ( $this->plugin->settings()->IsLoginSuperAdmin( $user_login ) ) {
184
  $user_roles[] = 'superadmin';
185
  }
186
 
@@ -192,17 +191,18 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
192
  $alert_data['SessionID'] = WSAL_UserSessions_Helpers::hash_token( $token );
193
  }
194
 
195
- $this->plugin->alerts->TriggerIf(
196
  1000,
197
  $alert_data,
198
  /**
 
 
199
  * @param WSAL_AlertManager $manager
200
  *
201
  * @return bool
202
  */
203
  function ( $manager ) {
204
- // don't fire if the user is changing their password via admin profile page
205
- return ! $manager->WillOrHasTriggered( 4003 );
206
  }
207
  );
208
 
@@ -211,10 +211,10 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
211
  /**
212
  * Event Logout.
213
  */
214
- public function EventLogout() {
215
- if ( $this->_current_user->ID ) {
216
  // get the list of excluded users.
217
- $excluded_users = $this->plugin->settings()->GetExcludedMonitoringUsers();
218
  $excluded_user_ids = array();
219
  // convert excluded usernames into IDs.
220
  if ( ! empty( $excluded_users ) && is_array( $excluded_users ) ) {
@@ -224,14 +224,14 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
224
  }
225
  }
226
  // bail early if this user is in the excluded ids list.
227
- if ( in_array( $this->_current_user->ID, $excluded_user_ids, true ) ) {
228
  return;
229
  }
230
- $this->plugin->alerts->Trigger(
231
  1001,
232
  array(
233
- 'CurrentUserID' => $this->_current_user->ID,
234
- 'CurrentUserRoles' => $this->plugin->settings()->GetCurrentUserRoles( $this->_current_user->roles ),
235
  ),
236
  true
237
  );
@@ -243,7 +243,7 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
243
  *
244
  * @return int
245
  */
246
- protected function GetLoginFailureLogLimit() {
247
  return $this->plugin->settings()->get_failed_login_limit();
248
  }
249
 
@@ -252,7 +252,7 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
252
  *
253
  * @return int
254
  */
255
- protected function GetVisitorLoginFailureLogLimit() {
256
  return $this->plugin->settings()->get_visitor_failed_login_limit();
257
  }
258
 
@@ -261,7 +261,7 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
261
  *
262
  * @return integer Time until expiration in seconds from now
263
  */
264
- protected function GetLoginFailureExpiration() {
265
  return 12 * 60 * 60;
266
  }
267
 
@@ -273,21 +273,21 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
273
  * @param WP_User $user - User object.
274
  * @return boolean - Passed limit true|false.
275
  */
276
- protected function IsPastLoginFailureLimit( $ip, $site_id, $user ) {
277
- $get_fn = $this->IsMultisite() ? 'get_site_transient' : 'get_transient';
278
  if ( $user ) {
279
- if ( -1 === (int) $this->GetLoginFailureLogLimit() ) {
280
  return false;
281
  } else {
282
  $data_known = $get_fn( self::TRANSIENT_FAILEDLOGINS );
283
- return ( false !== $data_known ) && isset( $data_known[ $site_id . ':' . $user->ID . ':' . $ip ] ) && ( $data_known[ $site_id . ':' . $user->ID . ':' . $ip ] >= $this->GetLoginFailureLogLimit() );
284
  }
285
  } else {
286
- if ( -1 === (int) $this->GetVisitorLoginFailureLogLimit() ) {
287
  return false;
288
  } else {
289
  $data_unknown = $get_fn( self::TRANSIENT_FAILEDLOGINS_UNKNOWN );
290
- return ( false !== $data_unknown ) && isset( $data_unknown[ $site_id . ':' . $ip ] ) && ( $data_unknown[ $site_id . ':' . $ip ] >= $this->GetVisitorLoginFailureLogLimit() );
291
  }
292
  }
293
  }
@@ -299,9 +299,9 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
299
  * @param integer $site_id - Blog ID.
300
  * @param WP_User $user - User object.
301
  */
302
- protected function IncrementLoginFailure( $ip, $site_id, $user ) {
303
- $get_fn = $this->IsMultisite() ? 'get_site_transient' : 'get_transient';
304
- $set_fn = $this->IsMultisite() ? 'set_site_transient' : 'set_transient';
305
  if ( $user ) {
306
  $data_known = $get_fn( self::TRANSIENT_FAILEDLOGINS );
307
  if ( ! $data_known ) {
@@ -311,7 +311,7 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
311
  $data_known[ $site_id . ':' . $user->ID . ':' . $ip ] = 1;
312
  }
313
  $data_known[ $site_id . ':' . $user->ID . ':' . $ip ]++;
314
- $set_fn( self::TRANSIENT_FAILEDLOGINS, $data_known, $this->GetLoginFailureExpiration() );
315
  } else {
316
  $data_unknown = $get_fn( self::TRANSIENT_FAILEDLOGINS_UNKNOWN );
317
  if ( ! $data_unknown ) {
@@ -321,7 +321,7 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
321
  $data_unknown[ $site_id . ':' . $ip ] = 1;
322
  }
323
  $data_unknown[ $site_id . ':' . $ip ]++;
324
- $set_fn( self::TRANSIENT_FAILEDLOGINS_UNKNOWN, $data_unknown, $this->GetLoginFailureExpiration() );
325
  }
326
  }
327
 
@@ -330,10 +330,10 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
330
  *
331
  * @param string $username Username.
332
  */
333
- public function EventLoginFailure( $username ) {
334
- list($y, $m, $d) = explode( '-', date( 'Y-m-d' ) );
335
 
336
- $ip = $this->plugin->settings()->GetMainClientIP();
337
 
338
  // Filter $_POST global array for security.
339
  $post_array = filter_input_array( INPUT_POST );
@@ -346,31 +346,32 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
346
  if ( empty( $user ) ) {
347
  $user = get_user_by( 'email', $username );
348
  }
349
- $site_id = ( function_exists( 'get_current_blog_id' ) ? get_current_blog_id() : 0 );
 
350
  if ( $user ) {
351
  $new_alert_code = 1002;
352
- $user_roles = $this->plugin->settings()->GetCurrentUserRoles( $user->roles );
353
- if ( $this->plugin->settings()->IsLoginSuperAdmin( $username ) ) {
354
  $user_roles[] = 'superadmin';
355
  }
356
  }
357
 
358
  // Check if the alert is disabled from the "Enable/Disable Alerts" section.
359
- if ( ! $this->plugin->alerts->IsEnabled( $new_alert_code ) ) {
360
  return;
361
  }
362
 
363
- if ( $this->IsPastLoginFailureLimit( $ip, $site_id, $user ) ) {
364
  return;
365
  }
366
 
367
  $obj_occurrence = new WSAL_Models_Occurrence();
368
 
369
  if ( 1002 === $new_alert_code ) {
370
- if ( ! $this->plugin->alerts->CheckEnableUserRoles( $username, $user_roles ) ) {
371
  return;
372
  }
373
- $occ = $obj_occurrence->CheckKnownUsers(
374
  array(
375
  $ip,
376
  $username,
@@ -382,29 +383,28 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
382
  );
383
  $occ = count( $occ ) ? $occ[0] : null;
384
 
385
- if ($this->plugin->alerts->WillOrHasTriggered(1004)) {
386
- // skip if 1004 (session block) is already in place
387
  return;
388
  }
389
 
390
  if ( ! empty( $occ ) ) {
391
  // Update existing record exists user.
392
- $this->IncrementLoginFailure( $ip, $site_id, $user );
393
- $new = $occ->GetMetaValue( 'Attempts', 0 ) + 1;
394
 
395
- $login_failure_log_limit = $this->GetLoginFailureLogLimit();
396
- if ( - 1 !== $login_failure_log_limit
397
- && $new > $login_failure_log_limit ) {
398
  $new = $login_failure_log_limit . '+';
399
  }
400
 
401
- $occ->UpdateMetaValue( 'Attempts', $new );
402
- $occ->username = $username;
403
  $occ->created_on = null;
404
- $occ->Save();
405
  } else {
406
  // Create a new record exists user.
407
- $this->plugin->alerts->Trigger(
408
  $new_alert_code,
409
  array(
410
  'Attempts' => 1,
@@ -413,18 +413,19 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
413
  'CurrentUserRoles' => $user_roles,
414
  ),
415
  /**
 
 
416
  * @param WSAL_AlertManager $manager
417
  *
418
  * @return bool
419
  */
420
  function ( $manager ) {
421
- // skip if 1004 (session block) is already in place
422
- return !$manager->WillOrHasTriggered(1004);
423
  }
424
  );
425
  }
426
  } else {
427
- $occ_unknown = $obj_occurrence->CheckUnknownUsers(
428
  array(
429
  $ip,
430
  1003,
@@ -437,40 +438,40 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
437
  $occ_unknown = count( $occ_unknown ) ? $occ_unknown[0] : null;
438
  if ( ! empty( $occ_unknown ) ) {
439
  // Update existing record not exists user.
440
- $this->IncrementLoginFailure( $ip, $site_id, false );
441
 
442
  // Increase the number of attempts.
443
- $new = $occ_unknown->GetMetaValue( 'Attempts', 0 ) + 1;
444
 
445
  // If login attempts pass allowed number of attempts then stop increasing the attempts.
446
- $failure_limit = $this->GetVisitorLoginFailureLogLimit();
447
  if ( -1 !== $failure_limit && $new > $failure_limit ) {
448
  $new = $failure_limit . '+';
449
  }
450
 
451
  // Update the number of login attempts.
452
- $occ_unknown->UpdateMetaValue( 'Attempts', $new );
453
 
454
  // Get users from alert.
455
- $users = $occ_unknown->GetMetaValue( 'Users' );
456
 
457
  // Update it if username is not already present in the array.
458
  if ( ! empty( $users ) && is_array( $users ) && ! in_array( $username, $users, true ) ) {
459
  $users[] = $username;
460
- $occ_unknown->UpdateMetaValue( 'Users', $users );
461
  } else {
462
  // In this case the value doesn't exist so set the value to array.
463
- $users = array( $username );
464
  }
465
 
466
  $occ_unknown->created_on = null;
467
- $occ_unknown->Save();
468
  } else {
469
  // Make an array of usernames.
470
  $users = array( $username );
471
 
472
  // Log an alert for a login attempt with unknown username.
473
- $this->plugin->alerts->Trigger(
474
  $new_alert_code,
475
  array(
476
  'Attempts' => 1,
@@ -489,10 +490,10 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
489
  * @param WP_User $user - User object.
490
  * @param string $new_pass - New Password.
491
  */
492
- public function EventPasswordReset( $user, $new_pass ) {
493
  if ( ! empty( $user ) ) {
494
- $user_roles = $this->plugin->settings()->GetCurrentUserRoles( $user->roles );
495
- $this->plugin->alerts->Trigger(
496
  4003,
497
  array(
498
  'Username' => $user->user_login,
@@ -515,12 +516,12 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
515
  */
516
  public function user_switched_event( $new_user_id, $old_user_id ) {
517
  $target_user = get_user_by( 'ID', $new_user_id );
518
- $target_user_roles = $this->plugin->settings()->GetCurrentUserRoles( $target_user->roles );
519
  $target_user_roles = implode( ', ', $target_user_roles );
520
  $old_user = get_user_by( 'ID', $old_user_id );
521
- $old_user_roles = $this->plugin->settings()->GetCurrentUserRoles( $old_user->roles );
522
 
523
- $this->plugin->alerts->Trigger(
524
  1008,
525
  array(
526
  'TargetUserName' => $target_user->user_login,
@@ -534,18 +535,18 @@ class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
534
  /**
535
  * User has requested a password reset.
536
  *
537
- * @param object $errors Current WP_errors objtect.
538
  * @param object $user User making the request.
539
  */
540
  public function event_user_requested_pw_reset( $errors, $user = null ) {
541
-
542
- // If we dont have the user. do nothing.
543
  if ( is_null( $user ) || ! isset( $user->roles ) ) {
544
  return;
545
  }
546
-
547
- $user_roles = $this->plugin->settings()->GetCurrentUserRoles( $user->roles );
548
- $this->plugin->alerts->Trigger(
549
  1010,
550
  array(
551
  'Username' => $user->user_login,
4
  *
5
  * Log In & Out sensor class file.
6
  *
7
+ * @since 1.0.0
8
+ * @package wsal
9
+ * @subpackage sensors
10
  */
11
 
12
  // Exit if accessed directly.
24
  * 1004 Login blocked
25
  * 4003 User has changed his or her password
26
  *
27
+ * @package wsal
28
  * @subpackage sensors
29
  */
30
  class WSAL_Sensors_LogInOut extends WSAL_AbstractSensor {
41
  *
42
  * @var WP_User
43
  */
44
+ protected $current_user = null;
45
 
46
  /**
47
+ * {@inheritDoc}
48
  */
49
+ public function hook_events() {
50
+ add_action( 'set_auth_cookie', array( $this, 'event_login' ), 10, 6 );
51
+ add_action( 'wp_logout', array( $this, 'event_logout' ), 5 );
52
+ add_action( 'password_reset', array( $this, 'event_password_reset' ), 10, 2 );
53
+ add_action( 'wp_login_failed', array( $this, 'event_login_failure' ) );
54
+ add_action( 'clear_auth_cookie', array( $this, 'get_current_user' ), 10 );
 
55
  add_action( 'lostpassword_post', array( $this, 'event_user_requested_pw_reset' ), 10, 2 );
56
 
57
  if ( WpSecurityAuditLog::is_twofactor_active() ) {
61
  if ( WpSecurityAuditLog::is_plugin_active( 'user-switching/user-switching.php' ) ) {
62
  add_action( 'switch_to_user', array( $this, 'user_switched_event' ), 10, 2 );
63
  }
 
64
  }
65
 
66
  /**
67
  * Sets current user.
68
  */
69
+ public function get_current_user() {
70
+ $this->current_user = wp_get_current_user();
71
  }
72
 
73
  /**
96
  // If provider and user are set and provider is known then log the event.
97
  if ( $provider && $user && in_array( $provider, $providers_2fa, true ) ) {
98
  // Get user roles.
99
+ $user_roles = $this->plugin->settings()->get_current_user_roles( $user->roles );
100
 
101
+ if ( $this->plugin->settings()->is_login_super_admin( $user->user_login ) ) {
102
  $user_roles[] = 'superadmin';
103
  }
104
 
105
+ $this->plugin->alerts->trigger_event(
106
  1000,
107
  array(
108
  'Username' => $user->user_login,
127
  * @param string $scheme Authentication scheme. Values include 'auth' or 'secure_auth'.
128
  * @param string $token User's session token to use for this cookie.
129
  */
130
+ public function event_login( $auth_cookie, $expire, $expiration, $user_id, $scheme, $token ) {
131
  // Get global POST array.
132
  $post_array = filter_input_array( INPUT_POST );
133
 
157
 
158
  // Log user changed password alert.
159
  if ( ! empty( $user ) ) {
160
+ $user_roles = $this->plugin->settings()->get_current_user_roles( $user->roles );
161
+ $this->plugin->alerts->trigger_event(
162
  4003,
163
  array(
164
  'Username' => $user->user_login,
177
  return;
178
  }
179
  $user_login = $user->data->user_login;
180
+ $user_roles = $this->plugin->settings()->get_current_user_roles( $user->roles );
181
 
182
+ if ( $this->plugin->settings()->is_login_super_admin( $user_login ) ) {
183
  $user_roles[] = 'superadmin';
184
  }
185
 
191
  $alert_data['SessionID'] = WSAL_UserSessions_Helpers::hash_token( $token );
192
  }
193
 
194
+ $this->plugin->alerts->trigger_event_if(
195
  1000,
196
  $alert_data,
197
  /**
198
+ * Don't fire if the user is changing their password via admin profile page.
199
+ *
200
  * @param WSAL_AlertManager $manager
201
  *
202
  * @return bool
203
  */
204
  function ( $manager ) {
205
+ return ! $manager->will_or_has_triggered( 4003 );
 
206
  }
207
  );
208
 
211
  /**
212
  * Event Logout.
213
  */
214
+ public function event_logout() {
215
+ if ( $this->current_user->ID ) {
216
  // get the list of excluded users.
217
+ $excluded_users = $this->plugin->settings()->get_excluded_monitoring_users();
218
  $excluded_user_ids = array();
219
  // convert excluded usernames into IDs.
220
  if ( ! empty( $excluded_users ) && is_array( $excluded_users ) ) {
224
  }
225
  }
226
  // bail early if this user is in the excluded ids list.
227
+ if ( in_array( $this->current_user->ID, $excluded_user_ids, true ) ) {
228
  return;
229
  }
230
+ $this->plugin->alerts->trigger_event(
231
  1001,
232
  array(
233
+ 'CurrentUserID' => $this->current_user->ID,
234
+ 'CurrentUserRoles' => $this->plugin->settings()->get_current_user_roles( $this->current_user->roles ),
235
  ),
236
  true
237
  );
243
  *
244
  * @return int
245
  */
246
+ protected function get_login_failure_log_limit() {
247
  return $this->plugin->settings()->get_failed_login_limit();
248
  }
249
 
252
  *
253
  * @return int
254
  */
255
+ protected function get_visitor_login_failure_log_limit() {
256
  return $this->plugin->settings()->get_visitor_failed_login_limit();
257
  }
258
 
261
  *
262
  * @return integer Time until expiration in seconds from now
263
  */
264
+ protected function get_login_failure_expiration() {
265
  return 12 * 60 * 60;
266
  }
267
 
273
  * @param WP_User $user - User object.
274
  * @return boolean - Passed limit true|false.
275
  */
276
+ protected function is_past_login_failure_limit( $ip, $site_id, $user ) {
277
+ $get_fn = $this->is_multisite() ? 'get_site_transient' : 'get_transient';
278
  if ( $user ) {
279
+ if ( -1 === (int) $this->get_login_failure_log_limit() ) {
280
  return false;
281
  } else {
282
  $data_known = $get_fn( self::TRANSIENT_FAILEDLOGINS );
283
+ return ( false !== $data_known ) && isset( $data_known[ $site_id . ':' . $user->ID . ':' . $ip ] ) && ( $data_known[ $site_id . ':' . $user->ID . ':' . $ip ] >= $this->get_login_failure_log_limit() );
284
  }
285
  } else {
286
+ if ( -1 === (int) $this->get_visitor_login_failure_log_limit() ) {
287
  return false;
288
  } else {
289
  $data_unknown = $get_fn( self::TRANSIENT_FAILEDLOGINS_UNKNOWN );
290
+ return ( false !== $data_unknown ) && isset( $data_unknown[ $site_id . ':' . $ip ] ) && ( $data_unknown[ $site_id . ':' . $ip ] >= $this->get_visitor_login_failure_log_limit() );
291
  }
292
  }
293
  }
299
  * @param integer $site_id - Blog ID.
300
  * @param WP_User $user - User object.
301
  */
302
+ protected function increment_login_failure( $ip, $site_id, $user ) {
303
+ $get_fn = $this->is_multisite() ? 'get_site_transient' : 'get_transient';
304
+ $set_fn = $this->is_multisite() ? 'set_site_transient' : 'set_transient';
305
  if ( $user ) {
306
  $data_known = $get_fn( self::TRANSIENT_FAILEDLOGINS );
307
  if ( ! $data_known ) {
311
  $data_known[ $site_id . ':' . $user->ID . ':' . $ip ] = 1;
312
  }
313
  $data_known[ $site_id . ':' . $user->ID . ':' . $ip ]++;
314
+ $set_fn( self::TRANSIENT_FAILEDLOGINS, $data_known, $this->get_login_failure_expiration() );
315
  } else {
316
  $data_unknown = $get_fn( self::TRANSIENT_FAILEDLOGINS_UNKNOWN );
317
  if ( ! $data_unknown ) {
321
  $data_unknown[ $site_id . ':' . $ip ] = 1;
322
  }
323
  $data_unknown[ $site_id . ':' . $ip ]++;
324
+ $set_fn( self::TRANSIENT_FAILEDLOGINS_UNKNOWN, $data_unknown, $this->get_login_failure_expiration() );
325
  }
326
  }
327
 
330
  *
331
  * @param string $username Username.
332
  */
333
+ public function event_login_failure( $username ) {
334
+ list($y, $m, $d) = explode( '-', date( 'Y-m-d' ) ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
335
 
336
+ $ip = $this->plugin->settings()->get_main_client_ip();
337
 
338
  // Filter $_POST global array for security.
339
  $post_array = filter_input_array( INPUT_POST );
346
  if ( empty( $user ) ) {
347
  $user = get_user_by( 'email', $username );
348
  }
349
+
350
+ $site_id = ( function_exists( 'get_current_blog_id' ) ? get_current_blog_id() : 0 );
351
  if ( $user ) {
352
  $new_alert_code = 1002;
353
+ $user_roles = $this->plugin->settings()->get_current_user_roles( $user->roles );
354
+ if ( $this->plugin->settings()->is_login_super_admin( $username ) ) {
355
  $user_roles[] = 'superadmin';
356
  }
357
  }
358
 
359
  // Check if the alert is disabled from the "Enable/Disable Alerts" section.
360
+ if ( ! $this->plugin->alerts->is_enabled( $new_alert_code ) ) {
361
  return;
362
  }
363
 
364
+ if ( $this->is_past_login_failure_limit( $ip, $site_id, $user ) ) {
365
  return;
366
  }
367
 
368
  $obj_occurrence = new WSAL_Models_Occurrence();
369
 
370
  if ( 1002 === $new_alert_code ) {
371
+ if ( ! $this->plugin->alerts->check_enable_user_roles( $username, $user_roles ) ) {
372
  return;
373
  }
374
+ $occ = $obj_occurrence->check_known_users(
375
  array(
376
  $ip,
377
  $username,
383
  );
384
  $occ = count( $occ ) ? $occ[0] : null;
385
 
386
+ if ( $this->plugin->alerts->will_or_has_triggered( 1004 ) ) {
387
+ // Skip if 1004 (session block) is already in place.
388
  return;
389
  }
390
 
391
  if ( ! empty( $occ ) ) {
392
  // Update existing record exists user.
393
+ $this->increment_login_failure( $ip, $site_id, $user );
394
+ $new = $occ->get_meta_value( 'Attempts', 0 ) + 1;
395
 
396
+ $login_failure_log_limit = $this->get_login_failure_log_limit();
397
+ if ( - 1 !== $login_failure_log_limit && $new > $login_failure_log_limit ) {
 
398
  $new = $login_failure_log_limit . '+';
399
  }
400
 
401
+ $occ->update_meta_value( 'Attempts', $new );
402
+ $occ->username = $username;
403
  $occ->created_on = null;
404
+ $occ->save();
405
  } else {
406
  // Create a new record exists user.
407
+ $this->plugin->alerts->trigger_event(
408
  $new_alert_code,
409
  array(
410
  'Attempts' => 1,
413
  'CurrentUserRoles' => $user_roles,
414
  ),
415
  /**
416
+ * Skip if 1004 (session block) is already in place.
417
+ *
418
  * @param WSAL_AlertManager $manager
419
  *
420
  * @return bool
421
  */
422
  function ( $manager ) {
423
+ return ! $manager->will_or_has_triggered( 1004 );
 
424
  }
425
  );
426
  }
427
  } else {
428
+ $occ_unknown = $obj_occurrence->check_unknown_users(
429
  array(
430
  $ip,
431
  1003,
438
  $occ_unknown = count( $occ_unknown ) ? $occ_unknown[0] : null;
439
  if ( ! empty( $occ_unknown ) ) {
440
  // Update existing record not exists user.
441
+ $this->increment_login_failure( $ip, $site_id, false );
442
 
443
  // Increase the number of attempts.
444
+ $new = $occ_unknown->get_meta_value( 'Attempts', 0 ) + 1;
445
 
446
  // If login attempts pass allowed number of attempts then stop increasing the attempts.
447
+ $failure_limit = $this->get_visitor_login_failure_log_limit();
448
  if ( -1 !== $failure_limit && $new > $failure_limit ) {
449
  $new = $failure_limit . '+';
450
  }
451
 
452
  // Update the number of login attempts.
453
+ $occ_unknown->update_meta_value( 'Attempts', $new );
454
 
455
  // Get users from alert.
456
+ $users = $occ_unknown->get_meta_value( 'Users' );
457
 
458
  // Update it if username is not already present in the array.
459
  if ( ! empty( $users ) && is_array( $users ) && ! in_array( $username, $users, true ) ) {
460
  $users[] = $username;
461
+ $occ_unknown->update_meta_value( 'Users', $users );
462
  } else {
463
  // In this case the value doesn't exist so set the value to array.
464
+ $users = array( $username );
465
  }
466
 
467
  $occ_unknown->created_on = null;
468
+ $occ_unknown->save();
469
  } else {
470
  // Make an array of usernames.
471
  $users = array( $username );
472
 
473
  // Log an alert for a login attempt with unknown username.
474
+ $this->plugin->alerts->trigger_event(
475
  $new_alert_code,
476
  array(
477
  'Attempts' => 1,
490
  * @param WP_User $user - User object.
491
  * @param string $new_pass - New Password.
492
  */
493
+ public function event_password_reset( $user, $new_pass ) {
494
  if ( ! empty( $user ) ) {
495
+ $user_roles = $this->plugin->settings()->get_current_user_roles( $user->roles );
496
+ $this->plugin->alerts->trigger_event(
497
  4003,
498
  array(
499
  'Username' => $user->user_login,
516
  */
517
  public function user_switched_event( $new_user_id, $old_user_id ) {
518
  $target_user = get_user_by( 'ID', $new_user_id );
519
+ $target_user_roles = $this->plugin->settings()->get_current_user_roles( $target_user->roles );
520
  $target_user_roles = implode( ', ', $target_user_roles );
521
  $old_user = get_user_by( 'ID', $old_user_id );
522
+ $old_user_roles = $this->plugin->settings()->get_current_user_roles( $old_user->roles );
523
 
524
+ $this->plugin->alerts->trigger_event(
525
  1008,
526
  array(
527
  'TargetUserName' => $target_user->user_login,
535
  /**
536
  * User has requested a password reset.
537
  *
538
+ * @param object $errors Current WP_errors object.
539
  * @param object $user User making the request.
540
  */
541
  public function event_user_requested_pw_reset( $errors, $user = null ) {
542
+
543
+ // If we don't have the user, do nothing.
544
  if ( is_null( $user ) || ! isset( $user->roles ) ) {
545
  return;
546
  }
547
+
548
+ $user_roles = $this->plugin->settings()->get_current_user_roles( $user->roles );
549
+ $this->plugin->alerts->trigger_event(
550
  1010,
551
  array(
552
  'Username' => $user->user_login,
classes/Sensors/MainWP.php CHANGED
@@ -4,8 +4,9 @@
4
  *
5
  * MainWP Plugins & Themes sensor file.
6
  *
7
- * @since 4.1.4
8
- * @package wsal
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -26,7 +27,7 @@ if ( ! defined( 'ABSPATH' ) ) {
26
  * 5007 User uninstalled a theme
27
  * 5031 User updated a theme
28
  *
29
- * @package wsal
30
  * @subpackage sensors
31
  */
32
  class WSAL_Sensors_MainWP extends WSAL_AbstractSensor {
@@ -39,11 +40,11 @@ class WSAL_Sensors_MainWP extends WSAL_AbstractSensor {
39
  protected $old_themes = array();
40
 
41
  /**
42
- * Listening to events using WP hooks.as
43
  */
44
- public function HookEvents() {
45
 
46
- add_action( 'admin_init', array( $this, 'EventAdminInit' ) );
47
 
48
  // Check if MainWP Child Plugin exists.
49
  if ( WpSecurityAuditLog::is_mainwp_active() ) {
@@ -64,15 +65,14 @@ class WSAL_Sensors_MainWP extends WSAL_AbstractSensor {
64
  add_action( 'mainwp_child_theme_action', array( $this, 'mainwp_child_uninstall_theme' ), 10, 1 );
65
 
66
  // Update theme/plugin from MainWP dashboard.
67
- add_action( 'upgrader_process_complete', array( $this, 'mainwp_child_update_assets' ), 10, 2 );
68
-
69
  }
70
  }
71
 
72
  /**
73
  * Triggered when a user accesses the admin area.
74
  */
75
- public function EventAdminInit() {
76
  $this->old_themes = wp_get_themes();
77
  $this->old_plugins = get_plugins();
78
  }
@@ -107,9 +107,9 @@ class WSAL_Sensors_MainWP extends WSAL_AbstractSensor {
107
  /**
108
  * Get removed themes.
109
  *
110
- * @return array of WP_Theme objects
111
  */
112
- protected function GetRemovedThemes() {
113
  $result = $this->old_themes;
114
  foreach ( $result as $i => $theme ) {
115
  if ( file_exists( $theme->get_template_directory() ) ) {
@@ -125,6 +125,8 @@ class WSAL_Sensors_MainWP extends WSAL_AbstractSensor {
125
  *
126
  * @param array $args - Array of arguments related to asset installed.
127
  * @since 3.2.2
 
 
128
  */
129
  public function mainwp_child_install_assets( $args ) {
130
  if ( empty( $args ) || ! is_array( $args ) ) {
@@ -143,7 +145,7 @@ class WSAL_Sensors_MainWP extends WSAL_AbstractSensor {
143
 
144
  // Check if theme exists.
145
  if ( $theme_obj->exists() ) {
146
- $this->plugin->alerts->Trigger(
147
  5005,
148
  array(
149
  'Theme' => (object) array(
@@ -165,7 +167,7 @@ class WSAL_Sensors_MainWP extends WSAL_AbstractSensor {
165
  $plugin = $plugins[ $plugin_slug ]; // Take out the plugin being installed.
166
 
167
  $plugin_path = plugin_dir_path( WP_PLUGIN_DIR . '/' . $plugin_slug );
168
- $this->plugin->alerts->Trigger(
169
  5000,
170
  array(
171
  'Plugin' => (object) array(
@@ -215,7 +217,7 @@ class WSAL_Sensors_MainWP extends WSAL_AbstractSensor {
215
  $plugin_filename = WSAL_Sensors_PluginsThemes::get_plugin_file_name( $plugin_name );
216
 
217
  if ( ! empty( $plugin_filename ) && in_array( $plugin_filename, $wp_plugins, true ) ) {
218
- $this->plugin->alerts->Trigger(
219
  5003,
220
  array(
221
  'PluginFile' => $plugin_filename,
@@ -234,6 +236,8 @@ class WSAL_Sensors_MainWP extends WSAL_AbstractSensor {
234
  *
235
  * @param array $args - Array of arguments related to asset uninstalled.
236
  * @since 3.2.2
 
 
237
  */
238
  public function mainwp_child_uninstall_theme( $args ) {
239
  if ( empty( $args ) || ! is_array( $args ) ) {
@@ -255,12 +259,12 @@ class WSAL_Sensors_MainWP extends WSAL_AbstractSensor {
255
  && isset( $post_array['mainwpsignature'] ) && ! empty( $post_array['mainwpsignature'] )
256
  ) {
257
  // Get theme object.
258
- $themes = $this->GetRemovedThemes();
259
 
260
  if ( ! empty( $themes ) ) {
261
  foreach ( $themes as $index => $theme ) {
262
  if ( ! empty( $theme ) && $theme instanceof WP_Theme && in_array( $theme->Name, $wp_themes, true ) ) {
263
- $this->plugin->alerts->Trigger(
264
  5007,
265
  array(
266
  'Theme' => (object) array(
@@ -315,7 +319,7 @@ class WSAL_Sensors_MainWP extends WSAL_AbstractSensor {
315
 
316
  $plugin = WP_PLUGIN_DIR . '/' . $plugin;
317
  $plugin_data = get_plugin_data( $plugin, false, true );
318
- $this->plugin->alerts->Trigger(
319
  $event,
320
  array(
321
  'PluginFile' => $plugin,
@@ -337,7 +341,7 @@ class WSAL_Sensors_MainWP extends WSAL_AbstractSensor {
337
  ) {
338
  $plugin = WP_PLUGIN_DIR . '/' . $plugin;
339
  $plugin_data = get_plugin_data( $plugin, false, true );
340
- $this->plugin->alerts->Trigger(
341
  5001,
342
  array(
343
  'PluginFile' => $plugin,
@@ -353,14 +357,14 @@ class WSAL_Sensors_MainWP extends WSAL_AbstractSensor {
353
  }
354
  }
355
 
356
- /**
357
- * Method: Handle plugin/theme update event
358
- * from MainWP dashboard on child site.
359
- *
360
- * @param WP_Upgrader $upgrader
361
- * @param array $args - Array of arguments related to asset updated.
362
- * @since 3.2.2
363
- */
364
  public function mainwp_child_update_assets( $upgrader, $args ) {
365
  if ( empty( $args ) || ! is_array( $args ) ) {
366
  return;
@@ -374,32 +378,32 @@ class WSAL_Sensors_MainWP extends WSAL_AbstractSensor {
374
  isset( $post_array['function'] ) && 'upgradeplugintheme' === $post_array['function']
375
  && isset( $post_array['mainwpsignature'] ) && ! empty( $post_array['mainwpsignature'] )
376
  && isset( $post_array['list'] ) && ! empty( $post_array['list'] )
377
- && isset( $args['action'] ) && 'update' === $args['action']
378
- && isset( $args['type'] ) && ! empty( $args['type'] )
379
  ) {
380
  if ( 'theme' === $args['type'] ) {
381
  // Site themes updated.
382
  $site_themes = array_key_exists( 'themes', $args ) ? $args['themes'] : explode( ',', $post_array['list'] );
383
 
384
  if ( empty( $site_themes ) ) {
385
- // no themes in any of the lists
386
- return;
387
- }
388
 
389
  foreach ( $site_themes as $theme_name ) {
390
- WSAL_Sensors_PluginsThemes::LogThemeUpdatedEvent( $theme_name );
391
- }
392
  } elseif ( 'plugin' === $args['type'] ) {
393
- // Site plugins updated.
394
- if ( ! array_key_exists( 'plugins', $args ) || empty( $args['plugins'] ) ) {
395
- // no plugins in the list
396
- return;
397
- }
398
-
399
- $plugins = $args['plugins'];
400
- foreach ( $plugins as $plugin_file ) {
401
- WSAL_Sensors_PluginsThemes::LogPluginUpdatedEvent( $plugin_file );
402
- }
403
  }
404
  }
405
  }
4
  *
5
  * MainWP Plugins & Themes sensor file.
6
  *
7
+ * @since 4.1.4
8
+ * @package wsal
9
+ * @subpackage sensors
10
  */
11
 
12
  // Exit if accessed directly.
27
  * 5007 User uninstalled a theme
28
  * 5031 User updated a theme
29
  *
30
+ * @package wsal
31
  * @subpackage sensors
32
  */
33
  class WSAL_Sensors_MainWP extends WSAL_AbstractSensor {
40
  protected $old_themes = array();
41
 
42
  /**
43
+ * {@inheritDoc}
44
  */
45
+ public function hook_events() {
46
 
47
+ add_action( 'admin_init', array( $this, 'event_admin_init' ) );
48
 
49
  // Check if MainWP Child Plugin exists.
50
  if ( WpSecurityAuditLog::is_mainwp_active() ) {
65
  add_action( 'mainwp_child_theme_action', array( $this, 'mainwp_child_uninstall_theme' ), 10, 1 );
66
 
67
  // Update theme/plugin from MainWP dashboard.
68
+ add_action( 'upgrader_process_complete', array( $this, 'mainwp_child_update_assets' ), 10, 2 );
 
69
  }
70
  }
71
 
72
  /**
73
  * Triggered when a user accesses the admin area.
74
  */
75
+ public function event_admin_init() {
76
  $this->old_themes = wp_get_themes();
77
  $this->old_plugins = get_plugins();
78
  }
107
  /**
108
  * Get removed themes.
109
  *
110
+ * @return WP_Theme[] List of WP_Theme objects.
111
  */
112
+ protected function get_removed_themes() {
113
  $result = $this->old_themes;
114
  foreach ( $result as $i => $theme ) {
115
  if ( file_exists( $theme->get_template_directory() ) ) {
125
  *
126
  * @param array $args - Array of arguments related to asset installed.
127
  * @since 3.2.2
128
+ *
129
+ * phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
130
  */
131
  public function mainwp_child_install_assets( $args ) {
132
  if ( empty( $args ) || ! is_array( $args ) ) {
145
 
146
  // Check if theme exists.
147
  if ( $theme_obj->exists() ) {
148
+ $this->plugin->alerts->trigger_event(
149
  5005,
150
  array(
151
  'Theme' => (object) array(
167
  $plugin = $plugins[ $plugin_slug ]; // Take out the plugin being installed.
168
 
169
  $plugin_path = plugin_dir_path( WP_PLUGIN_DIR . '/' . $plugin_slug );
170
+ $this->plugin->alerts->trigger_event(
171
  5000,
172
  array(
173
  'Plugin' => (object) array(
217
  $plugin_filename = WSAL_Sensors_PluginsThemes::get_plugin_file_name( $plugin_name );
218
 
219
  if ( ! empty( $plugin_filename ) && in_array( $plugin_filename, $wp_plugins, true ) ) {
220
+ $this->plugin->alerts->trigger_event(
221
  5003,
222
  array(
223
  'PluginFile' => $plugin_filename,
236
  *
237
  * @param array $args - Array of arguments related to asset uninstalled.
238
  * @since 3.2.2
239
+ *
240
+ * phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
241
  */
242
  public function mainwp_child_uninstall_theme( $args ) {
243
  if ( empty( $args ) || ! is_array( $args ) ) {
259
  && isset( $post_array['mainwpsignature'] ) && ! empty( $post_array['mainwpsignature'] )
260
  ) {
261
  // Get theme object.
262
+ $themes = $this->get_removed_themes();
263
 
264
  if ( ! empty( $themes ) ) {
265
  foreach ( $themes as $index => $theme ) {
266
  if ( ! empty( $theme ) && $theme instanceof WP_Theme && in_array( $theme->Name, $wp_themes, true ) ) {
267
+ $this->plugin->alerts->trigger_event(
268
  5007,
269
  array(
270
  'Theme' => (object) array(
319
 
320
  $plugin = WP_PLUGIN_DIR . '/' . $plugin;
321
  $plugin_data = get_plugin_data( $plugin, false, true );
322
+ $this->plugin->alerts->trigger_event(
323
  $event,
324
  array(
325
  'PluginFile' => $plugin,
341
  ) {
342
  $plugin = WP_PLUGIN_DIR . '/' . $plugin;
343
  $plugin_data = get_plugin_data( $plugin, false, true );
344
+ $this->plugin->alerts->trigger_event(
345
  5001,
346
  array(
347
  'PluginFile' => $plugin,
357
  }
358
  }
359
 
360
+ /**
361
+ * Method: Handle plugin/theme update event from MainWP dashboard on child site.
362
+ *
363
+ * @param WP_Upgrader $upgrader WordPress upgrader.
364
+ * @param array $args - Array of arguments related to asset updated.
365
+ *
366
+ * @since 3.2.2
367
+ */
368
  public function mainwp_child_update_assets( $upgrader, $args ) {
369
  if ( empty( $args ) || ! is_array( $args ) ) {
370
  return;
378
  isset( $post_array['function'] ) && 'upgradeplugintheme' === $post_array['function']
379
  && isset( $post_array['mainwpsignature'] ) && ! empty( $post_array['mainwpsignature'] )
380
  && isset( $post_array['list'] ) && ! empty( $post_array['list'] )
381
+ && isset( $args['action'] ) && 'update' === $args['action']
382
+ && isset( $args['type'] ) && ! empty( $args['type'] )
383
  ) {
384
  if ( 'theme' === $args['type'] ) {
385
  // Site themes updated.
386
  $site_themes = array_key_exists( 'themes', $args ) ? $args['themes'] : explode( ',', $post_array['list'] );
387
 
388
  if ( empty( $site_themes ) ) {
389
+ // No themes in any of the lists.
390
+ return;
391
+ }
392
 
393
  foreach ( $site_themes as $theme_name ) {
394
+ WSAL_Sensors_PluginsThemes::log_theme_updated_event( $theme_name );
395
+ }
396
  } elseif ( 'plugin' === $args['type'] ) {
397
+ // Site plugins updated.
398
+ if ( ! array_key_exists( 'plugins', $args ) || empty( $args['plugins'] ) ) {
399
+ // No plugins in the list.
400
+ return;
401
+ }
402
+
403
+ $plugins = $args['plugins'];
404
+ foreach ( $plugins as $plugin_file ) {
405
+ WSAL_Sensors_PluginsThemes::log_plugin_updated_event( $plugin_file );
406
+ }
407
  }
408
  }
409
  }
classes/Sensors/Menus.php CHANGED
@@ -4,8 +4,9 @@
4
  *
5
  * Menus sensor file.
6
  *
7
- * @since 1.0.0
8
- * @package wsal
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -26,7 +27,7 @@ if ( ! defined( 'ABSPATH' ) ) {
26
  * 2085 User changed order of the objects in a menu
27
  * 2089 User moved objects as a sub-item
28
  *
29
- * @package wsal
30
  * @subpackage sensors
31
  */
32
  class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
@@ -36,28 +37,28 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
36
  *
37
  * @var object
38
  */
39
- protected $_old_menu = null;
40
 
41
  /**
42
  * Old Menu objects.
43
  *
44
  * @var array
45
  */
46
- protected $_old_menu_terms = array();
47
 
48
  /**
49
  * Old Menu Items.
50
  *
51
  * @var array
52
  */
53
- protected $_old_menu_items = array();
54
 
55
  /**
56
  * Old Menu Locations.
57
  *
58
  * @var array
59
  */
60
- protected $_old_menu_locations = null;
61
 
62
  /**
63
  * An array of menu IDs for which an order change has already been reported during current request.
@@ -65,18 +66,18 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
65
  * @var array
66
  * @since 4.2.0.1
67
  */
68
- protected $order_changed_menu_ids = [];
69
 
70
  /**
71
- * Listening to events using WP hooks.
72
  */
73
- public function HookEvents() {
74
- add_action( 'wp_create_nav_menu', array( $this, 'CreateMenu' ), 10, 2 );
75
- add_action( 'wp_delete_nav_menu', array( $this, 'DeleteMenu' ), 10, 1 );
76
- add_action( 'wp_update_nav_menu', array( $this, 'UpdateMenu' ), 10, 2 );
77
 
78
- add_action( 'wp_update_nav_menu_item', array( $this, 'UpdateMenuItem' ), 10, 3 );
79
- add_action( 'admin_menu', array( $this, 'ManageMenuLocations' ) );
80
  add_action( 'admin_init', array( $this, 'EventAdminInit' ) );
81
 
82
  // Customizer trigger.
@@ -87,13 +88,13 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
87
  /**
88
  * Menu item updated.
89
  *
90
- * @param int $menu_id - Menu ID.
91
- * @param int $menu_item_db_id - Menu item DB ID.
92
- * @param array $args - An array of items used to update menu.
93
  *
94
  * @return boolean
95
  */
96
- public function UpdateMenuItem( $menu_id, $menu_item_db_id, $args ) {
97
  // Filter $_POST global array for security.
98
  $post_array = filter_input_array( INPUT_POST );
99
 
@@ -102,24 +103,24 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
102
  $is_changed_order = false;
103
  $is_sub_item = false;
104
  $new_menu_items = array_keys( $post_array['menu-item-title'] );
105
- if ( ! empty( $this->_old_menu_items ) ) {
106
- foreach ( $this->_old_menu_items as $old_item ) {
107
- if ( $old_item['menu_id'] == $menu_id ) {
108
  $item_id = $old_item['item_id'];
109
- if ( $item_id == $menu_item_db_id ) {
110
- if ( $old_item['menu_order'] != $args['menu-item-position'] ) {
111
  $is_changed_order = true;
112
  }
113
  if ( ! empty( $args['menu-item-parent-id'] ) ) {
114
  $is_sub_item = true;
115
  }
116
- if ( ! empty( $args['menu-item-title'] ) && $old_item['title'] != $args['menu-item-title'] ) {
117
  // Verify nonce.
118
  if ( ! wp_verify_nonce( $post_array['update-nav-menu-nonce'], 'update-nav_menu' ) ) {
119
  return false;
120
  }
121
 
122
- $this->EventModifiedItems( $post_array['menu-item-object'][ $menu_item_db_id ], $post_array['menu-item-title'][ $menu_item_db_id ], $post_array['menu-name'], $menu_id );
123
  }
124
  }
125
  $old_menu_items[ $item_id ] = array(
@@ -134,40 +135,40 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
134
  // Add Items to the menu.
135
  $added_items = array_diff( $new_menu_items, array_keys( $old_menu_items ) );
136
  if ( count( $added_items ) > 0 && wp_verify_nonce( $post_array['update-nav-menu-nonce'], 'update-nav_menu' ) ) {
137
- if ( in_array( $menu_item_db_id, $added_items ) ) {
138
- $this->EventAddItems( $post_array['menu-item-object'][ $menu_item_db_id ], $post_array['menu-item-title'][ $menu_item_db_id ], $post_array['menu-name'], $menu_id );
139
  }
140
  }
141
 
142
  // Remove items from the menu.
143
  $removed_items = array_diff( array_keys( $old_menu_items ), $new_menu_items );
144
  if ( count( $removed_items ) > 0 && wp_verify_nonce( $post_array['update-nav-menu-nonce'], 'update-nav_menu' ) ) {
145
- if ( array_search( $menu_item_db_id, $new_menu_items ) == ( count( $new_menu_items ) - 1 ) ) {
146
  foreach ( $removed_items as $removed_item_id ) {
147
- $this->EventRemoveItems( $old_menu_items[ $removed_item_id ]['type'], $old_menu_items[ $removed_item_id ]['title'], $post_array['menu-name'], $menu_id );
148
  }
149
  }
150
  }
151
 
152
- // we want to ignore order changes when menu items are added, removed or another order change has already
153
- // been logged during this request
154
  $ignore_order_change = ! empty( $removed_items ) || ! empty( $added_items );
155
 
156
- // check if an order has changed
157
  if ( ! $ignore_order_change && $is_changed_order && wp_verify_nonce( $post_array['meta-box-order-nonce'], 'meta-box-order' ) ) {
158
  $old_item = $old_menu_items[ $menu_item_db_id ];
159
  $menu_object = wp_get_nav_menu_object( $menu_id );
160
  if ( $menu_object instanceof WP_Term ) {
161
- $this->EventChangeOrder( $old_item['title'], $menu_object->name, $menu_id );
162
  }
163
  }
164
 
165
  if ( $is_sub_item && wp_verify_nonce( $post_array['update-nav-menu-nonce'], 'update-nav_menu' ) ) {
166
  $item_parent_id = $args['menu-item-parent-id'];
167
  $item_name = $old_menu_items[ $menu_item_db_id ]['title'];
168
- if ( $old_menu_items[ $menu_item_db_id ]['parent'] != $item_parent_id ) {
169
  $parent_name = isset( $old_menu_items[ $item_parent_id ]['title'] ) ? $old_menu_items[ $item_parent_id ]['title'] : false;
170
- $this->EventChangeSubItem( $item_name, $parent_name, $post_array['menu-name'], $menu_id );
171
  }
172
  }
173
  }
@@ -179,8 +180,8 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
179
  * @param int $term_id - Term ID.
180
  * @param array $menu_data - Menu data.
181
  */
182
- public function CreateMenu( $term_id, $menu_data ) {
183
- $this->plugin->alerts->Trigger(
184
  2078,
185
  array(
186
  'MenuName' => $menu_data['menu-name'],
@@ -194,7 +195,7 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
194
  *
195
  * @global array $_POST Data post.
196
  */
197
- public function ManageMenuLocations() {
198
  // Filter $_POST global array for security.
199
  $post_array = filter_input_array( INPUT_POST );
200
 
@@ -207,10 +208,10 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
207
  if ( isset( $post_array['menu-locations'] ) ) {
208
  $new_locations = $post_array['menu-locations'];
209
  if ( isset( $new_locations['top'] ) ) {
210
- $this->LocationSetting( $new_locations['top'], 'top' );
211
  }
212
  if ( isset( $new_locations['social'] ) ) {
213
- $this->LocationSetting( $new_locations['social'], 'social' );
214
  }
215
  }
216
  }
@@ -221,17 +222,17 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
221
  * @param integer $new_location - New location.
222
  * @param string $type - Location type.
223
  */
224
- private function LocationSetting( $new_location, $type ) {
225
  $old_locations = get_nav_menu_locations();
226
- if ( 0 != $new_location ) {
227
  $menu = wp_get_nav_menu_object( $new_location );
228
- if ( isset( $old_locations[ $type ] ) && $old_locations[ $type ] != $new_location ) {
229
- $this->EventMenuSetting( $menu->name, 'Enabled', 'Location: ' . $type . ' menu' );
230
  }
231
  } else {
232
  if ( ! empty( $old_locations[ $type ] ) ) {
233
  $menu = wp_get_nav_menu_object( $old_locations[ $type ] );
234
- $this->EventMenuSetting( $menu->name, 'Disabled', 'Location: ' . $type . ' menu' );
235
  }
236
  }
237
  }
@@ -241,12 +242,12 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
241
  *
242
  * @param int $term_id - Term ID.
243
  */
244
- public function DeleteMenu( $term_id ) {
245
- if ( $this->_old_menu ) {
246
- $this->plugin->alerts->Trigger(
247
  2081,
248
  array(
249
- 'MenuName' => $this->_old_menu->name,
250
  'MenuID' => $term_id,
251
  )
252
  );
@@ -258,8 +259,11 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
258
  *
259
  * @param int $menu_id - Menu ID.
260
  * @param array $menu_data (Optional) Menu data.
 
 
 
261
  */
262
- public function UpdateMenu( $menu_id, $menu_data = null ) {
263
  if ( ! empty( $menu_data ) ) {
264
  $content_names_old = array();
265
  $content_types_old = array();
@@ -278,15 +282,15 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
278
  $post_array = filter_input_array( INPUT_POST );
279
 
280
  // Menu changed name.
281
- if ( ! empty( $this->_old_menu_terms ) && isset( $post_array['menu'] ) && isset( $post_array['menu-name'] ) ) {
282
- foreach ( $this->_old_menu_terms as $old_menu_term ) {
283
  if ( $old_menu_term['term_id'] == $post_array['menu'] && wp_verify_nonce( $post_array['update-nav-menu-nonce'], 'update-nav_menu' ) ) {
284
- if ( $old_menu_term['name'] != $post_array['menu-name'] ) {
285
- $this->EventChangeName( $old_menu_term['name'], $post_array['menu-name'], $menu_id );
286
  } else {
287
- //Remove the last menu item.
288
  if ( count( $content_names_old ) == 1 && count( $content_types_old ) == 1 ) {
289
- $this->EventRemoveItems( $content_types_old[0], $content_names_old[0], $post_array['menu-name'], $menu_id );
290
  }
291
  }
292
  }
@@ -314,49 +318,49 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
314
 
315
  // Alert 2082 Auto add pages.
316
  if ( ! empty( $auto_add ) ) {
317
- $this->EventMenuSetting( $menu_data['menu-name'], $auto_add, 'Auto add pages', $menu_id );
318
  }
319
 
320
  $nav_menu_locations = get_nav_menu_locations();
321
 
322
  $location_top = null;
323
- if ( isset( $this->_old_menu_locations['top'] ) && isset( $nav_menu_locations['top'] ) ) {
324
- if ( $nav_menu_locations['top'] == $menu_id && $this->_old_menu_locations['top'] != $nav_menu_locations['top'] ) {
325
  $location_top = 'Enabled';
326
  }
327
- } elseif ( empty( $this->_old_menu_locations['top'] ) && isset( $nav_menu_locations['top'] ) ) {
328
  if ( $nav_menu_locations['top'] == $menu_id ) {
329
  $location_top = 'Enabled';
330
  }
331
- } elseif ( isset( $this->_old_menu_locations['top'] ) && empty( $nav_menu_locations['top'] ) ) {
332
- if ( $this->_old_menu_locations['top'] == $menu_id ) {
333
  $location_top = 'Disabled';
334
  }
335
  }
336
 
337
  // Alert 2082 top menu.
338
  if ( ! empty( $location_top ) ) {
339
- $this->EventMenuSetting( $menu_data['menu-name'], $location_top, 'Location: top menu', $menu_id );
340
  }
341
 
342
  $location_social = null;
343
- if ( isset( $this->_old_menu_locations['social'] ) && isset( $nav_menu_locations['social'] ) ) {
344
- if ( $nav_menu_locations['social'] == $menu_id && $this->_old_menu_locations['social'] != $nav_menu_locations['social'] ) {
345
  $location_social = 'Enabled';
346
  }
347
- } elseif ( empty( $this->_old_menu_locations['social'] ) && isset( $nav_menu_locations['social'] ) ) {
348
  if ( $nav_menu_locations['social'] == $menu_id ) {
349
  $location_social = 'Enabled';
350
  }
351
- } elseif ( isset( $this->_old_menu_locations['social'] ) && empty( $nav_menu_locations['social'] ) ) {
352
- if ( $this->_old_menu_locations['social'] == $menu_id ) {
353
  $location_social = 'Disabled';
354
  }
355
  }
356
 
357
  // Alert 2082 Social links menu.
358
  if ( ! empty( $location_social ) ) {
359
- $this->EventMenuSetting( $menu_data['menu-name'], $location_social, 'Location: social menu', $menu_id );
360
  }
361
  }
362
  }
@@ -369,7 +373,7 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
369
  if ( ! empty( $menus ) ) {
370
  foreach ( $menus as $menu ) {
371
  array_push(
372
- $this->_old_menu_terms,
373
  array(
374
  'term_id' => $menu->term_id,
375
  'name' => $menu->name,
@@ -379,7 +383,7 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
379
  if ( ! empty( $items ) ) {
380
  foreach ( $items as $item ) {
381
  array_push(
382
- $this->_old_menu_items,
383
  array(
384
  'menu_id' => $menu->term_id,
385
  'item_id' => $item->ID,
@@ -415,12 +419,12 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
415
  if ( $is_nav_menu ) {
416
  if ( isset( $get_array['action'] ) && 'delete' == $get_array['action'] ) {
417
  if ( isset( $get_array['menu'] ) ) {
418
- $this->_old_menu = wp_get_nav_menu_object( $get_array['menu'] );
419
  }
420
  } else {
421
  $this->BuildOldMenuTermsAndItems();
422
  }
423
- $this->_old_menu_locations = get_nav_menu_locations();
424
  }
425
  }
426
 
@@ -429,7 +433,7 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
429
  */
430
  public function CustomizeInit() {
431
  $this->BuildOldMenuTermsAndItems();
432
- $this->_old_menu_locations = get_nav_menu_locations();
433
  }
434
 
435
  /**
@@ -451,13 +455,13 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
451
  }
452
 
453
  // Deleted Menu.
454
- if ( isset( $update_menus ) && isset( $this->_old_menu_terms ) ) {
455
- $terms = array_diff( array_map( 'serialize', $this->_old_menu_terms ), array_map( 'serialize', $update_menus ) );
456
  $terms = array_map( 'unserialize', $terms );
457
 
458
  if ( isset( $terms ) && count( $terms ) > 0 ) {
459
  foreach ( $terms as $term ) {
460
- $this->plugin->alerts->Trigger(
461
  2081,
462
  array(
463
  'MenuName' => $term['name'],
@@ -479,25 +483,25 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
479
  $is_occurred_event = false;
480
  $menu = wp_get_nav_menu_object( $value['nav_menu_term_id'] );
481
  $content_name = ! empty( $value['title'] ) ? $value['title'] : 'no title';
482
- if ( ! empty( $this->_old_menu_items ) ) {
483
- foreach ( $this->_old_menu_items as $old_item ) {
484
  $item_id = substr( trim( $key, ']' ), 14 );
485
  if ( $old_item['item_id'] == $item_id ) {
486
  // Modified Items in the menu.
487
  if ( $old_item['title'] != $content_name ) {
488
  $is_occurred_event = true;
489
- $this->EventModifiedItems( $value['type_label'], $content_name, $menu->name, $menu->term_id );
490
  }
491
  // Moved as a sub-item.
492
  if ( $old_item['menu_item_parent'] != $value['menu_item_parent'] && 0 != $value['menu_item_parent'] ) {
493
  $is_occurred_event = true;
494
- $parent_name = $this->GetItemName( $value['nav_menu_term_id'], $value['menu_item_parent'] );
495
- $this->EventChangeSubItem( $content_name, $parent_name, $menu->name, $menu->term_id );
496
  }
497
  // Changed order of the objects in a menu.
498
  if ( $old_item['menu_order'] != $value['position'] ) {
499
  $is_occurred_event = true;
500
- $this->EventChangeOrder( $content_name, $menu->name, $menu->term_id );
501
  }
502
  }
503
  }
@@ -505,15 +509,15 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
505
  // Add Items to the menu.
506
  if ( ! $is_occurred_event ) {
507
  $menu_name = ! empty( $customized['new_menu_name'] ) ? $customized['new_menu_name'] : $menu->name;
508
- $this->EventAddItems( $value['type_label'], $content_name, $menu_name, $menu->term_id );
509
  }
510
  } else {
511
  // Menu changed name.
512
- if ( isset( $update_menus ) && isset( $this->_old_menu_terms ) ) {
513
- foreach ( $this->_old_menu_terms as $old_menu ) {
514
  foreach ( $update_menus as $update_menu ) {
515
  if ( $old_menu['term_id'] == $update_menu['term_id'] && $old_menu['name'] != $update_menu['name'] ) {
516
- $this->EventChangeName( $old_menu['name'], $update_menu['name'], $menu->term_id );
517
  }
518
  }
519
  }
@@ -521,9 +525,9 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
521
  // Setting Auto add pages.
522
  if ( ! empty( $value ) && isset( $value['auto_add'] ) ) {
523
  if ( $value['auto_add'] ) {
524
- $this->EventMenuSetting( $value['name'], 'Enabled', 'Auto add pages', $menu->term_id );
525
  } else {
526
- $this->EventMenuSetting( $value['name'], 'Disabled', 'Auto add pages', $menu->term_id );
527
  }
528
  }
529
  // Setting Location.
@@ -532,22 +536,22 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
532
  if ( ! empty( $value ) ) {
533
  $menu = wp_get_nav_menu_object( $value );
534
  $menu_name = ! empty( $customized['new_menu_name'] ) ? $customized['new_menu_name'] : ( ! empty( $menu ) ? $menu->name : '' );
535
- $this->EventMenuSetting( $menu_name, 'Enabled', 'Location: ' . $loc . ' menu', $menu->term_id );
536
  } else {
537
- if ( ! empty( $this->_old_menu_locations[ $loc ] ) ) {
538
- $menu = wp_get_nav_menu_object( $this->_old_menu_locations[ $loc ] );
539
  $menu_name = ! empty( $customized['new_menu_name'] ) ? $customized['new_menu_name'] : ( ! empty( $menu ) ? $menu->name : '' );
540
- $this->EventMenuSetting( $menu_name, 'Disabled', 'Location: ' . $loc . ' menu', $menu->term_id );
541
  }
542
  }
543
  }
544
  // Remove items from the menu.
545
  if ( false !== strpos( $key, 'nav_menu_item[' ) ) {
546
  $item_id = substr( trim( $key, ']' ), 14 );
547
- if ( ! empty( $this->_old_menu_items ) ) {
548
- foreach ( $this->_old_menu_items as $old_item ) {
549
  if ( $old_item['item_id'] == $item_id ) {
550
- $this->EventRemoveItems( $old_item['object'], $old_item['title'], $old_item['menu_name'], $menu->term_id );
551
  }
552
  }
553
  }
@@ -564,10 +568,11 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
564
  *
565
  * @param string $content_type - Type of content.
566
  * @param string $content_name - Name of content.
567
- * @param string $menu_name - Menu name.
 
568
  */
569
- private function EventAddItems( $content_type, $content_name, $menu_name, $menu_id ) {
570
- $this->plugin->alerts->Trigger(
571
  2079,
572
  array(
573
  'ContentType' => 'custom' === $content_type ? 'custom link' : $content_type,
@@ -583,10 +588,11 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
583
  *
584
  * @param string $content_type - Type of content.
585
  * @param string $content_name - Name of content.
586
- * @param string $menu_name - Menu name.
 
587
  */
588
- private function EventRemoveItems( $content_type, $content_name, $menu_name, $menu_id ) {
589
- $this->plugin->alerts->Trigger(
590
  2080,
591
  array(
592
  'ContentType' => 'custom' === $content_type ? 'custom link' : $content_type,
@@ -600,13 +606,14 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
600
  /**
601
  * Changed menu setting.
602
  *
603
- * @param string $menu_name - Menu Name.
604
- * @param string $status - Status of menu.
605
  * @param string $menu_setting - Menu setting.
 
606
  */
607
- private function EventMenuSetting( $menu_name, $status, $menu_setting, $menu_id ) {
608
  $status = 'Enabled' === $status ? 'enabled' : 'disabled';
609
- $this->plugin->alerts->Trigger(
610
  2082,
611
  array(
612
  'EventType' => $status,
@@ -622,10 +629,11 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
622
  *
623
  * @param string $content_type - Type of content.
624
  * @param string $content_name - Name of content.
625
- * @param string $menu_name - Menu name.
 
626
  */
627
- private function EventModifiedItems( $content_type, $content_name, $menu_name, $menu_id ) {
628
- $this->plugin->alerts->Trigger(
629
  2083,
630
  array(
631
  'ContentType' => 'custom' === $content_type ? 'custom link' : $content_type,
@@ -641,9 +649,10 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
641
  *
642
  * @param string $old_menu_name - Old Menu Name.
643
  * @param string $new_menu_name - New Menu Name.
 
644
  */
645
- private function EventChangeName( $old_menu_name, $new_menu_name, $menu_id ) {
646
- $this->plugin->alerts->Trigger(
647
  2084,
648
  array(
649
  'OldMenuName' => $old_menu_name,
@@ -658,15 +667,15 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
658
  *
659
  * @param string $item_name - Item name.
660
  * @param string $menu_name - Menu name.
661
- * @param int $menu_id - Menu ID.
662
  */
663
- private function EventChangeOrder( $item_name, $menu_name, $menu_id ) {
664
- // skip if an order change for this menu has already been reported during the current request
665
- if ( in_array( $menu_id, $this->order_changed_menu_ids ) ) {
666
  return;
667
  }
668
 
669
- $this->plugin->alerts->Trigger(
670
  2085,
671
  array(
672
  'ItemName' => $item_name,
@@ -675,20 +684,20 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
675
  )
676
  );
677
 
678
- // keep track of already reported order changes to prevent repetitive events
679
  array_push( $this->order_changed_menu_ids, $menu_id );
680
  }
681
 
682
  /**
683
  * Moved objects as a sub-item.
684
  *
685
- * @param string $item_name - Item name.
686
  * @param string $parent_name - Parent Name.
687
- * @param string $menu_name - Menu Name.
688
- * @param int $menu_id - Menu ID.
689
  */
690
- private function EventChangeSubItem( $item_name, $parent_name, $menu_name, $menu_id ) {
691
- $this->plugin->alerts->Trigger(
692
  2089,
693
  array(
694
  'ItemName' => $item_name,
@@ -707,7 +716,7 @@ class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
707
  *
708
  * @return string
709
  */
710
- private function GetItemName( $term_id, $item_id ) {
711
  $item_name = '';
712
  $menu_items = wp_get_nav_menu_items( $term_id );
713
  foreach ( $menu_items as $menu_item ) {
4
  *
5
  * Menus sensor file.
6
  *
7
+ * @since 1.0.0
8
+ * @package wsal
9
+ * @subpackage sensors
10
  */
11
 
12
  // Exit if accessed directly.
27
  * 2085 User changed order of the objects in a menu
28
  * 2089 User moved objects as a sub-item
29
  *
30
+ * @package wsal
31
  * @subpackage sensors
32
  */
33
  class WSAL_Sensors_Menus extends WSAL_AbstractSensor {
37
  *
38
  * @var object
39
  */
40
+ protected $old_menu = null;
41
 
42
  /**
43
  * Old Menu objects.
44
  *
45
  * @var array
46
  */
47
+ protected $old_menu_terms = array();
48
 
49
  /**
50
  * Old Menu Items.
51
  *
52
  * @var array
53
  */
54
+ protected $old_menu_items = array();
55
 
56
  /**
57
  * Old Menu Locations.
58
  *
59
  * @var array
60
  */
61
+ protected $old_menu_locations = null;
62
 
63
  /**
64
  * An array of menu IDs for which an order change has already been reported during current request.
66
  * @var array
67
  * @since 4.2.0.1
68
  */
69
+ protected $order_changed_menu_ids = array();
70
 
71
  /**
72
+ * {@inheritDoc}
73
  */
74
+ public function hook_events() {
75
+ add_action( 'wp_create_nav_menu', array( $this, 'create_menu' ), 10, 2 );
76
+ add_action( 'wp_delete_nav_menu', array( $this, 'delete_menu' ), 10, 1 );
77
+ add_action( 'wp_update_nav_menu', array( $this, 'update_menu' ), 10, 2 );
78
 
79
+ add_action( 'wp_update_nav_menu_item', array( $this, 'update_menu_item' ), 10, 3 );
80
+ add_action( 'admin_menu', array( $this, 'manage_menu_locations' ) );
81
  add_action( 'admin_init', array( $this, 'EventAdminInit' ) );
82
 
83
  // Customizer trigger.
88
  /**
89
  * Menu item updated.
90
  *
91
+ * @param int $menu_id - Menu ID.
92
+ * @param int $menu_item_db_id - Menu item DB ID.
93
+ * @param array $args - An array of items used to update menu.
94
  *
95
  * @return boolean
96
  */
97
+ public function update_menu_item( $menu_id, $menu_item_db_id, $args ) {
98
  // Filter $_POST global array for security.
99
  $post_array = filter_input_array( INPUT_POST );
100
 
103
  $is_changed_order = false;
104
  $is_sub_item = false;
105
  $new_menu_items = array_keys( $post_array['menu-item-title'] );
106
+ if ( ! empty( $this->old_menu_items ) ) {
107
+ foreach ( $this->old_menu_items as $old_item ) {
108
+ if ( $old_item['menu_id'] === $menu_id ) {
109
  $item_id = $old_item['item_id'];
110
+ if ( $item_id === $menu_item_db_id ) {
111
+ if ( $old_item['menu_order'] !== $args['menu-item-position'] ) {
112
  $is_changed_order = true;
113
  }
114
  if ( ! empty( $args['menu-item-parent-id'] ) ) {
115
  $is_sub_item = true;
116
  }
117
+ if ( ! empty( $args['menu-item-title'] ) && $old_item['title'] !== $args['menu-item-title'] ) {
118
  // Verify nonce.
119
  if ( ! wp_verify_nonce( $post_array['update-nav-menu-nonce'], 'update-nav_menu' ) ) {
120
  return false;
121
  }
122
 
123
+ $this->event_modified_items( $post_array['menu-item-object'][ $menu_item_db_id ], $post_array['menu-item-title'][ $menu_item_db_id ], $post_array['menu-name'], $menu_id );
124
  }
125
  }
126
  $old_menu_items[ $item_id ] = array(
135
  // Add Items to the menu.
136
  $added_items = array_diff( $new_menu_items, array_keys( $old_menu_items ) );
137
  if ( count( $added_items ) > 0 && wp_verify_nonce( $post_array['update-nav-menu-nonce'], 'update-nav_menu' ) ) {
138
+ if ( in_array( $menu_item_db_id, $added_items, true ) ) {
139
+ $this->event_add_items( $post_array['menu-item-object'][ $menu_item_db_id ], $post_array['menu-item-title'][ $menu_item_db_id ], $post_array['menu-name'], $menu_id );
140
  }
141
  }
142
 
143
  // Remove items from the menu.
144
  $removed_items = array_diff( array_keys( $old_menu_items ), $new_menu_items );
145
  if ( count( $removed_items ) > 0 && wp_verify_nonce( $post_array['update-nav-menu-nonce'], 'update-nav_menu' ) ) {
146
+ if ( array_search( $menu_item_db_id, $new_menu_items ) == ( count( $new_menu_items ) - 1 ) ) { // phpcs:ignore
147
  foreach ( $removed_items as $removed_item_id ) {
148
+ $this->event_remove_items( $old_menu_items[ $removed_item_id ]['type'], $old_menu_items[ $removed_item_id ]['title'], $post_array['menu-name'], $menu_id );
149
  }
150
  }
151
  }
152
 
153
+ // We want to ignore order changes when menu items are added, removed or another order change has already
154
+ // been logged during this request.
155
  $ignore_order_change = ! empty( $removed_items ) || ! empty( $added_items );
156
 
157
+ // Check if an order has changed.
158
  if ( ! $ignore_order_change && $is_changed_order && wp_verify_nonce( $post_array['meta-box-order-nonce'], 'meta-box-order' ) ) {
159
  $old_item = $old_menu_items[ $menu_item_db_id ];
160
  $menu_object = wp_get_nav_menu_object( $menu_id );
161
  if ( $menu_object instanceof WP_Term ) {
162
+ $this->event_change_order( $old_item['title'], $menu_object->name, $menu_id );
163
  }
164
  }
165
 
166
  if ( $is_sub_item && wp_verify_nonce( $post_array['update-nav-menu-nonce'], 'update-nav_menu' ) ) {
167
  $item_parent_id = $args['menu-item-parent-id'];
168
  $item_name = $old_menu_items[ $menu_item_db_id ]['title'];
169
+ if ( $old_menu_items[ $menu_item_db_id ]['parent'] !== $item_parent_id ) {
170
  $parent_name = isset( $old_menu_items[ $item_parent_id ]['title'] ) ? $old_menu_items[ $item_parent_id ]['title'] : false;
171
+ $this->event_change_sub_item( $item_name, $parent_name, $post_array['menu-name'], $menu_id );
172
  }
173
  }
174
  }
180
  * @param int $term_id - Term ID.
181
  * @param array $menu_data - Menu data.
182
  */
183
+ public function create_menu( $term_id, $menu_data ) {
184
+ $this->plugin->alerts->trigger_event(
185
  2078,
186
  array(
187
  'MenuName' => $menu_data['menu-name'],
195
  *
196
  * @global array $_POST Data post.
197
  */
198
+ public function manage_menu_locations() {
199
  // Filter $_POST global array for security.
200
  $post_array = filter_input_array( INPUT_POST );
201
 
208
  if ( isset( $post_array['menu-locations'] ) ) {
209
  $new_locations = $post_array['menu-locations'];
210
  if ( isset( $new_locations['top'] ) ) {
211
+ $this->location_setting( $new_locations['top'], 'top' );
212
  }
213
  if ( isset( $new_locations['social'] ) ) {
214
+ $this->location_setting( $new_locations['social'], 'social' );
215
  }
216
  }
217
  }
222
  * @param integer $new_location - New location.
223
  * @param string $type - Location type.
224
  */
225
+ private function location_setting( $new_location, $type ) {
226
  $old_locations = get_nav_menu_locations();
227
+ if ( 0 != $new_location ) { // phpcs:ignore
228
  $menu = wp_get_nav_menu_object( $new_location );
229
+ if ( isset( $old_locations[ $type ] ) && $old_locations[ $type ] != $new_location ) { // phpcs:ignore
230
+ $this->event_menu_setting( $menu->name, 'Enabled', 'Location: ' . $type . ' menu' );
231
  }
232
  } else {
233
  if ( ! empty( $old_locations[ $type ] ) ) {
234
  $menu = wp_get_nav_menu_object( $old_locations[ $type ] );
235
+ $this->event_menu_setting( $menu->name, 'Disabled', 'Location: ' . $type . ' menu' );
236
  }
237
  }
238
  }
242
  *
243
  * @param int $term_id - Term ID.
244
  */
245
+ public function delete_menu( $term_id ) {
246
+ if ( $this->old_menu ) {
247
+ $this->plugin->alerts->trigger_event(
248
  2081,
249
  array(
250
+ 'MenuName' => $this->old_menu->name,
251
  'MenuID' => $term_id,
252
  )
253
  );
259
  *
260
  * @param int $menu_id - Menu ID.
261
  * @param array $menu_data (Optional) Menu data.
262
+ *
263
+ * phpcs:disable WordPress.PHP.StrictComparisons.LooseComparison
264
+ * phpcs:disable WordPress.PHP.StrictInArray.MissingTrueStrict
265
  */
266
+ public function update_menu( $menu_id, $menu_data = null ) {
267
  if ( ! empty( $menu_data ) ) {
268
  $content_names_old = array();
269
  $content_types_old = array();
282
  $post_array = filter_input_array( INPUT_POST );
283
 
284
  // Menu changed name.
285
+ if ( ! empty( $this->old_menu_terms ) && isset( $post_array['menu'] ) && isset( $post_array['menu-name'] ) ) {
286
+ foreach ( $this->old_menu_terms as $old_menu_term ) {
287
  if ( $old_menu_term['term_id'] == $post_array['menu'] && wp_verify_nonce( $post_array['update-nav-menu-nonce'], 'update-nav_menu' ) ) {
288
+ if ( $old_menu_term['name'] !== $post_array['menu-name'] ) {
289
+ $this->event_change_name( $old_menu_term['name'], $post_array['menu-name'], $menu_id );
290
  } else {
291
+ // Remove the last menu item.
292
  if ( count( $content_names_old ) == 1 && count( $content_types_old ) == 1 ) {
293
+ $this->event_remove_items( $content_types_old[0], $content_names_old[0], $post_array['menu-name'], $menu_id );
294
  }
295
  }
296
  }
318
 
319
  // Alert 2082 Auto add pages.
320
  if ( ! empty( $auto_add ) ) {
321
+ $this->event_menu_setting( $menu_data['menu-name'], $auto_add, 'Auto add pages', $menu_id );
322
  }
323
 
324
  $nav_menu_locations = get_nav_menu_locations();
325
 
326
  $location_top = null;
327
+ if ( isset( $this->old_menu_locations['top'] ) && isset( $nav_menu_locations['top'] ) ) {
328
+ if ( $nav_menu_locations['top'] == $menu_id && $this->old_menu_locations['top'] != $nav_menu_locations['top'] ) {
329
  $location_top = 'Enabled';
330
  }
331
+ } elseif ( empty( $this->old_menu_locations['top'] ) && isset( $nav_menu_locations['top'] ) ) {
332
  if ( $nav_menu_locations['top'] == $menu_id ) {
333
  $location_top = 'Enabled';
334
  }
335
+ } elseif ( isset( $this->old_menu_locations['top'] ) && empty( $nav_menu_locations['top'] ) ) {
336
+ if ( $this->old_menu_locations['top'] == $menu_id ) {
337
  $location_top = 'Disabled';
338
  }
339
  }
340
 
341
  // Alert 2082 top menu.
342
  if ( ! empty( $location_top ) ) {
343
+ $this->event_menu_setting( $menu_data['menu-name'], $location_top, 'Location: top menu', $menu_id );
344
  }
345
 
346
  $location_social = null;
347
+ if ( isset( $this->old_menu_locations['social'] ) && isset( $nav_menu_locations['social'] ) ) {
348
+ if ( $nav_menu_locations['social'] == $menu_id && $this->old_menu_locations['social'] != $nav_menu_locations['social'] ) {
349
  $location_social = 'Enabled';
350
  }
351
+ } elseif ( empty( $this->old_menu_locations['social'] ) && isset( $nav_menu_locations['social'] ) ) {
352
  if ( $nav_menu_locations['social'] == $menu_id ) {
353
  $location_social = 'Enabled';
354
  }
355
+ } elseif ( isset( $this->old_menu_locations['social'] ) && empty( $nav_menu_locations['social'] ) ) {
356
+ if ( $this->old_menu_locations['social'] == $menu_id ) {
357
  $location_social = 'Disabled';
358
  }
359
  }
360
 
361
  // Alert 2082 Social links menu.
362
  if ( ! empty( $location_social ) ) {
363
+ $this->event_menu_setting( $menu_data['menu-name'], $location_social, 'Location: social menu', $menu_id );
364
  }
365
  }
366
  }
373
  if ( ! empty( $menus ) ) {
374
  foreach ( $menus as $menu ) {
375
  array_push(
376
+ $this->old_menu_terms,
377
  array(
378
  'term_id' => $menu->term_id,
379
  'name' => $menu->name,
383
  if ( ! empty( $items ) ) {
384
  foreach ( $items as $item ) {
385
  array_push(
386
+ $this->old_menu_items,
387
  array(
388
  'menu_id' => $menu->term_id,
389
  'item_id' => $item->ID,
419
  if ( $is_nav_menu ) {
420
  if ( isset( $get_array['action'] ) && 'delete' == $get_array['action'] ) {
421
  if ( isset( $get_array['menu'] ) ) {
422
+ $this->old_menu = wp_get_nav_menu_object( $get_array['menu'] );
423
  }
424
  } else {
425
  $this->BuildOldMenuTermsAndItems();
426
  }
427
+ $this->old_menu_locations = get_nav_menu_locations();
428
  }
429
  }
430
 
433
  */
434
  public function CustomizeInit() {
435
  $this->BuildOldMenuTermsAndItems();
436
+ $this->old_menu_locations = get_nav_menu_locations();
437
  }
438
 
439
  /**
455
  }
456
 
457
  // Deleted Menu.
458
+ if ( isset( $update_menus ) && isset( $this->old_menu_terms ) ) {
459
+ $terms = array_diff( array_map( 'serialize', $this->old_menu_terms ), array_map( 'serialize', $update_menus ) );
460
  $terms = array_map( 'unserialize', $terms );
461
 
462
  if ( isset( $terms ) && count( $terms ) > 0 ) {
463
  foreach ( $terms as $term ) {
464
+ $this->plugin->alerts->trigger_event(
465
  2081,
466
  array(
467
  'MenuName' => $term['name'],
483
  $is_occurred_event = false;
484
  $menu = wp_get_nav_menu_object( $value['nav_menu_term_id'] );
485
  $content_name = ! empty( $value['title'] ) ? $value['title'] : 'no title';
486
+ if ( ! empty( $this->old_menu_items ) ) {
487
+ foreach ( $this->old_menu_items as $old_item ) {
488
  $item_id = substr( trim( $key, ']' ), 14 );
489
  if ( $old_item['item_id'] == $item_id ) {
490
  // Modified Items in the menu.
491
  if ( $old_item['title'] != $content_name ) {
492
  $is_occurred_event = true;
493
+ $this->event_modified_items( $value['type_label'], $content_name, $menu->name, $menu->term_id );
494
  }
495
  // Moved as a sub-item.
496
  if ( $old_item['menu_item_parent'] != $value['menu_item_parent'] && 0 != $value['menu_item_parent'] ) {
497
  $is_occurred_event = true;
498
+ $parent_name = $this->get_item_name( $value['nav_menu_term_id'], $value['menu_item_parent'] );
499
+ $this->event_change_sub_item( $content_name, $parent_name, $menu->name, $menu->term_id );
500
  }
501
  // Changed order of the objects in a menu.
502
  if ( $old_item['menu_order'] != $value['position'] ) {
503
  $is_occurred_event = true;
504
+ $this->event_change_order( $content_name, $menu->name, $menu->term_id );
505
  }
506
  }
507
  }
509
  // Add Items to the menu.
510
  if ( ! $is_occurred_event ) {
511
  $menu_name = ! empty( $customized['new_menu_name'] ) ? $customized['new_menu_name'] : $menu->name;
512
+ $this->event_add_items( $value['type_label'], $content_name, $menu_name, $menu->term_id );
513
  }
514
  } else {
515
  // Menu changed name.
516
+ if ( isset( $update_menus ) && isset( $this->old_menu_terms ) ) {
517
+ foreach ( $this->old_menu_terms as $old_menu ) {
518
  foreach ( $update_menus as $update_menu ) {
519
  if ( $old_menu['term_id'] == $update_menu['term_id'] && $old_menu['name'] != $update_menu['name'] ) {
520
+ $this->event_change_name( $old_menu['name'], $update_menu['name'], $menu->term_id );
521
  }
522
  }
523
  }
525
  // Setting Auto add pages.
526
  if ( ! empty( $value ) && isset( $value['auto_add'] ) ) {
527
  if ( $value['auto_add'] ) {
528
+ $this->event_menu_setting( $value['name'], 'Enabled', 'Auto add pages', $menu->term_id );
529
  } else {
530
+ $this->event_menu_setting( $value['name'], 'Disabled', 'Auto add pages', $menu->term_id );
531
  }
532
  }
533
  // Setting Location.
536
  if ( ! empty( $value ) ) {
537
  $menu = wp_get_nav_menu_object( $value );
538
  $menu_name = ! empty( $customized['new_menu_name'] ) ? $customized['new_menu_name'] : ( ! empty( $menu ) ? $menu->name : '' );
539
+ $this->event_menu_setting( $menu_name, 'Enabled', 'Location: ' . $loc . ' menu', $menu->term_id );
540
  } else {
541
+ if ( ! empty( $this->old_menu_locations[ $loc ] ) ) {
542
+ $menu = wp_get_nav_menu_object( $this->old_menu_locations[ $loc ] );
543
  $menu_name = ! empty( $customized['new_menu_name'] ) ? $customized['new_menu_name'] : ( ! empty( $menu ) ? $menu->name : '' );
544
+ $this->event_menu_setting( $menu_name, 'Disabled', 'Location: ' . $loc . ' menu', $menu->term_id );
545
  }
546
  }
547
  }
548
  // Remove items from the menu.
549
  if ( false !== strpos( $key, 'nav_menu_item[' ) ) {
550
  $item_id = substr( trim( $key, ']' ), 14 );
551
+ if ( ! empty( $this->old_menu_items ) ) {
552
+ foreach ( $this->old_menu_items as $old_item ) {
553
  if ( $old_item['item_id'] == $item_id ) {
554
+ $this->event_remove_items( $old_item['object'], $old_item['title'], $old_item['menu_name'], $menu->term_id );
555
  }
556
  }
557
  }
568
  *
569
  * @param string $content_type - Type of content.
570
  * @param string $content_name - Name of content.
571
+ * @param string $menu_name - Menu name.
572
+ * @param int $menu_id - Menu ID.
573
  */
574
+ private function event_add_items( $content_type, $content_name, $menu_name, $menu_id ) {
575
+ $this->plugin->alerts->trigger_event(
576
  2079,
577
  array(
578
  'ContentType' => 'custom' === $content_type ? 'custom link' : $content_type,
588
  *
589
  * @param string $content_type - Type of content.
590
  * @param string $content_name - Name of content.
591
+ * @param string $menu_name - Menu name.
592
+ * @param int $menu_id - Menu ID.
593
  */
594
+ private function event_remove_items( $content_type, $content_name, $menu_name, $menu_id ) {
595
+ $this->plugin->alerts->trigger_event(
596
  2080,
597
  array(
598
  'ContentType' => 'custom' === $content_type ? 'custom link' : $content_type,
606
  /**
607
  * Changed menu setting.
608
  *
609
+ * @param string $menu_name - Menu Name.
610
+ * @param string $status - Status of menu.
611
  * @param string $menu_setting - Menu setting.
612
+ * @param int $menu_id - Menu ID.
613
  */
614
+ private function event_menu_setting( $menu_name, $status, $menu_setting, $menu_id ) {
615
  $status = 'Enabled' === $status ? 'enabled' : 'disabled';
616
+ $this->plugin->alerts->trigger_event(
617
  2082,
618
  array(
619
  'EventType' => $status,
629
  *
630
  * @param string $content_type - Type of content.
631
  * @param string $content_name - Name of content.
632
+ * @param string $menu_name - Menu name.
633
+ * @param int $menu_id - Menu ID.
634
  */
635
+ private function event_modified_items( $content_type, $content_name, $menu_name, $menu_id ) {
636
+ $this->plugin->alerts->trigger_event(
637
  2083,
638
  array(
639
  'ContentType' => 'custom' === $content_type ? 'custom link' : $content_type,
649
  *
650
  * @param string $old_menu_name - Old Menu Name.
651
  * @param string $new_menu_name - New Menu Name.
652
+ * @param int $menu_id Menu ID.
653
  */
654
+ private function event_change_name( $old_menu_name, $new_menu_name, $menu_id ) {
655
+ $this->plugin->alerts->trigger_event(
656
  2084,
657
  array(
658
  'OldMenuName' => $old_menu_name,
667
  *
668
  * @param string $item_name - Item name.
669
  * @param string $menu_name - Menu name.
670
+ * @param int $menu_id - Menu ID.
671
  */
672
+ private function event_change_order( $item_name, $menu_name, $menu_id ) {
673
+ // Skip if an order change for this menu has already been reported during the current request.
674
+ if ( in_array( $menu_id, $this->order_changed_menu_ids ) ) { // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
675
  return;
676
  }
677
 
678
+ $this->plugin->alerts->trigger_event(
679
  2085,
680
  array(
681
  'ItemName' => $item_name,
684
  )
685
  );
686
 
687
+ // Keep track of already reported order changes to prevent repetitive events.
688
  array_push( $this->order_changed_menu_ids, $menu_id );
689
  }
690
 
691
  /**
692
  * Moved objects as a sub-item.
693
  *
694
+ * @param string $item_name - Item name.
695
  * @param string $parent_name - Parent Name.
696
+ * @param string $menu_name - Menu Name.
697
+ * @param int $menu_id - Menu ID.
698
  */
699
+ private function event_change_sub_item( $item_name, $parent_name, $menu_name, $menu_id ) {
700
+ $this->plugin->alerts->trigger_event(
701
  2089,
702
  array(
703
  'ItemName' => $item_name,
716
  *
717
  * @return string
718
  */
719
+ private function get_item_name( $term_id, $item_id ) {
720
  $item_name = '';
721
  $menu_items = wp_get_nav_menu_items( $term_id );
722
  foreach ( $menu_items as $menu_item ) {
classes/Sensors/MetaData.php CHANGED
@@ -4,8 +4,9 @@
4
  *
5
  * Meta Data sensor file.
6
  *
7
- * @since 1.0.0
8
- * @package wsal
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -27,9 +28,9 @@ if ( ! defined( 'ABSPATH' ) ) {
27
  * 4019 User changed nickname for a user
28
  * 4020 User changed the display name for a user
29
  *
30
- * @package wsal
31
  * @subpackage sensors
32
- * @since 1.0.0
33
  */
34
  class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
35
 
@@ -43,11 +44,11 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
43
  /**
44
  * Listening to events using WP hooks.
45
  */
46
- public function HookEvents() {
47
- add_action( 'add_post_meta', array( $this, 'EventPostMetaCreated' ), 10, 3 );
48
- add_action( 'update_post_meta', array( $this, 'EventPostMetaUpdating' ), 10, 3 );
49
- add_action( 'updated_post_meta', array( $this, 'EventPostMetaUpdated' ), 10, 4 );
50
- add_action( 'deleted_post_meta', array( $this, 'EventPostMetaDeleted' ), 10, 4 );
51
  add_action( 'save_post', array( $this, 'reset_null_meta_counter' ), 10 );
52
  add_action( 'add_user_meta', array( $this, 'event_user_meta_created' ), 10, 3 );
53
  add_action( 'update_user_meta', array( $this, 'event_user_meta_updating' ), 10, 3 );
@@ -62,8 +63,8 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
62
  * @param string $meta_key - Meta key.
63
  * @param mixed $meta_value - Meta value.
64
  */
65
- public function EventPostMetaCreated( $object_id, $meta_key, $meta_value ) {
66
- if ( ! $this->CanLogMetaKey( 'post', $object_id, $meta_key ) || is_array( $meta_value ) ) {
67
  return;
68
  }
69
 
@@ -82,8 +83,9 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
82
  }
83
 
84
  // Remove WC coupons from ignored array.
85
- if ( ( $key = array_search( 'shop_coupon', $this->plugin->alerts->ignored_cpts ) ) !== false) {
86
- unset( $this->plugin->alerts->ignored_cpts[$key] );
 
87
  }
88
 
89
  // Ignore post types we are not interested in.
@@ -110,8 +112,8 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
110
  $log_meta_event = apply_filters( 'wsal_before_post_meta_create_event', true, $meta_key, $meta_value, $post );
111
 
112
  if ( $log_meta_event ) {
113
- $editor_link = $this->GetEditorLink( $post );
114
- $this->plugin->alerts->Trigger(
115
  2053,
116
  array(
117
  'PostID' => $object_id,
@@ -136,7 +138,7 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
136
  * @param int $object_id - Object ID.
137
  * @param string $meta_key - Meta key.
138
  */
139
- public function EventPostMetaUpdating( $meta_id, $object_id, $meta_key ) {
140
  static $meta_type = 'post';
141
  $meta = get_metadata_by_mid( $meta_type, $meta_id );
142
 
@@ -154,8 +156,8 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
154
  * @param string $meta_key - Meta key.
155
  * @param mixed $meta_value - Meta value.
156
  */
157
- public function EventPostMetaUpdated( $meta_id, $object_id, $meta_key, $meta_value ) {
158
- if ( ! $this->CanLogMetaKey( 'post', $object_id, $meta_key ) || is_array( $meta_value ) ) {
159
  return;
160
  }
161
 
@@ -178,7 +180,7 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
178
  *
179
  * @param int $meta_id - Meta ID.
180
  * @param int $object_id - Post ID.
181
- * @param array $this->old_meta - Array of meta data holding keys & values of old meta data before updating the current post.
182
  * @param string $meta_key - Meta key.
183
  * @param mixed $meta_value - Meta value.
184
  * @since 3.2.2
@@ -192,21 +194,21 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
192
  * Runs before logging events for post meta updated i.e. 2054 or 2062.
193
  * This filter can be used as check to whether log these events or not.
194
  *
195
- * @since 3.3.1
 
 
 
 
 
196
  *
197
- * @param bool $log_event - True if log meta event 2054 or 2062, false if not.
198
- * @param string $meta_key - Meta key.
199
- * @param mixed $meta_value - Meta value.
200
- * @param stdClass $this->old_meta[ $meta_id ] - Old meta value and key object.
201
- * @param WP_Post $post - Post object.
202
- * @param integer $meta_id - Meta ID.
203
  */
204
  $log_meta_event = apply_filters( 'wsal_before_post_meta_update_event', true, $meta_key, $meta_value, $this->old_meta[ $meta_id ], $post, $meta_id );
205
 
206
  // Check change in meta key.
207
  if ( $log_meta_event && $this->old_meta[ $meta_id ]->key !== $meta_key ) {
208
- $editor_link = $this->GetEditorLink( $post );
209
- $this->plugin->alerts->Trigger(
210
  2062,
211
  array(
212
  'PostID' => $object_id,
@@ -224,8 +226,8 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
224
  )
225
  );
226
  } elseif ( $log_meta_event && $this->old_meta[ $meta_id ]->val !== $meta_value ) { // Check change in meta value.
227
- $editor_link = $this->GetEditorLink( $post );
228
- $this->plugin->alerts->TriggerIf(
229
  2054,
230
  array(
231
  'PostID' => $object_id,
@@ -242,13 +244,14 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
242
  $editor_link['name'] => $editor_link['value'],
243
  ),
244
  /**
245
- * @param WSAL_AlertManager$manager
 
 
246
  * @return bool
247
  */
248
  function ( $manager ) {
249
- // don't fire if there's already an event 2131 or 2132 (ACF relationship change)
250
- return ! $manager->WillOrHasTriggered( 2131 )
251
- && ! $manager->WillOrHasTriggered( 2132 );
252
  }
253
  );
254
  }
@@ -265,7 +268,7 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
265
  * @param string $meta_key - Meta key.
266
  * @param mixed $meta_value - Meta value.
267
  */
268
- public function EventPostMetaDeleted( $meta_ids, $object_id, $meta_key, $meta_value ) {
269
  // If meta key starts with "_" then return.
270
  if ( '_' === substr( $meta_key, 0, 1 ) ) {
271
  return;
@@ -279,9 +282,9 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
279
  return;
280
  }
281
 
282
- $editor_link = $this->GetEditorLink( $post );
283
  foreach ( $meta_ids as $meta_id ) {
284
- if ( ! $this->CanLogMetaKey( 'post', $object_id, $meta_key ) ) {
285
  continue;
286
  }
287
 
@@ -311,8 +314,8 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
311
  continue;
312
  }
313
 
314
- if( 'trash' !== $post->post_status ) {
315
- $this->plugin->alerts->Trigger(
316
  2055,
317
  array(
318
  'PostID' => $object_id,
@@ -349,7 +352,7 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
349
  */
350
  public function event_user_meta_created( $object_id, $meta_key, $meta_value ) {
351
  // Check to see if we can log the meta key.
352
- if ( ! $this->CanLogMetaKey( 'user', $object_id, $meta_key ) || is_array( $meta_value ) ) {
353
  return;
354
  }
355
 
@@ -366,7 +369,7 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
366
  // Get user.
367
  $user = get_user_by( 'ID', $object_id );
368
 
369
- $this->plugin->alerts->TriggerIf(
370
  4016,
371
  array(
372
  'TargetUsername' => $user->user_login,
@@ -409,7 +412,7 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
409
  */
410
  public function event_user_meta_updated( $meta_id, $object_id, $meta_key, $meta_value ) {
411
  // Check to see if we can log the meta key.
412
- if ( ! $this->CanLogMetaKey( 'user', $object_id, $meta_key ) || is_array( $meta_value ) ) {
413
  return;
414
  }
415
 
@@ -427,7 +430,7 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
427
  if ( isset( $this->old_meta[ $meta_id ] ) && ! in_array( $meta_key, $username_meta, true ) ) {
428
  // Check change in meta value.
429
  if ( $this->old_meta[ $meta_id ]->val !== $meta_value ) {
430
- $this->plugin->alerts->TriggerIf(
431
  4015,
432
  array(
433
  'TargetUsername' => $user->user_login,
@@ -450,7 +453,7 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
450
  switch ( $meta_key ) {
451
  case 'first_name':
452
  if ( $this->old_meta[ $meta_id ]->val !== $meta_value ) {
453
- $this->plugin->alerts->Trigger(
454
  4017,
455
  array(
456
  'TargetUsername' => $user->user_login,
@@ -468,7 +471,7 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
468
 
469
  case 'last_name':
470
  if ( $this->old_meta[ $meta_id ]->val !== $meta_value ) {
471
- $this->plugin->alerts->Trigger(
472
  4018,
473
  array(
474
  'TargetUsername' => $user->user_login,
@@ -485,7 +488,7 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
485
 
486
  case 'nickname':
487
  if ( $this->old_meta[ $meta_id ]->val !== $meta_value ) {
488
- $this->plugin->alerts->Trigger(
489
  4019,
490
  array(
491
  'TargetUsername' => $user->user_login,
@@ -514,8 +517,8 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
514
  * @return bool
515
  * @since 3.2.3
516
  */
517
- public function must_not_contain_role_changes( WSAL_AlertManager $manager ) {
518
- return ! $manager->WillOrHasTriggered( 4002 );
519
  }
520
 
521
  /**
@@ -526,8 +529,8 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
526
  * @return bool
527
  * @since 3.2.3
528
  */
529
- public function must_not_contain_new_user_alert( WSAL_AlertManager $manager ) {
530
- return ! $manager->WillOrHasTriggered( 4001 ) && ! $manager->WillOrHasTriggered( 4012 );
531
  }
532
 
533
  /**
4
  *
5
  * Meta Data sensor file.
6
  *
7
+ * @since 1.0.0
8
+ * @package wsal
9
+ * @subpackage sensors
10
  */
11
 
12
  // Exit if accessed directly.
28
  * 4019 User changed nickname for a user
29
  * 4020 User changed the display name for a user
30
  *
31
+ * @package wsal
32
  * @subpackage sensors
33
+ * @since 1.0.0
34
  */
35
  class WSAL_Sensors_MetaData extends WSAL_AbstractMetaDataSensor {
36
 
44
  /**
45
  * Listening to events using WP hooks.
46
  */
47
+ public function hook_events() {
48
+ add_action( 'add_post_meta', array( $this, 'event_post_meta_created' ), 10, 3 );
49
+ add_action( 'update_post_meta', array( $this, 'event_post_meta_updating' ), 10, 3 );
50
+ add_action( 'updated_post_meta', array( $this, 'event_post_meta_updated' ), 10, 4 );
51
+ add_action( 'deleted_post_meta', array( $this, 'event_post_meta_deleted' ), 10, 4 );
52
  add_action( 'save_post', array( $this, 'reset_null_meta_counter' ), 10 );
53
  add_action( 'add_user_meta', array( $this, 'event_user_meta_created' ), 10, 3 );
54
  add_action( 'update_user_meta', array( $this, 'event_user_meta_updating' ), 10, 3 );
63
  * @param string $meta_key - Meta key.
64
  * @param mixed $meta_value - Meta value.
65
  */
66
+ public function event_post_meta_created( $object_id, $meta_key, $meta_value ) {
67
+ if ( ! $this->can_log_meta_key( 'post', $object_id, $meta_key ) || is_array( $meta_value ) ) {
68
  return;
69
  }
70
 
83
  }
84
 
85
  // Remove WC coupons from ignored array.
86
+ $key = array_search( 'shop_coupon', $this->plugin->alerts->ignored_cpts ); // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
87
+ if ( false !== $key ) {
88
+ unset( $this->plugin->alerts->ignored_cpts[ $key ] );
89
  }
90
 
91
  // Ignore post types we are not interested in.
112
  $log_meta_event = apply_filters( 'wsal_before_post_meta_create_event', true, $meta_key, $meta_value, $post );
113
 
114
  if ( $log_meta_event ) {
115
+ $editor_link = $this->get_editor_link( $post );
116
+ $this->plugin->alerts->trigger_event(
117
  2053,
118
  array(
119
  'PostID' => $object_id,
138
  * @param int $object_id - Object ID.
139
  * @param string $meta_key - Meta key.
140
  */
141
+ public function event_post_meta_updating( $meta_id, $object_id, $meta_key ) {
142
  static $meta_type = 'post';
143
  $meta = get_metadata_by_mid( $meta_type, $meta_id );
144
 
156
  * @param string $meta_key - Meta key.
157
  * @param mixed $meta_value - Meta value.
158
  */
159
+ public function event_post_meta_updated( $meta_id, $object_id, $meta_key, $meta_value ) {
160
+ if ( ! $this->can_log_meta_key( 'post', $object_id, $meta_key ) || is_array( $meta_value ) ) {
161
  return;
162
  }
163
 
180
  *
181
  * @param int $meta_id - Meta ID.
182
  * @param int $object_id - Post ID.
183
+ * @param array $this->old_meta - Array of metadata holding keys & values of old metadata before updating the current post.
184
  * @param string $meta_key - Meta key.
185
  * @param mixed $meta_value - Meta value.
186
  * @since 3.2.2
194
  * Runs before logging events for post meta updated i.e. 2054 or 2062.
195
  * This filter can be used as check to whether log these events or not.
196
  *
197
+ * @param bool $log_event - True if log meta event 2054 or 2062, false if not.
198
+ * @param string $meta_key - Meta key.
199
+ * @param mixed $meta_value - Meta value.
200
+ * @param stdClass $old_meta - Old meta value and key object.
201
+ * @param WP_Post $post - Post object.
202
+ * @param integer $meta_id - Meta ID.
203
  *
204
+ * @since 3.3.1
 
 
 
 
 
205
  */
206
  $log_meta_event = apply_filters( 'wsal_before_post_meta_update_event', true, $meta_key, $meta_value, $this->old_meta[ $meta_id ], $post, $meta_id );
207
 
208
  // Check change in meta key.
209
  if ( $log_meta_event && $this->old_meta[ $meta_id ]->key !== $meta_key ) {
210
+ $editor_link = $this->get_editor_link( $post );
211
+ $this->plugin->alerts->trigger_event(
212
  2062,
213
  array(
214
  'PostID' => $object_id,
226
  )
227
  );
228
  } elseif ( $log_meta_event && $this->old_meta[ $meta_id ]->val !== $meta_value ) { // Check change in meta value.
229
+ $editor_link = $this->get_editor_link( $post );
230
+ $this->plugin->alerts->trigger_event_if(
231
  2054,
232
  array(
233
  'PostID' => $object_id,
244
  $editor_link['name'] => $editor_link['value'],
245
  ),
246
  /**
247
+ * Don't fire if there's already an event 2131 or 2132 (ACF relationship change).
248
+ *
249
+ * @param WSAL_AlertManager $manager
250
  * @return bool
251
  */
252
  function ( $manager ) {
253
+ return ! $manager->will_or_has_triggered( 2131 )
254
+ && ! $manager->will_or_has_triggered( 2132 );
 
255
  }
256
  );
257
  }
268
  * @param string $meta_key - Meta key.
269
  * @param mixed $meta_value - Meta value.
270
  */
271
+ public function event_post_meta_deleted( $meta_ids, $object_id, $meta_key, $meta_value ) {
272
  // If meta key starts with "_" then return.
273
  if ( '_' === substr( $meta_key, 0, 1 ) ) {
274
  return;
282
  return;
283
  }
284
 
285
+ $editor_link = $this->get_editor_link( $post );
286
  foreach ( $meta_ids as $meta_id ) {
287
+ if ( ! $this->can_log_meta_key( 'post', $object_id, $meta_key ) ) {
288
  continue;
289
  }
290
 
314
  continue;
315
  }
316
 
317
+ if ( 'trash' !== $post->post_status ) {
318
+ $this->plugin->alerts->trigger_event(
319
  2055,
320
  array(
321
  'PostID' => $object_id,
352
  */
353
  public function event_user_meta_created( $object_id, $meta_key, $meta_value ) {
354
  // Check to see if we can log the meta key.
355
+ if ( ! $this->can_log_meta_key( 'user', $object_id, $meta_key ) || is_array( $meta_value ) ) {
356
  return;
357
  }
358
 
369
  // Get user.
370
  $user = get_user_by( 'ID', $object_id );
371
 
372
+ $this->plugin->alerts->trigger_event_if(
373
  4016,
374
  array(
375
  'TargetUsername' => $user->user_login,
412
  */
413
  public function event_user_meta_updated( $meta_id, $object_id, $meta_key, $meta_value ) {
414
  // Check to see if we can log the meta key.
415
+ if ( ! $this->can_log_meta_key( 'user', $object_id, $meta_key ) || is_array( $meta_value ) ) {
416
  return;
417
  }
418
 
430
  if ( isset( $this->old_meta[ $meta_id ] ) && ! in_array( $meta_key, $username_meta, true ) ) {
431
  // Check change in meta value.
432
  if ( $this->old_meta[ $meta_id ]->val !== $meta_value ) {
433
+ $this->plugin->alerts->trigger_event_if(
434
  4015,
435
  array(
436
  'TargetUsername' => $user->user_login,
453
  switch ( $meta_key ) {
454
  case 'first_name':
455
  if ( $this->old_meta[ $meta_id ]->val !== $meta_value ) {
456
+ $this->plugin->alerts->trigger_event(
457
  4017,
458
  array(
459
  'TargetUsername' => $user->user_login,
471
 
472
  case 'last_name':
473
  if ( $this->old_meta[ $meta_id ]->val !== $meta_value ) {
474
+ $this->plugin->alerts->trigger_event(
475
  4018,
476
  array(
477
  'TargetUsername' => $user->user_login,
488
 
489
  case 'nickname':
490
  if ( $this->old_meta[ $meta_id ]->val !== $meta_value ) {
491
+ $this->plugin->alerts->trigger_event(
492
  4019,
493
  array(
494
  'TargetUsername' => $user->user_login,
517
  * @return bool
518
  * @since 3.2.3
519
  */
520
+ public function must_not_contain_role_changes( $manager ) {
521
+ return ! $manager->will_or_has_triggered( 4002 );
522
  }
523
 
524
  /**
529
  * @return bool
530
  * @since 3.2.3
531
  */
532
+ public function must_not_contain_new_user_alert( $manager ) {
533
+ return ! $manager->will_or_has_triggered( 4001 ) && ! $manager->will_or_has_triggered( 4012 );
534
  }
535
 
536
  /**
classes/Sensors/Multisite.php CHANGED
@@ -4,9 +4,9 @@
4
  *
5
  * Multisite sensor file.
6
  *
7
- * @since 1.0.0
8
  *
9
- * @package wsal
10
  * @subpackage sensors
11
  */
12
 
@@ -30,7 +30,7 @@ if ( ! defined( 'ABSPATH' ) ) {
30
  * 7005 Existing site deleted from network
31
  * 7012 Network registration option updated
32
  *
33
- * @package wsal
34
  * @subpackage sensors
35
  */
36
  class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
@@ -43,21 +43,21 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
43
  protected $old_allowedthemes = null;
44
 
45
  /**
46
- * Listening to events using WP hooks.
47
  */
48
- public function HookEvents() {
49
- add_action( 'admin_init', array( $this, 'EventAdminInit' ) );
50
  if ( current_user_can( 'switch_themes' ) ) {
51
- add_action( 'shutdown', array( $this, 'EventAdminShutdown' ) );
52
  }
53
- add_action( 'wp_insert_site', array( $this, 'EventNewBlog' ), 10, 1 );
54
- add_action( 'archive_blog', array( $this, 'EventArchiveBlog' ) );
55
- add_action( 'unarchive_blog', array( $this, 'EventUnarchiveBlog' ) );
56
- add_action( 'activate_blog', array( $this, 'EventActivateBlog' ) );
57
- add_action( 'deactivate_blog', array( $this, 'EventDeactivateBlog' ) );
58
- add_action( 'wp_uninitialize_site', array( $this, 'EventDeleteBlog' ) );
59
- add_action( 'add_user_to_blog', array( $this, 'EventUserAddedToBlog' ), 10, 3 );
60
- add_action( 'remove_user_from_blog', array( $this, 'EventUserRemovedFromBlog' ), 10, 2 );
61
 
62
  add_action( 'update_site_option', array( $this, 'on_network_option_change' ), 10, 4 );
63
  }
@@ -83,7 +83,7 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
83
  'blog' => __( 'users can register new sites', 'wp-security-audit-log' ),
84
  'all' => __( 'sites & users can be registered', 'wp-security-audit-log' ),
85
  );
86
- $this->plugin->alerts->Trigger(
87
  7012,
88
  array(
89
  'previous_setting' => ( isset( $possible_values[ $old_value ] ) ) ? $possible_values[ $old_value ] : $old_value,
@@ -93,7 +93,7 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
93
  break;
94
 
95
  case 'add_new_users':
96
- $this->plugin->alerts->Trigger(
97
  7007,
98
  array(
99
  'EventType' => ( ! $value ) ? 'disabled' : 'enabled',
@@ -102,7 +102,7 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
102
  break;
103
 
104
  case 'upload_space_check_disabled':
105
- $this->plugin->alerts->Trigger(
106
  7008,
107
  array(
108
  'EventType' => ( $value ) ? 'disabled' : 'enabled',
@@ -111,7 +111,7 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
111
  break;
112
 
113
  case 'blog_upload_space':
114
- $this->plugin->alerts->Trigger(
115
  7009,
116
  array(
117
  'old_value' => sanitize_text_field( $old_value ),
@@ -121,7 +121,7 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
121
  break;
122
 
123
  case 'upload_filetypes':
124
- $this->plugin->alerts->Trigger(
125
  7010,
126
  array(
127
  'old_value' => sanitize_text_field( $old_value ),
@@ -131,7 +131,7 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
131
  break;
132
 
133
  case 'fileupload_maxk':
134
- $this->plugin->alerts->Trigger(
135
  7009,
136
  array(
137
  'old_value' => sanitize_text_field( $old_value ),
@@ -146,14 +146,16 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
146
  /**
147
  * Triggered when a user accesses the admin area.
148
  */
149
- public function EventAdminInit() {
150
  $this->old_allowedthemes = array_keys( (array) get_site_option( 'allowedthemes' ) );
151
  }
152
 
153
  /**
154
  * Activated/Deactivated theme on network.
 
 
155
  */
156
- public function EventAdminShutdown() {
157
  if ( is_null( $this->old_allowedthemes ) ) {
158
  return;
159
  }
@@ -161,9 +163,9 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
161
 
162
  // Check for enabled themes.
163
  foreach ( $new_allowedthemes as $theme ) {
164
- if ( ! in_array( $theme, (array) $this->old_allowedthemes ) ) {
165
  $theme = wp_get_theme( $theme );
166
- $this->plugin->alerts->Trigger(
167
  5008,
168
  array(
169
  'Theme' => (object) array(
@@ -181,9 +183,9 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
181
 
182
  // Check for disabled themes.
183
  foreach ( (array) $this->old_allowedthemes as $theme ) {
184
- if ( ! in_array( $theme, $new_allowedthemes ) ) {
185
  $theme = wp_get_theme( $theme );
186
- $this->plugin->alerts->Trigger(
187
  5009,
188
  array(
189
  'Theme' => (object) array(
@@ -205,11 +207,11 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
205
  *
206
  * @param WP_Site $new_blog - New site object.
207
  */
208
- public function EventNewBlog( $new_blog ) {
209
  $blog_id = $new_blog->blog_id;
210
 
211
  /*
212
- * Site meta data nor options are not setup at this points so get_blog_option and get_home_url are not
213
  * returning anything for the new blog.
214
  *
215
  * The following code to work out the correct URL for the new site was taken from ms-site.php (WP 5.7).
@@ -222,15 +224,15 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
222
 
223
  $home_scheme = 'http';
224
  if ( ! is_subdomain_install() ) {
225
- if ( 'https' === parse_url( get_home_url( $network->site_id ), PHP_URL_SCHEME ) ) {
226
  $home_scheme = 'https';
227
  }
228
  }
229
 
230
- $blog_title = strip_tags( $_POST['blog']['title'] );
231
  $blog_url = untrailingslashit( $home_scheme . '://' . $new_blog->domain . $new_blog->path );
232
 
233
- $this->plugin->alerts->Trigger(
234
  7000,
235
  array(
236
  'BlogID' => $blog_id,
@@ -245,8 +247,8 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
245
  *
246
  * @param int $blog_id - Blog ID.
247
  */
248
- public function EventArchiveBlog( $blog_id ) {
249
- $this->plugin->alerts->Trigger(
250
  7001,
251
  array(
252
  'BlogID' => $blog_id,
@@ -261,8 +263,8 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
261
  *
262
  * @param int $blog_id - Blog ID.
263
  */
264
- public function EventUnarchiveBlog( $blog_id ) {
265
- $this->plugin->alerts->Trigger(
266
  7002,
267
  array(
268
  'BlogID' => $blog_id,
@@ -277,8 +279,8 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
277
  *
278
  * @param int $blog_id - Blog ID.
279
  */
280
- public function EventActivateBlog( $blog_id ) {
281
- $this->plugin->alerts->Trigger(
282
  7003,
283
  array(
284
  'BlogID' => $blog_id,
@@ -293,8 +295,8 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
293
  *
294
  * @param int $blog_id - Blog ID.
295
  */
296
- public function EventDeactivateBlog( $blog_id ) {
297
- $this->plugin->alerts->Trigger(
298
  7004,
299
  array(
300
  'BlogID' => $blog_id,
@@ -309,9 +311,9 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
309
  *
310
  * @param WP_Site $deleted_blog - Deleted blog object.
311
  */
312
- public function EventDeleteBlog( $deleted_blog ) {
313
  $blog_id = $deleted_blog->blog_id;
314
- $this->plugin->alerts->Trigger(
315
  7005,
316
  array(
317
  'BlogID' => $blog_id,
@@ -328,9 +330,9 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
328
  * @param string $role - User role.
329
  * @param int $blog_id - Blog ID.
330
  */
331
- public function EventUserAddedToBlog( $user_id, $role, $blog_id ) {
332
  $user = get_userdata( $user_id );
333
- $this->plugin->alerts->TriggerIf(
334
  4010,
335
  array(
336
  'TargetUserID' => $user_id,
@@ -342,7 +344,7 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
342
  'LastName' => $user ? $user->user_lastname : false,
343
  'EditUserLink' => add_query_arg( 'user_id', $user_id, admin_url( 'user-edit.php' ) ),
344
  ),
345
- array( $this, 'MustNotContainCreateUser' )
346
  );
347
  }
348
 
@@ -352,9 +354,9 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
352
  * @param int $user_id - User ID.
353
  * @param int $blog_id - Blog ID.
354
  */
355
- public function EventUserRemovedFromBlog( $user_id, $blog_id ) {
356
  $user = get_userdata( $user_id );
357
- $this->plugin->alerts->TriggerIf(
358
  4011,
359
  array(
360
  'TargetUserID' => $user_id,
@@ -366,7 +368,7 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
366
  'LastName' => $user ? $user->user_lastname : false,
367
  'EditUserLink' => add_query_arg( 'user_id', $user_id, admin_url( 'user-edit.php' ) ),
368
  ),
369
- array( $this, 'MustNotContainCreateUser' )
370
  );
371
  }
372
 
@@ -376,7 +378,7 @@ class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
376
  * @param WSAL_AlertManager $mgr - Instance of Alert Manager.
377
  * @return bool
378
  */
379
- public function MustNotContainCreateUser( WSAL_AlertManager $mgr ) {
380
- return ! $mgr->WillTrigger( 4012 );
381
  }
382
  }
4
  *
5
  * Multisite sensor file.
6
  *
7
+ * @since 1.0.0
8
  *
9
+ * @package wsal
10
  * @subpackage sensors
11
  */
12
 
30
  * 7005 Existing site deleted from network
31
  * 7012 Network registration option updated
32
  *
33
+ * @package wsal
34
  * @subpackage sensors
35
  */
36
  class WSAL_Sensors_Multisite extends WSAL_AbstractSensor {
43
  protected $old_allowedthemes = null;
44
 
45
  /**
46
+ * {@inheritDoc}
47
  */
48
+ public function hook_events() {
49
+ add_action( 'admin_init', array( $this, 'event_admin_init' ) );
50
  if ( current_user_can( 'switch_themes' ) ) {
51
+ add_action( 'shutdown', array( $this, 'event_admin_shutdown' ) );
52
  }
53
+ add_action( 'wp_insert_site', array( $this, 'event_new_blog' ), 10, 1 );
54
+ add_action( 'archive_blog', array( $this, 'event_archive_blog' ) );
55
+ add_action( 'unarchive_blog', array( $this, 'event_unarchive_blog' ) );
56
+ add_action( 'activate_blog', array( $this, 'event_activate_blog' ) );
57
+ add_action( 'deactivate_blog', array( $this, 'event_deactivate_blog' ) );
58
+ add_action( 'wp_uninitialize_site', array( $this, 'event_delete_blog' ) );
59
+ add_action( 'add_user_to_blog', array( $this, 'event_user_added_to_blog' ), 10, 3 );
60
+ add_action( 'remove_user_from_blog', array( $this, 'event_user_removed_from_blog' ), 10, 2 );
61
 
62
  add_action( 'update_site_option', array( $this, 'on_network_option_change' ), 10, 4 );
63
  }
83
  'blog' => __( 'users can register new sites', 'wp-security-audit-log' ),
84
  'all' => __( 'sites & users can be registered', 'wp-security-audit-log' ),
85
  );
86
+ $this->plugin->alerts->trigger_event(
87
  7012,
88
  array(
89
  'previous_setting' => ( isset( $possible_values[ $old_value ] ) ) ? $possible_values[ $old_value ] : $old_value,
93
  break;
94
 
95
  case 'add_new_users':
96
+ $this->plugin->alerts->trigger_event(
97
  7007,
98
  array(
99
  'EventType' => ( ! $value ) ? 'disabled' : 'enabled',
102
  break;
103
 
104
  case 'upload_space_check_disabled':
105
+ $this->plugin->alerts->trigger_event(
106
  7008,
107
  array(
108
  'EventType' => ( $value ) ? 'disabled' : 'enabled',
111
  break;
112
 
113
  case 'blog_upload_space':
114
+ $this->plugin->alerts->trigger_event(
115
  7009,
116
  array(
117
  'old_value' => sanitize_text_field( $old_value ),
121
  break;
122
 
123
  case 'upload_filetypes':
124
+ $this->plugin->alerts->trigger_event(
125
  7010,
126
  array(
127
  'old_value' => sanitize_text_field( $old_value ),
131
  break;
132
 
133
  case 'fileupload_maxk':
134
+ $this->plugin->alerts->trigger_event(
135
  7009,
136
  array(
137
  'old_value' => sanitize_text_field( $old_value ),
146
  /**
147
  * Triggered when a user accesses the admin area.
148
  */
149
+ public function event_admin_init() {
150
  $this->old_allowedthemes = array_keys( (array) get_site_option( 'allowedthemes' ) );
151
  }
152
 
153
  /**
154
  * Activated/Deactivated theme on network.
155
+ *
156
+ * phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
157
  */
158
+ public function event_admin_shutdown() {
159
  if ( is_null( $this->old_allowedthemes ) ) {
160
  return;
161
  }
163
 
164
  // Check for enabled themes.
165
  foreach ( $new_allowedthemes as $theme ) {
166
+ if ( ! in_array( $theme, (array) $this->old_allowedthemes, true ) ) {
167
  $theme = wp_get_theme( $theme );
168
+ $this->plugin->alerts->trigger_event(
169
  5008,
170
  array(
171
  'Theme' => (object) array(
183
 
184
  // Check for disabled themes.
185
  foreach ( (array) $this->old_allowedthemes as $theme ) {
186
+ if ( ! in_array( $theme, $new_allowedthemes, true ) ) {
187
  $theme = wp_get_theme( $theme );
188
+ $this->plugin->alerts->trigger_event(
189
  5009,
190
  array(
191
  'Theme' => (object) array(
207
  *
208
  * @param WP_Site $new_blog - New site object.
209
  */
210
+ public function event_new_blog( $new_blog ) {
211
  $blog_id = $new_blog->blog_id;
212
 
213
  /*
214
+ * Site metadata nor options are not setup at this point so get_blog_option and get_home_url are not
215
  * returning anything for the new blog.
216
  *
217
  * The following code to work out the correct URL for the new site was taken from ms-site.php (WP 5.7).
224
 
225
  $home_scheme = 'http';
226
  if ( ! is_subdomain_install() ) {
227
+ if ( 'https' === parse_url( get_home_url( $network->site_id ), PHP_URL_SCHEME ) ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.parse_url_parse_url
228
  $home_scheme = 'https';
229
  }
230
  }
231
 
232
+ $blog_title = strip_tags( $_POST['blog']['title'] ); // phpcs:ignore
233
  $blog_url = untrailingslashit( $home_scheme . '://' . $new_blog->domain . $new_blog->path );
234
 
235
+ $this->plugin->alerts->trigger_event(
236
  7000,
237
  array(
238
  'BlogID' => $blog_id,
247
  *
248
  * @param int $blog_id - Blog ID.
249
  */
250
+ public function event_archive_blog( $blog_id ) {
251
+ $this->plugin->alerts->trigger_event(
252
  7001,
253
  array(
254
  'BlogID' => $blog_id,
263
  *
264
  * @param int $blog_id - Blog ID.
265
  */
266
+ public function event_unarchive_blog( $blog_id ) {
267
+ $this->plugin->alerts->trigger_event(
268
  7002,
269
  array(
270
  'BlogID' => $blog_id,
279
  *
280
  * @param int $blog_id - Blog ID.
281
  */
282
+ public function event_activate_blog( $blog_id ) {
283
+ $this->plugin->alerts->trigger_event(
284
  7003,
285
  array(
286
  'BlogID' => $blog_id,
295
  *
296
  * @param int $blog_id - Blog ID.
297
  */
298
+ public function event_deactivate_blog( $blog_id ) {
299
+ $this->plugin->alerts->trigger_event(
300
  7004,
301
  array(
302
  'BlogID' => $blog_id,
311
  *
312
  * @param WP_Site $deleted_blog - Deleted blog object.
313
  */
314
+ public function event_delete_blog( $deleted_blog ) {
315
  $blog_id = $deleted_blog->blog_id;
316
+ $this->plugin->alerts->trigger_event(
317
  7005,
318
  array(
319
  'BlogID' => $blog_id,
330
  * @param string $role - User role.
331
  * @param int $blog_id - Blog ID.
332
  */
333
+ public function event_user_added_to_blog( $user_id, $role, $blog_id ) {
334
  $user = get_userdata( $user_id );
335
+ $this->plugin->alerts->trigger_event_if(
336
  4010,
337
  array(
338
  'TargetUserID' => $user_id,
344
  'LastName' => $user ? $user->user_lastname : false,
345
  'EditUserLink' => add_query_arg( 'user_id', $user_id, admin_url( 'user-edit.php' ) ),
346
  ),
347
+ array( $this, 'must_not_contain_create_user' )
348
  );
349
  }
350
 
354
  * @param int $user_id - User ID.
355
  * @param int $blog_id - Blog ID.
356
  */
357
+ public function event_user_removed_from_blog( $user_id, $blog_id ) {
358
  $user = get_userdata( $user_id );
359
+ $this->plugin->alerts->trigger_event_if(
360
  4011,
361
  array(
362
  'TargetUserID' => $user_id,
368
  'LastName' => $user ? $user->user_lastname : false,
369
  'EditUserLink' => add_query_arg( 'user_id', $user_id, admin_url( 'user-edit.php' ) ),
370
  ),
371
+ array( $this, 'must_not_contain_create_user' )
372
  );
373
  }
374
 
378
  * @param WSAL_AlertManager $mgr - Instance of Alert Manager.
379
  * @return bool
380
  */
381
+ public function must_not_contain_create_user( WSAL_AlertManager $mgr ) {
382
+ return ! $mgr->will_trigger( 4012 );
383
  }
384
  }
classes/Sensors/MultisiteSignUp.php CHANGED
@@ -28,7 +28,7 @@ class WSAL_Sensors_MultisiteSignUp extends WSAL_AbstractSensor {
28
  /**
29
  * {@inheritDoc}
30
  */
31
- public function HookEvents() {
32
  add_action( 'after_signup_user', array( $this, 'handle_multisite_user_signup' ), 10, 4 );
33
  add_action( 'wpmu_activate_user', array( $this, 'handle_multisite_user_activation' ), 10, 3 );
34
  }
@@ -60,7 +60,7 @@ class WSAL_Sensors_MultisiteSignUp extends WSAL_AbstractSensor {
60
  'EditUserLink' => add_query_arg( 'user_id', $user_id, admin_url( 'user-edit.php' ) ),
61
  );
62
 
63
- $this->plugin->alerts->TriggerIf( 4013, $event_data, array( $this, 'must_not_contain_create_user' ) );
64
  }
65
 
66
  /**
@@ -74,7 +74,7 @@ class WSAL_Sensors_MultisiteSignUp extends WSAL_AbstractSensor {
74
  * @param array $meta Signup meta data. Default empty array.
75
  */
76
  public function handle_multisite_user_signup( $user, $user_email, $key, $meta ) {
77
- $this->plugin->alerts->TriggerIf(
78
  4024,
79
  array(
80
  'username' => $user,
@@ -90,6 +90,6 @@ class WSAL_Sensors_MultisiteSignUp extends WSAL_AbstractSensor {
90
  * @param WSAL_AlertManager $manager - Instance of WSAL_AlertManager.
91
  */
92
  public function must_not_contain_create_user( WSAL_AlertManager $manager ) {
93
- return ! $manager->WillTrigger( 4012 );
94
  }
95
  }
28
  /**
29
  * {@inheritDoc}
30
  */
31
+ public function hook_events() {
32
  add_action( 'after_signup_user', array( $this, 'handle_multisite_user_signup' ), 10, 4 );
33
  add_action( 'wpmu_activate_user', array( $this, 'handle_multisite_user_activation' ), 10, 3 );
34
  }
60
  'EditUserLink' => add_query_arg( 'user_id', $user_id, admin_url( 'user-edit.php' ) ),
61
  );
62
 
63
+ $this->plugin->alerts->trigger_event_if( 4013, $event_data, array( $this, 'must_not_contain_create_user' ) );
64
  }
65
 
66
  /**
74
  * @param array $meta Signup meta data. Default empty array.
75
  */
76
  public function handle_multisite_user_signup( $user, $user_email, $key, $meta ) {
77
+ $this->plugin->alerts->trigger_event_if(
78
  4024,
79
  array(
80
  'username' => $user,
90
  * @param WSAL_AlertManager $manager - Instance of WSAL_AlertManager.
91
  */
92
  public function must_not_contain_create_user( WSAL_AlertManager $manager ) {
93
+ return ! $manager->will_trigger( 4012 );
94
  }
95
  }
classes/Sensors/PluginsThemes.php CHANGED
@@ -4,7 +4,7 @@
4
  *
5
  * Plugins & Themes sensor file.
6
  *
7
- * @since 1.0.0
8
  * @package wsal
9
  */
10
 
@@ -26,7 +26,7 @@ if ( ! defined( 'ABSPATH' ) ) {
26
  * 5007 User uninstalled a theme
27
  * 5031 User updated a theme
28
  *
29
- * @package wsal
30
  * @subpackage sensors
31
  */
32
  class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
@@ -48,30 +48,33 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
48
  /**
49
  * Listening to events using WP hooks.
50
  */
51
- public function HookEvents() {
52
  $has_permission = ( current_user_can( 'install_plugins' ) || current_user_can( 'activate_plugins' ) ||
53
- current_user_can( 'delete_plugins' ) || current_user_can( 'update_plugins' ) || current_user_can( 'install_themes' ) );
54
 
55
- add_action( 'admin_init', array( $this, 'EventAdminInit' ) );
56
  if ( $has_permission ) {
57
- add_action( 'shutdown', array( $this, 'EventAdminShutdown' ) );
58
  }
59
- add_action( 'switch_theme', array( $this, 'EventThemeActivated' ) );
60
- add_action( 'upgrader_overwrote_package', [ $this, 'OnPackageOverwrite' ], 10, 3 );
61
  }
62
 
63
  /**
64
  * Triggered when a user accesses the admin area.
65
  */
66
- public function EventAdminInit() {
67
  $this->old_themes = wp_get_themes();
68
  $this->old_plugins = get_plugins();
69
  }
70
 
71
  /**
72
  * Install, uninstall, activate, deactivate, upgrade and update.
 
 
 
73
  */
74
- public function EventAdminShutdown() {
75
  // Filter global arrays for security.
76
  $post_array = filter_input_array( INPUT_POST );
77
  $get_array = filter_input_array( INPUT_GET );
@@ -98,10 +101,10 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
98
  $is_plugins = 'plugins' === $actype;
99
 
100
  // Install plugin.
101
- if ( in_array( $action, array( 'install-plugin', 'upload-plugin', 'run_addon_install' ) ) && current_user_can( 'install_plugins' ) ) {
102
  $plugin = array_values( array_diff( array_keys( get_plugins() ), array_keys( $this->old_plugins ) ) );
103
  if ( count( $plugin ) != 1 ) {
104
- $this->LogError(
105
  'Expected exactly one new plugin but found ' . count( $plugin ),
106
  array(
107
  'NewPlugin' => $plugin,
@@ -116,10 +119,10 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
116
  $plugin = $plugin[ $plugin_path ];
117
 
118
  // Get plugin directory name.
119
- $plugin_dir = WSAL_Sensors_PluginsThemes::get_plugin_dir( $plugin_path );
120
 
121
  $plugin_path = plugin_dir_path( WP_PLUGIN_DIR . '/' . $plugin_path[0] );
122
- $this->plugin->alerts->Trigger(
123
  5000,
124
  array(
125
  'Plugin' => (object) array(
@@ -137,7 +140,7 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
137
  }
138
 
139
  // Activate plugin.
140
- if ( $is_plugins && in_array( $action, array( 'activate', 'activate-selected' ) ) && current_user_can( 'activate_plugins' ) ) {
141
  // Check $_GET array case.
142
  if ( isset( $get_array['plugin'] ) ) {
143
  if ( ! isset( $get_array['checked'] ) ) {
@@ -157,7 +160,7 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
157
  if ( isset( $get_array['checked'] ) && ! empty( $get_array['checked'] ) ) {
158
  $latest_event = $this->plugin->alerts->get_latest_events();
159
  $latest_event = isset( $latest_event[0] ) ? $latest_event[0] : false;
160
- $event_meta = $latest_event ? $latest_event->GetMetaArray() : false;
161
 
162
  foreach ( $get_array['checked'] as $plugin_file ) {
163
  if ( $latest_event && 5001 === $latest_event->alert_id && $event_meta && isset( $event_meta['PluginFile'] ) ) {
@@ -169,7 +172,7 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
169
  $plugin_file = WP_PLUGIN_DIR . '/' . $plugin_file;
170
  $plugin_data = get_plugin_data( $plugin_file, false, true );
171
 
172
- $this->plugin->alerts->Trigger(
173
  5001,
174
  array(
175
  'PluginFile' => $plugin_file,
@@ -190,7 +193,7 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
190
  $plugin_file = WP_PLUGIN_DIR . '/' . $plugin_file;
191
  $plugin_data = get_plugin_data( $plugin_file, false, true );
192
 
193
- $this->plugin->alerts->Trigger(
194
  5001,
195
  array(
196
  'PluginFile' => $plugin_file,
@@ -210,7 +213,7 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
210
  }
211
 
212
  // Deactivate plugin.
213
- if ( $is_plugins && in_array( $action, array( 'deactivate', 'deactivate-selected' ) ) && current_user_can( 'activate_plugins' ) ) {
214
  // Check $_GET array case.
215
  if ( isset( $get_array['plugin'] ) ) {
216
  if ( ! isset( $get_array['checked'] ) ) {
@@ -231,7 +234,7 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
231
  foreach ( $get_array['checked'] as $plugin_file ) {
232
  $plugin_file = WP_PLUGIN_DIR . '/' . $plugin_file;
233
  $plugin_data = get_plugin_data( $plugin_file, false, true );
234
- $this->plugin->alerts->Trigger(
235
  5002,
236
  array(
237
  'PluginFile' => $plugin_file,
@@ -244,13 +247,13 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
244
  ),
245
  )
246
  );
247
- WSAL_Sensors_PluginsThemes::run_addon_removal_check( $plugin_file );
248
  }
249
  } elseif ( isset( $post_array['checked'] ) && ! empty( $post_array['checked'] ) ) {
250
  foreach ( $post_array['checked'] as $plugin_file ) {
251
  $plugin_file = WP_PLUGIN_DIR . '/' . $plugin_file;
252
  $plugin_data = get_plugin_data( $plugin_file, false, true );
253
- $this->plugin->alerts->Trigger(
254
  5002,
255
  array(
256
  'PluginFile' => $plugin_file,
@@ -263,14 +266,14 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
263
  ),
264
  )
265
  );
266
- WSAL_Sensors_PluginsThemes::run_addon_removal_check( $plugin_file );
267
  }
268
  }
269
  }
270
 
271
  // Uninstall plugin.
272
- if ( $is_plugins && in_array( $action, array( 'delete-selected' ) ) && current_user_can( 'delete_plugins' ) ) {
273
- if ( ! isset( $post_array['verify-delete'] ) ) {
274
  // First step, before user approves deletion
275
  // TODO store plugin data in session here.
276
  } else {
@@ -282,7 +285,7 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
282
  $plugin_name = ucwords( $plugin_name );
283
  $plugin_file = WP_PLUGIN_DIR . '/' . $plugin_file;
284
  $plugin_data = get_plugin_data( $plugin_file, false, true );
285
- $this->plugin->alerts->Trigger(
286
  5003,
287
  array(
288
  'PluginFile' => $plugin_file,
@@ -292,20 +295,20 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
292
  ),
293
  )
294
  );
295
- WSAL_Sensors_PluginsThemes::run_addon_removal_check( $plugin_file );
296
  }
297
  }
298
  }
299
 
300
  // Uninstall plugin for WordPress version 4.6.
301
- if ( in_array( $action, array( 'delete-plugin' ) ) && current_user_can( 'delete_plugins' ) ) {
302
  if ( isset( $post_array['plugin'] ) ) {
303
  $plugin_file = WP_PLUGIN_DIR . '/' . $post_array['plugin'];
304
  $plugin_name = basename( $plugin_file, '.php' );
305
  $plugin_name = str_replace( array( '_', '-', ' ' ), ' ', $plugin_name );
306
  $plugin_name = ucwords( $plugin_name );
307
  $plugin_data = $this->old_plugins[ $post_array['plugin'] ];
308
- $this->plugin->alerts->Trigger(
309
  5003,
310
  array(
311
  'PluginFile' => $plugin_file,
@@ -316,12 +319,12 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
316
  )
317
  );
318
 
319
- WSAL_Sensors_PluginsThemes::run_addon_removal_check( $plugin_file );
320
  }
321
  }
322
 
323
  // Upgrade plugin.
324
- if ( in_array( $action, array( 'upgrade-plugin', 'update-plugin', 'update-selected' ) ) && current_user_can( 'update_plugins' ) ) {
325
  $plugins = array();
326
 
327
  // Check $_GET array cases.
@@ -339,13 +342,13 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
339
  }
340
  if ( isset( $plugins ) ) {
341
  foreach ( $plugins as $plugin_file ) {
342
- WSAL_Sensors_PluginsThemes::LogPluginUpdatedEvent( $plugin_file, $this->old_plugins );
343
  }
344
  }
345
  }
346
 
347
  // Update theme.
348
- if ( in_array( $action, array( 'upgrade-theme', 'update-theme', 'update-selected-themes' ) ) && current_user_can( 'install_themes' ) ) {
349
  // Themes.
350
  $themes = array();
351
 
@@ -362,18 +365,18 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
362
  } elseif ( isset( $post_array['themes'] ) ) {
363
  $themes = explode( ',', $post_array['themes'] );
364
  }
365
- if ( isset( $themes ) ) {
366
- foreach ( $themes as $theme_name ) {
367
- WSAL_Sensors_PluginsThemes::LogThemeUpdatedEvent( $theme_name );
368
- }
369
- }
370
  }
371
 
372
  // Install theme.
373
- if ( in_array( $action, array( 'install-theme', 'upload-theme' ) ) && current_user_can( 'install_themes' ) ) {
374
  $themes = array_diff( wp_get_themes(), $this->old_themes );
375
- foreach ( $themes as $name => $theme ) {
376
- $this->plugin->alerts->Trigger(
377
  5005,
378
  array(
379
  'Theme' => (object) array(
@@ -390,9 +393,9 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
390
  }
391
 
392
  // Uninstall theme.
393
- if ( in_array( $action, array( 'delete-theme' ) ) && current_user_can( 'install_themes' ) ) {
394
- foreach ( $this->GetRemovedThemes() as $index => $theme ) {
395
- $this->plugin->alerts->Trigger(
396
  5007,
397
  array(
398
  'Theme' => (object) array(
@@ -413,17 +416,19 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
413
  * Activated a theme.
414
  *
415
  * @param string $theme_name - Theme name.
 
 
416
  */
417
- public function EventThemeActivated( $theme_name ) {
418
  $theme = null;
419
  foreach ( wp_get_themes() as $item ) {
420
- if ( $theme_name == $item->Name ) {
421
  $theme = $item;
422
  break;
423
  }
424
  }
425
- if ( null == $theme ) {
426
- $this->LogError(
427
  'Could not locate theme named "' . $theme . '".',
428
  array(
429
  'ThemeName' => $theme_name,
@@ -432,7 +437,7 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
432
  );
433
  return;
434
  }
435
- $this->plugin->alerts->Trigger(
436
  5006,
437
  array(
438
  'Theme' => (object) array(
@@ -452,7 +457,7 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
452
  *
453
  * @return array of WP_Theme objects
454
  */
455
- protected function GetRemovedThemes() {
456
  $result = $this->old_themes;
457
  foreach ( $result as $i => $theme ) {
458
  if ( file_exists( $theme->get_template_directory() ) ) {
@@ -465,14 +470,14 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
465
  /**
466
  * Get event code by post type.
467
  *
468
- * @param object $post - Post object.
469
- * @param int $type_post - Code for post.
470
- * @param int $type_page - Code for page.
471
- * @param int $type_custom - Code for custom post type.
472
  *
473
  * @return false|int
474
  */
475
- protected function GetEventTypeForPostType( $post, $type_post, $type_page, $type_custom ) {
476
  if ( empty( $post ) || ! isset( $post->post_type ) ) {
477
  return false;
478
  }
@@ -552,7 +557,7 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
552
  $theme = null;
553
  if ( ! empty( $all_themes ) ) {
554
  foreach ( $all_themes as $theme_slug => $theme_obj ) {
555
- if ( $theme_name === $theme_slug|| $theme_name === $theme_obj->get('Name') ) {
556
  $theme = $theme_obj;
557
  break;
558
  }
@@ -561,6 +566,11 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
561
  return $theme;
562
  }
563
 
 
 
 
 
 
564
  public function run_addon_check( $plugin_dir ) {
565
  $plugin_filename = basename( preg_replace( '/\\.[^.\\s]{3,4}$/', '', $plugin_dir ) );
566
 
@@ -578,25 +588,30 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
578
 
579
  // Check if plugin file starts with the same string as our addon_for, or if its equal.
580
  if ( $plugin_filename === $plugin ) {
581
- $addon_slug = array( array_search( $plugin, array_column( $predefined_plugins, 'addon_for', 'plugin_slug' ) ) );
582
  $is_addon_installed = array_intersect( $all_plugins, $addon_slug );
583
  if ( empty( $is_addon_installed ) ) {
584
- $current_value = $this->plugin->GetGlobalSetting( 'installed_plugin_addon_available' );
585
  $plugin_filename = array( $plugin_filename );
586
  if ( isset( $current_value ) && is_array( $current_value ) ) {
587
  $new_plugin_filenames = array_unique( array_merge( $current_value, $plugin_filename ) );
588
  } else {
589
  $new_plugin_filenames = $plugin_filename;
590
  }
591
- $this->plugin->SetGlobalSetting( 'installed_plugin_addon_available', $new_plugin_filenames );
592
- $this->plugin->DeleteGlobalSetting( 'addon_available_notice_dismissed' );
593
  }
594
  }
595
  }
596
  }
597
 
 
 
 
 
 
598
  public static function run_addon_removal_check( $plugin_dir ) {
599
- $wsal = WpSecurityAuditLog::GetInstance();
600
  $plugin_filename = basename( preg_replace( '/\\.[^.\\s]{3,4}$/', '', $plugin_dir ) );
601
 
602
  if ( is_array( $plugin_filename ) ) {
@@ -612,14 +627,15 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
612
 
613
  // Check if plugin file starts with the same string as our addon_for, or if its equal.
614
  if ( $plugin_filename === $plugin ) {
615
- $current_installed = $wsal->GetGlobalSetting( 'installed_plugin_addon_available' );
616
- if ( isset( $current_installed ) && ! empty( $current_installed ) ) {
617
- if ( ( $key = array_search( $plugin, $current_installed ) ) !== false ) {
618
- unset( $current_installed[$key] );
 
619
  }
620
  }
621
 
622
- $wsal->SetGlobalSetting( 'installed_plugin_addon_available', $current_installed );
623
  }
624
  }
625
  }
@@ -630,9 +646,9 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
630
  *
631
  * @since 4.1.4
632
  *
633
- * @param string $package The package file.
634
- * @param array $new_plugin_data The new plugin data.
635
- * @param string $package_type The package type (plugin or theme).
636
  */
637
  public function OnPackageOverwrite( $package, $new_plugin_data, $package_type ) {
638
  if ( 'plugin' !== $package_type ) {
@@ -640,9 +656,9 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
640
  }
641
 
642
  if ( array_key_exists( 'Name', $new_plugin_data ) ) {
643
- $plugin_file = WSAL_Sensors_PluginsThemes::get_plugin_file_name( $new_plugin_data['Name'] );
644
  if ( ! empty( $plugin_file ) ) {
645
- WSAL_Sensors_PluginsThemes::LogPluginUpdatedEvent( $plugin_file );
646
  }
647
  }
648
  }
@@ -655,7 +671,7 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
655
  *
656
  * @since 4.1.4
657
  */
658
- public static function LogPluginUpdatedEvent( $plugin_file, $old_plugins = '' ) {
659
  $plugin_file_full = WP_PLUGIN_DIR . '/' . $plugin_file;
660
  $plugin_data = get_plugin_data( $plugin_file_full, false, true );
661
 
@@ -663,8 +679,8 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
663
  $new_version = $plugin_data['Version'];
664
 
665
  if ( $old_version !== $new_version ) {
666
- $wsal = WpSecurityAuditLog::GetInstance();
667
- $wsal->alerts->Trigger(
668
  5004,
669
  array(
670
  'PluginFile' => $plugin_file,
@@ -680,32 +696,34 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
680
  }
681
  }
682
 
683
- /**
684
- * Log theme updated event.
685
- *
686
- * @param string $theme_name Theme name.
687
- *
688
- * @since 4.1.5
689
- */
690
- public static function LogThemeUpdatedEvent( $theme_name ) {
691
- $theme = WSAL_Sensors_PluginsThemes::get_theme_by_name($theme_name);
692
- if ( ! $theme instanceof WP_Theme ) {
693
- return;
694
- }
695
-
696
- $wsal = WpSecurityAuditLog::GetInstance();
697
- $wsal->alerts->Trigger(
698
- 5031,
699
- array(
700
- 'Theme' => (object) array(
701
- 'Name' => $theme->Name,
702
- 'ThemeURI' => $theme->ThemeURI,
703
- 'Description' => $theme->Description,
704
- 'Author' => $theme->Author,
705
- 'Version' => $theme->Version,
706
- 'get_template_directory' => $theme->get_template_directory(),
707
- ),
708
- )
709
- );
710
- }
 
 
711
  }
4
  *
5
  * Plugins & Themes sensor file.
6
  *
7
+ * @since 1.0.0
8
  * @package wsal
9
  */
10
 
26
  * 5007 User uninstalled a theme
27
  * 5031 User updated a theme
28
  *
29
+ * @package wsal
30
  * @subpackage sensors
31
  */
32
  class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
48
  /**
49
  * Listening to events using WP hooks.
50
  */
51
+ public function hook_events() {
52
  $has_permission = ( current_user_can( 'install_plugins' ) || current_user_can( 'activate_plugins' ) ||
53
+ current_user_can( 'delete_plugins' ) || current_user_can( 'update_plugins' ) || current_user_can( 'install_themes' ) );
54
 
55
+ add_action( 'admin_init', array( $this, 'event_admin_init' ) );
56
  if ( $has_permission ) {
57
+ add_action( 'shutdown', array( $this, 'event_admin_shutdown' ) );
58
  }
59
+ add_action( 'switch_theme', array( $this, 'event_theme_activated' ) );
60
+ add_action( 'upgrader_overwrote_package', array( $this, 'OnPackageOverwrite' ), 10, 3 );
61
  }
62
 
63
  /**
64
  * Triggered when a user accesses the admin area.
65
  */
66
+ public function event_admin_init() {
67
  $this->old_themes = wp_get_themes();
68
  $this->old_plugins = get_plugins();
69
  }
70
 
71
  /**
72
  * Install, uninstall, activate, deactivate, upgrade and update.
73
+ *
74
+ * phpcs:disable WordPress.PHP.StrictComparisons.LooseComparison
75
+ * phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
76
  */
77
+ public function event_admin_shutdown() {
78
  // Filter global arrays for security.
79
  $post_array = filter_input_array( INPUT_POST );
80
  $get_array = filter_input_array( INPUT_GET );
101
  $is_plugins = 'plugins' === $actype;
102
 
103
  // Install plugin.
104
+ if ( in_array( $action, array( 'install-plugin', 'upload-plugin', 'run_addon_install' ), true ) && current_user_can( 'install_plugins' ) ) {
105
  $plugin = array_values( array_diff( array_keys( get_plugins() ), array_keys( $this->old_plugins ) ) );
106
  if ( count( $plugin ) != 1 ) {
107
+ $this->log_error(
108
  'Expected exactly one new plugin but found ' . count( $plugin ),
109
  array(
110
  'NewPlugin' => $plugin,
119
  $plugin = $plugin[ $plugin_path ];
120
 
121
  // Get plugin directory name.
122
+ $plugin_dir = self::get_plugin_dir( $plugin_path );
123
 
124
  $plugin_path = plugin_dir_path( WP_PLUGIN_DIR . '/' . $plugin_path[0] );
125
+ $this->plugin->alerts->trigger_event(
126
  5000,
127
  array(
128
  'Plugin' => (object) array(
140
  }
141
 
142
  // Activate plugin.
143
+ if ( $is_plugins && in_array( $action, array( 'activate', 'activate-selected' ), true ) && current_user_can( 'activate_plugins' ) ) {
144
  // Check $_GET array case.
145
  if ( isset( $get_array['plugin'] ) ) {
146
  if ( ! isset( $get_array['checked'] ) ) {
160
  if ( isset( $get_array['checked'] ) && ! empty( $get_array['checked'] ) ) {
161
  $latest_event = $this->plugin->alerts->get_latest_events();
162
  $latest_event = isset( $latest_event[0] ) ? $latest_event[0] : false;
163
+ $event_meta = $latest_event ? $latest_event->get_meta_array() : false;
164
 
165
  foreach ( $get_array['checked'] as $plugin_file ) {
166
  if ( $latest_event && 5001 === $latest_event->alert_id && $event_meta && isset( $event_meta['PluginFile'] ) ) {
172
  $plugin_file = WP_PLUGIN_DIR . '/' . $plugin_file;
173
  $plugin_data = get_plugin_data( $plugin_file, false, true );
174
 
175
+ $this->plugin->alerts->trigger_event(
176
  5001,
177
  array(
178
  'PluginFile' => $plugin_file,
193
  $plugin_file = WP_PLUGIN_DIR . '/' . $plugin_file;
194
  $plugin_data = get_plugin_data( $plugin_file, false, true );
195
 
196
+ $this->plugin->alerts->trigger_event(
197
  5001,
198
  array(
199
  'PluginFile' => $plugin_file,
213
  }
214
 
215
  // Deactivate plugin.
216
+ if ( $is_plugins && in_array( $action, array( 'deactivate', 'deactivate-selected' ), true ) && current_user_can( 'activate_plugins' ) ) {
217
  // Check $_GET array case.
218
  if ( isset( $get_array['plugin'] ) ) {
219
  if ( ! isset( $get_array['checked'] ) ) {
234
  foreach ( $get_array['checked'] as $plugin_file ) {
235
  $plugin_file = WP_PLUGIN_DIR . '/' . $plugin_file;
236
  $plugin_data = get_plugin_data( $plugin_file, false, true );
237
+ $this->plugin->alerts->trigger_event(
238
  5002,
239
  array(
240
  'PluginFile' => $plugin_file,
247
  ),
248
  )
249
  );
250
+ self::run_addon_removal_check( $plugin_file );
251
  }
252
  } elseif ( isset( $post_array['checked'] ) && ! empty( $post_array['checked'] ) ) {
253
  foreach ( $post_array['checked'] as $plugin_file ) {
254
  $plugin_file = WP_PLUGIN_DIR . '/' . $plugin_file;
255
  $plugin_data = get_plugin_data( $plugin_file, false, true );
256
+ $this->plugin->alerts->trigger_event(
257
  5002,
258
  array(
259
  'PluginFile' => $plugin_file,
266
  ),
267
  )
268
  );
269
+ self::run_addon_removal_check( $plugin_file );
270
  }
271
  }
272
  }
273
 
274
  // Uninstall plugin.
275
+ if ( $is_plugins && in_array( $action, array( 'delete-selected' ), true ) && current_user_can( 'delete_plugins' ) ) {
276
+ if ( ! isset( $post_array['verify-delete'] ) ) { // phpcs:ignore
277
  // First step, before user approves deletion
278
  // TODO store plugin data in session here.
279
  } else {
285
  $plugin_name = ucwords( $plugin_name );
286
  $plugin_file = WP_PLUGIN_DIR . '/' . $plugin_file;
287
  $plugin_data = get_plugin_data( $plugin_file, false, true );
288
+ $this->plugin->alerts->trigger_event(
289
  5003,
290
  array(
291
  'PluginFile' => $plugin_file,
295
  ),
296
  )
297
  );
298
+ self::run_addon_removal_check( $plugin_file );
299
  }
300
  }
301
  }
302
 
303
  // Uninstall plugin for WordPress version 4.6.
304
+ if ( in_array( $action, array( 'delete-plugin' ), true ) && current_user_can( 'delete_plugins' ) ) {
305
  if ( isset( $post_array['plugin'] ) ) {
306
  $plugin_file = WP_PLUGIN_DIR . '/' . $post_array['plugin'];
307
  $plugin_name = basename( $plugin_file, '.php' );
308
  $plugin_name = str_replace( array( '_', '-', ' ' ), ' ', $plugin_name );
309
  $plugin_name = ucwords( $plugin_name );
310
  $plugin_data = $this->old_plugins[ $post_array['plugin'] ];
311
+ $this->plugin->alerts->trigger_event(
312
  5003,
313
  array(
314
  'PluginFile' => $plugin_file,
319
  )
320
  );
321
 
322
+ self::run_addon_removal_check( $plugin_file );
323
  }
324
  }
325
 
326
  // Upgrade plugin.
327
+ if ( in_array( $action, array( 'upgrade-plugin', 'update-plugin', 'update-selected' ), true ) && current_user_can( 'update_plugins' ) ) {
328
  $plugins = array();
329
 
330
  // Check $_GET array cases.
342
  }
343
  if ( isset( $plugins ) ) {
344
  foreach ( $plugins as $plugin_file ) {
345
+ self::log_plugin_updated_event( $plugin_file, $this->old_plugins );
346
  }
347
  }
348
  }
349
 
350
  // Update theme.
351
+ if ( in_array( $action, array( 'upgrade-theme', 'update-theme', 'update-selected-themes' ), true ) && current_user_can( 'install_themes' ) ) {
352
  // Themes.
353
  $themes = array();
354
 
365
  } elseif ( isset( $post_array['themes'] ) ) {
366
  $themes = explode( ',', $post_array['themes'] );
367
  }
368
+ if ( isset( $themes ) ) {
369
+ foreach ( $themes as $theme_name ) {
370
+ self::log_theme_updated_event( $theme_name );
371
+ }
372
+ }
373
  }
374
 
375
  // Install theme.
376
+ if ( in_array( $action, array( 'install-theme', 'upload-theme' ), true ) && current_user_can( 'install_themes' ) ) {
377
  $themes = array_diff( wp_get_themes(), $this->old_themes );
378
+ foreach ( $themes as $theme ) {
379
+ $this->plugin->alerts->trigger_event(
380
  5005,
381
  array(
382
  'Theme' => (object) array(
393
  }
394
 
395
  // Uninstall theme.
396
+ if ( in_array( $action, array( 'delete-theme' ), true ) && current_user_can( 'install_themes' ) ) {
397
+ foreach ( $this->get_removed_themes() as $theme ) {
398
+ $this->plugin->alerts->trigger_event(
399
  5007,
400
  array(
401
  'Theme' => (object) array(
416
  * Activated a theme.
417
  *
418
  * @param string $theme_name - Theme name.
419
+ *
420
+ * phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
421
  */
422
+ public function event_theme_activated( $theme_name ) {
423
  $theme = null;
424
  foreach ( wp_get_themes() as $item ) {
425
+ if ( $theme_name === $item->Name ) {
426
  $theme = $item;
427
  break;
428
  }
429
  }
430
+ if ( null == $theme ) { // phpcs:ignore
431
+ $this->log_error(
432
  'Could not locate theme named "' . $theme . '".',
433
  array(
434
  'ThemeName' => $theme_name,
437
  );
438
  return;
439
  }
440
+ $this->plugin->alerts->trigger_event(
441
  5006,
442
  array(
443
  'Theme' => (object) array(
457
  *
458
  * @return array of WP_Theme objects
459
  */
460
+ protected function get_removed_themes() {
461
  $result = $this->old_themes;
462
  foreach ( $result as $i => $theme ) {
463
  if ( file_exists( $theme->get_template_directory() ) ) {
470
  /**
471
  * Get event code by post type.
472
  *
473
+ * @param object $post - Post object.
474
+ * @param int $type_post - Code for post.
475
+ * @param int $type_page - Code for page.
476
+ * @param int $type_custom - Code for custom post type.
477
  *
478
  * @return false|int
479
  */
480
+ protected function get_event_type_for_post_type( $post, $type_post, $type_page, $type_custom ) {
481
  if ( empty( $post ) || ! isset( $post->post_type ) ) {
482
  return false;
483
  }
557
  $theme = null;
558
  if ( ! empty( $all_themes ) ) {
559
  foreach ( $all_themes as $theme_slug => $theme_obj ) {
560
+ if ( $theme_name === $theme_slug || $theme_name === $theme_obj->get( 'Name' ) ) {
561
  $theme = $theme_obj;
562
  break;
563
  }
566
  return $theme;
567
  }
568
 
569
+ /**
570
+ * Runs an add-on check.
571
+ *
572
+ * @param string $plugin_dir Plugin directory.
573
+ */
574
  public function run_addon_check( $plugin_dir ) {
575
  $plugin_filename = basename( preg_replace( '/\\.[^.\\s]{3,4}$/', '', $plugin_dir ) );
576
 
588
 
589
  // Check if plugin file starts with the same string as our addon_for, or if its equal.
590
  if ( $plugin_filename === $plugin ) {
591
+ $addon_slug = array( array_search( $plugin, array_column( $predefined_plugins, 'addon_for', 'plugin_slug' ) ) ); // phpcs:ignore
592
  $is_addon_installed = array_intersect( $all_plugins, $addon_slug );
593
  if ( empty( $is_addon_installed ) ) {
594
+ $current_value = $this->plugin->get_global_setting( 'installed_plugin_addon_available' );
595
  $plugin_filename = array( $plugin_filename );
596
  if ( isset( $current_value ) && is_array( $current_value ) ) {
597
  $new_plugin_filenames = array_unique( array_merge( $current_value, $plugin_filename ) );
598
  } else {
599
  $new_plugin_filenames = $plugin_filename;
600
  }
601
+ $this->plugin->set_global_setting( 'installed_plugin_addon_available', $new_plugin_filenames );
602
+ $this->plugin->delete_global_setting( 'addon_available_notice_dismissed' );
603
  }
604
  }
605
  }
606
  }
607
 
608
+ /**
609
+ * Checks for an add-on removal.
610
+ *
611
+ * @param string $plugin_dir Plugin directory.
612
+ */
613
  public static function run_addon_removal_check( $plugin_dir ) {
614
+ $wsal = WpSecurityAuditLog::get_instance();
615
  $plugin_filename = basename( preg_replace( '/\\.[^.\\s]{3,4}$/', '', $plugin_dir ) );
616
 
617
  if ( is_array( $plugin_filename ) ) {
627
 
628
  // Check if plugin file starts with the same string as our addon_for, or if its equal.
629
  if ( $plugin_filename === $plugin ) {
630
+ $current_installed = $wsal->get_global_setting( 'installed_plugin_addon_available' );
631
+ if ( isset( $current_installed ) && ! empty( $current_installed ) ) {
632
+ $key = array_search( $plugin, $current_installed ); // phpcs:ignore
633
+ if ( false !== $key ) {
634
+ unset( $current_installed[ $key ] );
635
  }
636
  }
637
 
638
+ $wsal->set_global_setting( 'installed_plugin_addon_available', $current_installed );
639
  }
640
  }
641
  }
646
  *
647
  * @since 4.1.4
648
  *
649
+ * @param string $package The package file.
650
+ * @param array $new_plugin_data The new plugin data.
651
+ * @param string $package_type The package type (plugin or theme).
652
  */
653
  public function OnPackageOverwrite( $package, $new_plugin_data, $package_type ) {
654
  if ( 'plugin' !== $package_type ) {
656
  }
657
 
658
  if ( array_key_exists( 'Name', $new_plugin_data ) ) {
659
+ $plugin_file = self::get_plugin_file_name( $new_plugin_data['Name'] );
660
  if ( ! empty( $plugin_file ) ) {
661
+ self::log_plugin_updated_event( $plugin_file );
662
  }
663
  }
664
  }
671
  *
672
  * @since 4.1.4
673
  */
674
+ public static function log_plugin_updated_event( $plugin_file, $old_plugins = '' ) {
675
  $plugin_file_full = WP_PLUGIN_DIR . '/' . $plugin_file;
676
  $plugin_data = get_plugin_data( $plugin_file_full, false, true );
677
 
679
  $new_version = $plugin_data['Version'];
680
 
681
  if ( $old_version !== $new_version ) {
682
+ $wsal = WpSecurityAuditLog::get_instance();
683
+ $wsal->alerts->trigger_event(
684
  5004,
685
  array(
686
  'PluginFile' => $plugin_file,
696
  }
697
  }
698
 
699
+ /**
700
+ * Log theme updated event.
701
+ *
702
+ * @param string $theme_name Theme name.
703
+ *
704
+ * @since 4.1.5
705
+ *
706
+ * phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
707
+ */
708
+ public static function log_theme_updated_event( $theme_name ) {
709
+ $theme = self::get_theme_by_name( $theme_name );
710
+ if ( ! $theme instanceof WP_Theme ) {
711
+ return;
712
+ }
713
+
714
+ $wsal = WpSecurityAuditLog::get_instance();
715
+ $wsal->alerts->trigger_event(
716
+ 5031,
717
+ array(
718
+ 'Theme' => (object) array(
719
+ 'Name' => $theme->Name,
720
+ 'ThemeURI' => $theme->ThemeURI,
721
+ 'Description' => $theme->Description,
722
+ 'Author' => $theme->Author,
723
+ 'Version' => $theme->Version,
724
+ 'get_template_directory' => $theme->get_template_directory(),
725
+ ),
726
+ )
727
+ );
728
+ }
729
  }
classes/Sensors/Register.php CHANGED
@@ -22,7 +22,7 @@ class WSAL_Sensors_Register extends WSAL_AbstractSensor {
22
  /**
23
  * {@inheritDoc}
24
  */
25
- public function HookEvents() {
26
  /*
27
  * Default WordPress registration utilizes action 'register_new_user', but we cannot rely on it to detect
28
  * a front-end registration implemented by a third party. We hook into the action 'user_register' because it is
@@ -60,9 +60,9 @@ class WSAL_Sensors_Register extends WSAL_AbstractSensor {
60
  'EditUserLink' => add_query_arg( 'user_id', $user_id, admin_url( 'user-edit.php' ) ),
61
  );
62
 
63
- if ( $this->IsMultisite() ) {
64
  // Registration should not be logged on multisite if event 4024 is fired.
65
- $this->plugin->alerts->TriggerIf(
66
  4000,
67
  $event_data,
68
  /**
@@ -71,11 +71,11 @@ class WSAL_Sensors_Register extends WSAL_AbstractSensor {
71
  * @param WSAL_AlertManager $mgr - Instance of WSAL_AlertManager.
72
  */
73
  function ( WSAL_AlertManager $mgr ) {
74
- return ! $mgr->WillTrigger( 4013 );
75
  }
76
  );
77
  } else {
78
- $this->plugin->alerts->Trigger( 4000, $event_data, true );
79
  }
80
 
81
  }
22
  /**
23
  * {@inheritDoc}
24
  */
25
+ public function hook_events() {
26
  /*
27
  * Default WordPress registration utilizes action 'register_new_user', but we cannot rely on it to detect
28
  * a front-end registration implemented by a third party. We hook into the action 'user_register' because it is
60
  'EditUserLink' => add_query_arg( 'user_id', $user_id, admin_url( 'user-edit.php' ) ),
61
  );
62
 
63
+ if ( $this->is_multisite() ) {
64
  // Registration should not be logged on multisite if event 4024 is fired.
65
+ $this->plugin->alerts->trigger_event_if(
66
  4000,
67
  $event_data,
68
  /**
71
  * @param WSAL_AlertManager $mgr - Instance of WSAL_AlertManager.
72
  */
73
  function ( WSAL_AlertManager $mgr ) {
74
+ return ! $mgr->will_trigger( 4013 );
75
  }
76
  );
77
  } else {
78
+ $this->plugin->alerts->trigger_event( 4000, $event_data, true );
79
  }
80
 
81
  }
classes/Sensors/System.php CHANGED
@@ -4,8 +4,9 @@
4
  *
5
  * System activity sensor class file.
6
  *
7
- * @since 1.0.0
8
- * @package wsal
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -40,21 +41,21 @@ if ( ! defined( 'ABSPATH' ) ) {
40
  * 6017 Modified the list of keywords for comments moderation
41
  * 6018 Modified the list of keywords for comments blacklisting
42
  *
43
- * @package wsal
44
  * @subpackage sensors
45
  */
46
  class WSAL_Sensors_System extends WSAL_AbstractSensor {
47
 
48
  /**
49
- * Listening to events using WP hooks.
50
  */
51
- public function HookEvents() {
52
- add_action( 'wsal_prune', array( $this, 'EventPruneEvents' ), 10, 2 );
53
- add_action( 'admin_init', array( $this, 'EventAdminInit' ) );
54
- add_action( 'automatic_updates_complete', array( $this, 'WPUpdate' ), 10, 1 );
55
 
56
  // whitelist options.
57
- add_action( 'allowed_options', array( $this, 'EventOptions' ), 10, 1 );
58
 
59
  // Update admin email alert.
60
  add_action( 'update_option_admin_email', array( $this, 'admin_email_changed' ), 10, 3 );
@@ -72,8 +73,8 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
72
  // Check if the option is not empty and is admin_email.
73
  if ( ! empty( $old_value ) && ! empty( $new_value )
74
  && ! empty( $option ) && 'admin_email' === $option ) {
75
- if ( $old_value != $new_value ) {
76
- $this->plugin->alerts->Trigger(
77
  6003,
78
  array(
79
  'OldEmail' => $old_value,
@@ -91,8 +92,8 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
91
  * @param int $count The number of deleted events.
92
  * @param string $query Query that selected events for deletion.
93
  */
94
- public function EventPruneEvents( $count, $query ) {
95
- $this->plugin->alerts->Trigger(
96
  6000,
97
  array(
98
  'EventCount' => $count,
@@ -103,8 +104,11 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
103
 
104
  /**
105
  * Triggered when a user accesses the admin area.
 
 
 
106
  */
107
- public function EventAdminInit() {
108
  // Filter global arrays for security.
109
  $post_array = filter_input_array( INPUT_POST );
110
  $get_array = filter_input_array( INPUT_GET );
@@ -112,7 +116,7 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
112
 
113
  // Destroy all the session of the same user from user profile page.
114
  if ( isset( $post_array['action'] ) && ( 'destroy-sessions' == $post_array['action'] ) && isset( $post_array['user_id'] ) ) {
115
- $this->plugin->alerts->Trigger(
116
  1006,
117
  array(
118
  'TargetUserID' => $post_array['user_id'],
@@ -130,22 +134,22 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
130
  $actype = basename( $server_array['SCRIPT_NAME'], '.php' );
131
  }
132
 
133
- if ( isset( $post_array['action'] ) && 'toggle-auto-updates' == $post_array['action'] ) {
134
  $event_id = ( 'theme' == $post_array['type'] ) ? 5029 : 5028;
135
 
136
  if ( 'theme' == $post_array['type'] ) {
137
  $all_themes = wp_get_themes();
138
- $our_theme = $all_themes[$post_array['asset']];
139
  $install_location = $our_theme->get_template_directory();
140
  $name = $our_theme->Name;
141
- } else if ( 'plugin' == $post_array['type'] ) {
142
  $all_plugins = get_plugins();
143
- $our_plugin = $all_plugins[$post_array['asset']];
144
  $install_location = plugin_dir_path( WP_PLUGIN_DIR . '/' . $post_array['asset'] );
145
  $name = $our_plugin['Name'];
146
  }
147
 
148
- $this->plugin->alerts->Trigger(
149
  $event_id,
150
  array(
151
  'install_directory' => $install_location,
@@ -166,7 +170,7 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
166
  $old_siteurl = get_option( 'siteurl' );
167
  $new_siteurl = isset( $post_array['siteurl'] ) ? $post_array['siteurl'] : '';
168
  if ( $old_siteurl !== $new_siteurl ) {
169
- $this->plugin->alerts->Trigger(
170
  6024,
171
  array(
172
  'old_url' => $old_siteurl,
@@ -184,7 +188,7 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
184
  $old_url = get_option( 'home' );
185
  $new_url = isset( $post_array['home'] ) ? $post_array['home'] : '';
186
  if ( $old_url !== $new_url ) {
187
- $this->plugin->alerts->Trigger(
188
  6025,
189
  array(
190
  'old_url' => $old_url,
@@ -197,10 +201,10 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
197
 
198
  if ( isset( $post_array['option_page'] ) && 'reading' === $post_array['option_page'] && isset( $post_array['show_on_front'] )
199
  && wp_verify_nonce( $post_array['_wpnonce'], 'reading-options' ) ) {
200
- $old_homepage = ( 'posts' === get_site_option( 'show_on_front' ) ) ? __( 'latest posts', 'wp-security-audit-log' ) :__( 'static page', 'wp-security-audit-log' );
201
- $new_homepage = ( 'posts' === $post_array['show_on_front'] ) ? __( 'latest posts', 'wp-security-audit-log' ) :__( 'static page', 'wp-security-audit-log' );
202
  if ( $old_homepage != $new_homepage ) {
203
- $this->plugin->alerts->Trigger(
204
  6035,
205
  array(
206
  'old_homepage' => $old_homepage,
@@ -212,10 +216,10 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
212
 
213
  if ( isset( $post_array['option_page'] ) && 'reading' === $post_array['option_page'] && isset( $post_array['page_on_front'] )
214
  && wp_verify_nonce( $post_array['_wpnonce'], 'reading-options' ) ) {
215
- $old_frontpage = get_the_title( get_site_option( 'page_on_front' ) ) ;
216
- $new_frontpage = get_the_title( $post_array[ 'page_on_front' ] );
217
  if ( $old_frontpage != $new_frontpage ) {
218
- $this->plugin->alerts->Trigger(
219
  6036,
220
  array(
221
  'old_page' => $old_frontpage,
@@ -228,9 +232,9 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
228
  if ( isset( $post_array['option_page'] ) && 'reading' === $post_array['option_page'] && isset( $post_array['page_for_posts'] )
229
  && wp_verify_nonce( $post_array['_wpnonce'], 'reading-options' ) ) {
230
  $old_postspage = get_the_title( get_site_option( 'page_for_posts' ) );
231
- $new_postspage = get_the_title( $post_array[ 'page_for_posts' ] );
232
  if ( $old_postspage != $new_postspage ) {
233
- $this->plugin->alerts->Trigger(
234
  6037,
235
  array(
236
  'old_page' => $old_postspage,
@@ -240,17 +244,17 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
240
  }
241
  }
242
 
243
- // check timezone change
244
  if ( $is_option_page && wp_verify_nonce( $post_array['_wpnonce'], 'general-options' ) && ! empty( $post_array['timezone_string'] ) ) {
245
  $this->check_timezone_change( $post_array );
246
  }
247
 
248
- // check date format change
249
  if ( $is_option_page && wp_verify_nonce( $post_array['_wpnonce'], 'general-options' ) && ! empty( $post_array['date_format'] ) ) {
250
  $old_date_format = get_option( 'date_format' );
251
  $new_date_format = ( '\c\u\s\t\o\m' === $post_array['date_format'] ) ? $post_array['date_format_custom'] : $post_array['date_format'];
252
  if ( $old_date_format !== $new_date_format ) {
253
- $this->plugin->alerts->Trigger(
254
  6041,
255
  array(
256
  'old_date_format' => $old_date_format,
@@ -261,12 +265,12 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
261
  }
262
  }
263
 
264
- // check time format change
265
  if ( $is_option_page && wp_verify_nonce( $post_array['_wpnonce'], 'general-options' ) && ! empty( $post_array['time_format'] ) ) {
266
- $old_time_format = get_option( 'time_format' );
267
  $new_time_format = ( '\c\u\s\t\o\m' === $post_array['time_format'] ) ? $post_array['time_format_custom'] : $post_array['time_format'];
268
  if ( $old_time_format !== $new_time_format ) {
269
- $this->plugin->alerts->Trigger(
270
  6042,
271
  array(
272
  'old_time_format' => $old_time_format,
@@ -283,7 +287,7 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
283
  $new = isset( $post_array['users_can_register'] ) ? 'enabled' : 'disabled';
284
 
285
  if ( $old !== $new ) {
286
- $this->plugin->alerts->Trigger(
287
  6001,
288
  array(
289
  'EventType' => $new,
@@ -298,7 +302,7 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
298
  $old = get_option( 'default_role' );
299
  $new = trim( $post_array['default_role'] );
300
  if ( $old != $new ) {
301
- $this->plugin->alerts->Trigger(
302
  6002,
303
  array(
304
  'OldRole' => $old,
@@ -314,7 +318,7 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
314
  $old = get_option( 'admin_email' );
315
  $new = trim( $post_array['admin_email'] );
316
  if ( $old != $new ) {
317
- $this->plugin->alerts->Trigger(
318
  6003,
319
  array(
320
  'OldEmail' => $old,
@@ -330,7 +334,7 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
330
  $old = get_site_option( 'admin_email' );
331
  $new = trim( $post_array['new_admin_email'] );
332
  if ( $old != $new ) {
333
- $this->plugin->alerts->Trigger(
334
  6003,
335
  array(
336
  'OldEmail' => $old,
@@ -343,11 +347,11 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
343
 
344
  // Permalinks changed.
345
  if ( $is_permalink_page && ! empty( $post_array['permalink_structure'] )
346
- && wp_verify_nonce( $post_array['_wpnonce'], 'update-permalink' )) {
347
  $old = get_option( 'permalink_structure' );
348
  $new = trim( $post_array['permalink_structure'] );
349
  if ( $old != $new ) {
350
- $this->plugin->alerts->Trigger(
351
  6005,
352
  array(
353
  'OldPattern' => $old,
@@ -360,11 +364,11 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
360
 
361
  // Core Update.
362
  if ( isset( $get_array['action'] ) && 'do-core-upgrade' === $get_array['action'] && isset( $post_array['version'] )
363
- && wp_verify_nonce( $post_array['_wpnonce'], 'upgrade-core' )) {
364
  $old_version = get_bloginfo( 'version' );
365
  $new_version = $post_array['version'];
366
  if ( $old_version != $new_version ) {
367
- $this->plugin->alerts->Trigger(
368
  6004,
369
  array(
370
  'OldVersion' => $old_version,
@@ -377,8 +381,8 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
377
  // Enable core updates.
378
  if ( isset( $get_array['action'] ) && 'core-major-auto-updates-settings' === $get_array['action'] && isset( $get_array['value'] )
379
  && wp_verify_nonce( $get_array['_wpnonce'], 'core-major-auto-updates-nonce' ) ) {
380
- $status = ( 'enable' === $get_array['value'] ) ? __( 'automatically update to all new versions of WordPress', 'wp-security-audit-log' ) : __( 'automatically update maintenance and security releases only', 'wp-security-audit-log' );
381
- $this->plugin->alerts->Trigger(
382
  6044,
383
  array(
384
  'updates_status' => $status,
@@ -400,11 +404,11 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
400
  $new_value = ( ! empty( $post_array['WPLANG'] ) ) ? $post_array['WPLANG'] : 'en-US';
401
 
402
  // Now lets turn these into a nice, native name - the same as shown to the user when choosing a language.
403
- $previous_value = ( isset( $available_translations[$previous_value] ) ) ? $available_translations[$previous_value]['native_name'] : 'English (United States)';
404
- $new_value = ( isset( $available_translations[$new_value] ) ) ? $available_translations[$new_value]['native_name'] : 'English (United States)';
405
 
406
  if ( $previous_value !== $new_value ) {
407
- $this->plugin->alerts->Trigger(
408
  6045,
409
  array(
410
  'previous_value' => $previous_value,
@@ -422,7 +426,7 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
422
  $new_value = ( ! empty( $post_array['blogname'] ) ) ? $post_array['blogname'] : '';
423
 
424
  if ( $previous_value !== $new_value ) {
425
- $this->plugin->alerts->Trigger(
426
  6059,
427
  array(
428
  'previous_value' => $previous_value,
@@ -438,11 +442,11 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
438
  *
439
  * @param array $automatic - Automatic update array.
440
  */
441
- public function WPUpdate( $automatic ) {
442
  if ( isset( $automatic['core'][0] ) ) {
443
  $obj = $automatic['core'][0];
444
  $old_version = get_bloginfo( 'version' );
445
- $this->plugin->alerts->Trigger(
446
  6004,
447
  array(
448
  'OldVersion' => $old_version,
@@ -459,7 +463,7 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
459
  *
460
  * @return array|null
461
  */
462
- public function EventOptions( $whitelist = null ) {
463
  // Filter global arrays for security.
464
  $post_array = filter_input_array( INPUT_POST );
465
 
@@ -468,7 +472,7 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
468
  $new_status = isset( $post_array['blog_public'] ) ? 0 : 1;
469
 
470
  if ( $old_status !== $new_status ) {
471
- $this->plugin->alerts->Trigger(
472
  6008,
473
  array( 'EventType' => ( 0 === $new_status ) ? 'enabled' : 'disabled' )
474
  );
@@ -480,7 +484,7 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
480
  $new_status = isset( $post_array['default_comment_status'] ) ? 'open' : 'closed';
481
 
482
  if ( $old_status !== $new_status ) {
483
- $this->plugin->alerts->Trigger(
484
  6009,
485
  array( 'EventType' => ( 'open' === $new_status ) ? 'enabled' : 'disabled' )
486
  );
@@ -490,7 +494,7 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
490
  $new_status = isset( $post_array['require_name_email'] ) ? 1 : 0;
491
 
492
  if ( $old_status !== $new_status ) {
493
- $this->plugin->alerts->Trigger(
494
  6010,
495
  array( 'EventType' => ( 1 === $new_status ) ? 'enabled' : 'disabled' )
496
  );
@@ -500,7 +504,7 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
500
  $new_status = isset( $post_array['comment_registration'] ) ? 1 : 0;
501
 
502
  if ( $old_status !== $new_status ) {
503
- $this->plugin->alerts->Trigger(
504
  6011,
505
  array( 'EventType' => ( 1 === $new_status ) ? 'enabled' : 'disabled' )
506
  );
@@ -511,7 +515,7 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
511
 
512
  if ( $old_status !== $new_status ) {
513
  $value = isset( $post_array['close_comments_days_old'] ) ? $post_array['close_comments_days_old'] : 0;
514
- $this->plugin->alerts->Trigger(
515
  6012,
516
  array(
517
  'EventType' => ( 1 === $new_status ) ? 'enabled' : 'disabled',
@@ -523,7 +527,7 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
523
  $old_value = get_option( 'close_comments_days_old', 0 );
524
  $new_value = isset( $post_array['close_comments_days_old'] ) ? $post_array['close_comments_days_old'] : 0;
525
  if ( $old_value !== $new_value ) {
526
- $this->plugin->alerts->Trigger(
527
  6013,
528
  array(
529
  'OldValue' => $old_value,
@@ -536,19 +540,19 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
536
  $new_status = isset( $post_array['comment_moderation'] ) ? 1 : 0;
537
 
538
  if ( $old_status !== $new_status ) {
539
- $this->plugin->alerts->Trigger(
540
  6014,
541
  array( 'EventType' => ( 1 === $new_status ) ? 'enabled' : 'disabled' )
542
  );
543
  }
544
 
545
- // comment_whitelist option was renamed to comment_previously_approved in WordPress 5.5.0
546
  $comment_whitelist_option_name = version_compare( get_bloginfo( 'version' ), '5.5.0', '<' ) ? 'comment_whitelist' : 'comment_previously_approved';
547
- $old_status = (int) get_option( $comment_whitelist_option_name, 0 );
548
- $new_status = isset( $post_array[ $comment_whitelist_option_name ] ) ? 1 : 0;
549
 
550
  if ( $old_status !== $new_status ) {
551
- $this->plugin->alerts->Trigger(
552
  6015,
553
  array( 'EventType' => ( 1 === $new_status ) ? 'enabled' : 'disabled' )
554
  );
@@ -557,7 +561,7 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
557
  $old_value = get_option( 'comment_max_links', 0 );
558
  $new_value = isset( $post_array['comment_max_links'] ) ? $post_array['comment_max_links'] : 0;
559
  if ( $old_value !== $new_value ) {
560
- $this->plugin->alerts->Trigger(
561
  6016,
562
  array(
563
  'OldValue' => $old_value,
@@ -569,15 +573,15 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
569
  $old_value = get_option( 'moderation_keys', 0 );
570
  $new_value = isset( $post_array['moderation_keys'] ) ? $post_array['moderation_keys'] : 0;
571
  if ( $old_value !== $new_value ) {
572
- $this->plugin->alerts->Trigger( 6017, array() );
573
  }
574
 
575
- // blacklist_keys option was renamed to disallowed_keys in WordPress 5.5.0
576
  $blacklist_keys_option_name = version_compare( get_bloginfo( 'version' ), '5.5.0', '<' ) ? 'blacklist_keys' : 'disallowed_keys';
577
- $old_value = get_option( $blacklist_keys_option_name, 0 );
578
- $new_value = isset( $post_array[ $blacklist_keys_option_name ] ) ? $post_array[ $blacklist_keys_option_name ] : 0;
579
  if ( $old_value !== $new_value ) {
580
- $this->plugin->alerts->Trigger( 6018, array() );
581
  }
582
  }
583
  return $whitelist;
@@ -594,24 +598,24 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
594
  $old_timezone_string = get_option( 'timezone_string' );
595
  $new_timezone_string = isset( $post_array['timezone_string'] ) ? $post_array['timezone_string'] : '';
596
 
597
- // backup of the labels as we might change them below when dealing with UTC offset definitions
598
  $old_timezone_label = $old_timezone_string;
599
  $new_timezone_label = $new_timezone_string;
600
  if ( strlen( $old_timezone_string ) === 0 ) {
601
- // the old timezone string can be empty if the time zone was configured using UTC offset selection
602
- // rather than using a country/city selection
603
- $old_timezone_string = $old_timezone_label = wp_timezone_string();
604
  if ( 'UTC' === $old_timezone_string ) {
605
  $old_timezone_string = '+00:00';
606
  }
607
 
608
- // adjusts label to show UTC offset consistently
609
  $old_timezone_label = 'UTC' . $old_timezone_label;
610
  }
611
 
612
- // new timezone can be defined as UTC offset
613
 
614
- // there is one UTC option that doesn't contain the offset, we need to tweak the value for further processing
615
  if ( 'UTC' === $new_timezone_string ) {
616
  $new_timezone_string = 'UTC+0';
617
  }
@@ -619,19 +623,19 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
619
  if ( preg_match( '/UTC([+\-][0-9\.]+)/', $new_timezone_string, $matches ) ) {
620
  $hours_decimal = floatval( $matches[1] );
621
 
622
- // the new timezone is also set using UTC offset, it needs to be converted to the same format used
623
- // by wp_timezone_string
624
  $sign = $hours_decimal < 0 ? '-' : '+';
625
  $abs_hours = abs( $hours_decimal );
626
  $abs_mins = abs( $hours_decimal * 60 % 60 );
627
  $new_timezone_string = sprintf( '%s%02d:%02d', $sign, floor( $abs_hours ), $abs_mins );
628
 
629
- // adjusts label to show UTC offset consistently
630
  $new_timezone_label = 'UTC' . $new_timezone_string;
631
  }
632
 
633
  if ( $old_timezone_string !== $new_timezone_string ) {
634
- $this->plugin->alerts->Trigger(
635
  6040,
636
  array(
637
  'old_timezone' => $old_timezone_label,
4
  *
5
  * System activity sensor class file.
6
  *
7
+ * @since 1.0.0
8
+ * @package wsal
9
+ * @subpackage sensors
10
  */
11
 
12
  // Exit if accessed directly.
41
  * 6017 Modified the list of keywords for comments moderation
42
  * 6018 Modified the list of keywords for comments blacklisting
43
  *
44
+ * @package wsal
45
  * @subpackage sensors
46
  */
47
  class WSAL_Sensors_System extends WSAL_AbstractSensor {
48
 
49
  /**
50
+ * {@inheritDoc}
51
  */
52
+ public function hook_events() {
53
+ add_action( 'wsal_prune', array( $this, 'event_prune_events' ), 10, 2 );
54
+ add_action( 'admin_init', array( $this, 'event_admin_init' ) );
55
+ add_action( 'automatic_updates_complete', array( $this, 'wp_update' ), 10, 1 );
56
 
57
  // whitelist options.
58
+ add_action( 'allowed_options', array( $this, 'event_options' ), 10, 1 );
59
 
60
  // Update admin email alert.
61
  add_action( 'update_option_admin_email', array( $this, 'admin_email_changed' ), 10, 3 );
73
  // Check if the option is not empty and is admin_email.
74
  if ( ! empty( $old_value ) && ! empty( $new_value )
75
  && ! empty( $option ) && 'admin_email' === $option ) {
76
+ if ( $old_value != $new_value ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
77
+ $this->plugin->alerts->trigger_event(
78
  6003,
79
  array(
80
  'OldEmail' => $old_value,
92
  * @param int $count The number of deleted events.
93
  * @param string $query Query that selected events for deletion.
94
  */
95
+ public function event_prune_events( $count, $query ) {
96
+ $this->plugin->alerts->trigger_event(
97
  6000,
98
  array(
99
  'EventCount' => $count,
104
 
105
  /**
106
  * Triggered when a user accesses the admin area.
107
+ *
108
+ * phpcs:disable WordPress.PHP.StrictComparisons.LooseComparison
109
+ * phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
110
  */
111
+ public function event_admin_init() {
112
  // Filter global arrays for security.
113
  $post_array = filter_input_array( INPUT_POST );
114
  $get_array = filter_input_array( INPUT_GET );
116
 
117
  // Destroy all the session of the same user from user profile page.
118
  if ( isset( $post_array['action'] ) && ( 'destroy-sessions' == $post_array['action'] ) && isset( $post_array['user_id'] ) ) {
119
+ $this->plugin->alerts->trigger_event(
120
  1006,
121
  array(
122
  'TargetUserID' => $post_array['user_id'],
134
  $actype = basename( $server_array['SCRIPT_NAME'], '.php' );
135
  }
136
 
137
+ if ( isset( $post_array['action'] ) && 'toggle-auto-updates' == $post_array['action'] ) {
138
  $event_id = ( 'theme' == $post_array['type'] ) ? 5029 : 5028;
139
 
140
  if ( 'theme' == $post_array['type'] ) {
141
  $all_themes = wp_get_themes();
142
+ $our_theme = $all_themes[ $post_array['asset'] ];
143
  $install_location = $our_theme->get_template_directory();
144
  $name = $our_theme->Name;
145
+ } elseif ( 'plugin' == $post_array['type'] ) {
146
  $all_plugins = get_plugins();
147
+ $our_plugin = $all_plugins[ $post_array['asset'] ];
148
  $install_location = plugin_dir_path( WP_PLUGIN_DIR . '/' . $post_array['asset'] );
149
  $name = $our_plugin['Name'];
150
  }
151
 
152
+ $this->plugin->alerts->trigger_event(
153
  $event_id,
154
  array(
155
  'install_directory' => $install_location,
170
  $old_siteurl = get_option( 'siteurl' );
171
  $new_siteurl = isset( $post_array['siteurl'] ) ? $post_array['siteurl'] : '';
172
  if ( $old_siteurl !== $new_siteurl ) {
173
+ $this->plugin->alerts->trigger_event(
174
  6024,
175
  array(
176
  'old_url' => $old_siteurl,
188
  $old_url = get_option( 'home' );
189
  $new_url = isset( $post_array['home'] ) ? $post_array['home'] : '';
190
  if ( $old_url !== $new_url ) {
191
+ $this->plugin->alerts->trigger_event(
192
  6025,
193
  array(
194
  'old_url' => $old_url,
201
 
202
  if ( isset( $post_array['option_page'] ) && 'reading' === $post_array['option_page'] && isset( $post_array['show_on_front'] )
203
  && wp_verify_nonce( $post_array['_wpnonce'], 'reading-options' ) ) {
204
+ $old_homepage = ( 'posts' === get_site_option( 'show_on_front' ) ) ? __( 'latest posts', 'wp-security-audit-log' ) : __( 'static page', 'wp-security-audit-log' );
205
+ $new_homepage = ( 'posts' === $post_array['show_on_front'] ) ? __( 'latest posts', 'wp-security-audit-log' ) : __( 'static page', 'wp-security-audit-log' );
206
  if ( $old_homepage != $new_homepage ) {
207
+ $this->plugin->alerts->trigger_event(
208
  6035,
209
  array(
210
  'old_homepage' => $old_homepage,
216
 
217
  if ( isset( $post_array['option_page'] ) && 'reading' === $post_array['option_page'] && isset( $post_array['page_on_front'] )
218
  && wp_verify_nonce( $post_array['_wpnonce'], 'reading-options' ) ) {
219
+ $old_frontpage = get_the_title( get_site_option( 'page_on_front' ) );
220
+ $new_frontpage = get_the_title( $post_array['page_on_front'] );
221
  if ( $old_frontpage != $new_frontpage ) {
222
+ $this->plugin->alerts->trigger_event(
223
  6036,
224
  array(
225
  'old_page' => $old_frontpage,
232
  if ( isset( $post_array['option_page'] ) && 'reading' === $post_array['option_page'] && isset( $post_array['page_for_posts'] )
233
  && wp_verify_nonce( $post_array['_wpnonce'], 'reading-options' ) ) {
234
  $old_postspage = get_the_title( get_site_option( 'page_for_posts' ) );
235
+ $new_postspage = get_the_title( $post_array['page_for_posts'] );
236
  if ( $old_postspage != $new_postspage ) {
237
+ $this->plugin->alerts->trigger_event(
238
  6037,
239
  array(
240
  'old_page' => $old_postspage,
244
  }
245
  }
246
 
247
+ // Check timezone change.
248
  if ( $is_option_page && wp_verify_nonce( $post_array['_wpnonce'], 'general-options' ) && ! empty( $post_array['timezone_string'] ) ) {
249
  $this->check_timezone_change( $post_array );
250
  }
251
 
252
+ // Check date format change.
253
  if ( $is_option_page && wp_verify_nonce( $post_array['_wpnonce'], 'general-options' ) && ! empty( $post_array['date_format'] ) ) {
254
  $old_date_format = get_option( 'date_format' );
255
  $new_date_format = ( '\c\u\s\t\o\m' === $post_array['date_format'] ) ? $post_array['date_format_custom'] : $post_array['date_format'];
256
  if ( $old_date_format !== $new_date_format ) {
257
+ $this->plugin->alerts->trigger_event(
258
  6041,
259
  array(
260
  'old_date_format' => $old_date_format,
265
  }
266
  }
267
 
268
+ // Check time format change.
269
  if ( $is_option_page && wp_verify_nonce( $post_array['_wpnonce'], 'general-options' ) && ! empty( $post_array['time_format'] ) ) {
270
+ $old_time_format = get_option( 'time_format' );
271
  $new_time_format = ( '\c\u\s\t\o\m' === $post_array['time_format'] ) ? $post_array['time_format_custom'] : $post_array['time_format'];
272
  if ( $old_time_format !== $new_time_format ) {
273
+ $this->plugin->alerts->trigger_event(
274
  6042,
275
  array(
276
  'old_time_format' => $old_time_format,
287
  $new = isset( $post_array['users_can_register'] ) ? 'enabled' : 'disabled';
288
 
289
  if ( $old !== $new ) {
290
+ $this->plugin->alerts->trigger_event(
291
  6001,
292
  array(
293
  'EventType' => $new,
302
  $old = get_option( 'default_role' );
303
  $new = trim( $post_array['default_role'] );
304
  if ( $old != $new ) {
305
+ $this->plugin->alerts->trigger_event(
306
  6002,
307
  array(
308
  'OldRole' => $old,
318
  $old = get_option( 'admin_email' );
319
  $new = trim( $post_array['admin_email'] );
320
  if ( $old != $new ) {
321
+ $this->plugin->alerts->trigger_event(
322
  6003,
323
  array(
324
  'OldEmail' => $old,
334
  $old = get_site_option( 'admin_email' );
335
  $new = trim( $post_array['new_admin_email'] );
336
  if ( $old != $new ) {
337
+ $this->plugin->alerts->trigger_event(
338
  6003,
339
  array(
340
  'OldEmail' => $old,
347
 
348
  // Permalinks changed.
349
  if ( $is_permalink_page && ! empty( $post_array['permalink_structure'] )
350
+ && wp_verify_nonce( $post_array['_wpnonce'], 'update-permalink' ) ) {
351
  $old = get_option( 'permalink_structure' );
352
  $new = trim( $post_array['permalink_structure'] );
353
  if ( $old != $new ) {
354
+ $this->plugin->alerts->trigger_event(
355
  6005,
356
  array(
357
  'OldPattern' => $old,
364
 
365
  // Core Update.
366
  if ( isset( $get_array['action'] ) && 'do-core-upgrade' === $get_array['action'] && isset( $post_array['version'] )
367
+ && wp_verify_nonce( $post_array['_wpnonce'], 'upgrade-core' ) ) {
368
  $old_version = get_bloginfo( 'version' );
369
  $new_version = $post_array['version'];
370
  if ( $old_version != $new_version ) {
371
+ $this->plugin->alerts->trigger_event(
372
  6004,
373
  array(
374
  'OldVersion' => $old_version,
381
  // Enable core updates.
382
  if ( isset( $get_array['action'] ) && 'core-major-auto-updates-settings' === $get_array['action'] && isset( $get_array['value'] )
383
  && wp_verify_nonce( $get_array['_wpnonce'], 'core-major-auto-updates-nonce' ) ) {
384
+ $status = ( 'enable' === $get_array['value'] ) ? esc_html__( 'automatically update to all new versions of WordPress', 'wp-security-audit-log' ) : esc_html__( 'automatically update maintenance and security releases only', 'wp-security-audit-log' );
385
+ $this->plugin->alerts->trigger_event(
386
  6044,
387
  array(
388
  'updates_status' => $status,
404
  $new_value = ( ! empty( $post_array['WPLANG'] ) ) ? $post_array['WPLANG'] : 'en-US';
405
 
406
  // Now lets turn these into a nice, native name - the same as shown to the user when choosing a language.
407
+ $previous_value = ( isset( $available_translations[ $previous_value ] ) ) ? $available_translations[ $previous_value ]['native_name'] : 'English (United States)';
408
+ $new_value = ( isset( $available_translations[ $new_value ] ) ) ? $available_translations[ $new_value ]['native_name'] : 'English (United States)';
409
 
410
  if ( $previous_value !== $new_value ) {
411
+ $this->plugin->alerts->trigger_event(
412
  6045,
413
  array(
414
  'previous_value' => $previous_value,
426
  $new_value = ( ! empty( $post_array['blogname'] ) ) ? $post_array['blogname'] : '';
427
 
428
  if ( $previous_value !== $new_value ) {
429
+ $this->plugin->alerts->trigger_event(
430
  6059,
431
  array(
432
  'previous_value' => $previous_value,
442
  *
443
  * @param array $automatic - Automatic update array.
444
  */
445
+ public function wp_update( $automatic ) {
446
  if ( isset( $automatic['core'][0] ) ) {
447
  $obj = $automatic['core'][0];
448
  $old_version = get_bloginfo( 'version' );
449
+ $this->plugin->alerts->trigger_event(
450
  6004,
451
  array(
452
  'OldVersion' => $old_version,
463
  *
464
  * @return array|null
465
  */
466
+ public function event_options( $whitelist = null ) {
467
  // Filter global arrays for security.
468
  $post_array = filter_input_array( INPUT_POST );
469
 
472
  $new_status = isset( $post_array['blog_public'] ) ? 0 : 1;
473
 
474
  if ( $old_status !== $new_status ) {
475
+ $this->plugin->alerts->trigger_event(
476
  6008,
477
  array( 'EventType' => ( 0 === $new_status ) ? 'enabled' : 'disabled' )
478
  );
484
  $new_status = isset( $post_array['default_comment_status'] ) ? 'open' : 'closed';
485
 
486
  if ( $old_status !== $new_status ) {
487
+ $this->plugin->alerts->trigger_event(
488
  6009,
489
  array( 'EventType' => ( 'open' === $new_status ) ? 'enabled' : 'disabled' )
490
  );
494
  $new_status = isset( $post_array['require_name_email'] ) ? 1 : 0;
495
 
496
  if ( $old_status !== $new_status ) {
497
+ $this->plugin->alerts->trigger_event(
498
  6010,
499
  array( 'EventType' => ( 1 === $new_status ) ? 'enabled' : 'disabled' )
500
  );
504
  $new_status = isset( $post_array['comment_registration'] ) ? 1 : 0;
505
 
506
  if ( $old_status !== $new_status ) {
507
+ $this->plugin->alerts->trigger_event(
508
  6011,
509
  array( 'EventType' => ( 1 === $new_status ) ? 'enabled' : 'disabled' )
510
  );
515
 
516
  if ( $old_status !== $new_status ) {
517
  $value = isset( $post_array['close_comments_days_old'] ) ? $post_array['close_comments_days_old'] : 0;
518
+ $this->plugin->alerts->trigger_event(
519
  6012,
520
  array(
521
  'EventType' => ( 1 === $new_status ) ? 'enabled' : 'disabled',
527
  $old_value = get_option( 'close_comments_days_old', 0 );
528
  $new_value = isset( $post_array['close_comments_days_old'] ) ? $post_array['close_comments_days_old'] : 0;
529
  if ( $old_value !== $new_value ) {
530
+ $this->plugin->alerts->trigger_event(
531
  6013,
532
  array(
533
  'OldValue' => $old_value,
540
  $new_status = isset( $post_array['comment_moderation'] ) ? 1 : 0;
541
 
542
  if ( $old_status !== $new_status ) {
543
+ $this->plugin->alerts->trigger_event(
544
  6014,
545
  array( 'EventType' => ( 1 === $new_status ) ? 'enabled' : 'disabled' )
546
  );
547
  }
548
 
549
+ // Comment_whitelist option was renamed to comment_previously_approved in WordPress 5.5.0.
550
  $comment_whitelist_option_name = version_compare( get_bloginfo( 'version' ), '5.5.0', '<' ) ? 'comment_whitelist' : 'comment_previously_approved';
551
+ $old_status = (int) get_option( $comment_whitelist_option_name, 0 );
552
+ $new_status = isset( $post_array[ $comment_whitelist_option_name ] ) ? 1 : 0;
553
 
554
  if ( $old_status !== $new_status ) {
555
+ $this->plugin->alerts->trigger_event(
556
  6015,
557
  array( 'EventType' => ( 1 === $new_status ) ? 'enabled' : 'disabled' )
558
  );
561
  $old_value = get_option( 'comment_max_links', 0 );
562
  $new_value = isset( $post_array['comment_max_links'] ) ? $post_array['comment_max_links'] : 0;
563
  if ( $old_value !== $new_value ) {
564
+ $this->plugin->alerts->trigger_event(
565
  6016,
566
  array(
567
  'OldValue' => $old_value,
573
  $old_value = get_option( 'moderation_keys', 0 );
574
  $new_value = isset( $post_array['moderation_keys'] ) ? $post_array['moderation_keys'] : 0;
575
  if ( $old_value !== $new_value ) {
576
+ $this->plugin->alerts->trigger_event( 6017, array() );
577
  }
578
 
579
+ // Blacklist_keys option was renamed to disallowed_keys in WordPress 5.5.0.
580
  $blacklist_keys_option_name = version_compare( get_bloginfo( 'version' ), '5.5.0', '<' ) ? 'blacklist_keys' : 'disallowed_keys';
581
+ $old_value = get_option( $blacklist_keys_option_name, 0 );
582
+ $new_value = isset( $post_array[ $blacklist_keys_option_name ] ) ? $post_array[ $blacklist_keys_option_name ] : 0;
583
  if ( $old_value !== $new_value ) {
584
+ $this->plugin->alerts->trigger_event( 6018, array() );
585
  }
586
  }
587
  return $whitelist;
598
  $old_timezone_string = get_option( 'timezone_string' );
599
  $new_timezone_string = isset( $post_array['timezone_string'] ) ? $post_array['timezone_string'] : '';
600
 
601
+ // Backup of the labels as we might change them below when dealing with UTC offset definitions.
602
  $old_timezone_label = $old_timezone_string;
603
  $new_timezone_label = $new_timezone_string;
604
  if ( strlen( $old_timezone_string ) === 0 ) {
605
+ // The old timezone string can be empty if the time zone was configured using UTC offset selection
606
+ // rather than using a country/city selection.
607
+ $old_timezone_string = $old_timezone_label = wp_timezone_string(); // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.Found
608
  if ( 'UTC' === $old_timezone_string ) {
609
  $old_timezone_string = '+00:00';
610
  }
611
 
612
+ // Adjusts label to show UTC offset consistently.
613
  $old_timezone_label = 'UTC' . $old_timezone_label;
614
  }
615
 
616
+ // New timezone can be defined as UTC offset.
617
 
618
+ // There is one UTC option that doesn't contain the offset, we need to tweak the value for further processing.
619
  if ( 'UTC' === $new_timezone_string ) {
620
  $new_timezone_string = 'UTC+0';
621
  }
623
  if ( preg_match( '/UTC([+\-][0-9\.]+)/', $new_timezone_string, $matches ) ) {
624
  $hours_decimal = floatval( $matches[1] );
625
 
626
+ // The new timezone is also set using UTC offset, it needs to be converted to the same format used
627
+ // by wp_timezone_string.
628
  $sign = $hours_decimal < 0 ? '-' : '+';
629
  $abs_hours = abs( $hours_decimal );
630
  $abs_mins = abs( $hours_decimal * 60 % 60 );
631
  $new_timezone_string = sprintf( '%s%02d:%02d', $sign, floor( $abs_hours ), $abs_mins );
632
 
633
+ // Adjusts label to show UTC offset consistently.
634
  $new_timezone_label = 'UTC' . $new_timezone_string;
635
  }
636
 
637
  if ( $old_timezone_string !== $new_timezone_string ) {
638
+ $this->plugin->alerts->trigger_event(
639
  6040,
640
  array(
641
  'old_timezone' => $old_timezone_label,
classes/Sensors/UserProfile.php CHANGED
@@ -4,10 +4,10 @@
4
  *
5
  * User profile sensor file.
6
  *
7
- * @package wsal
8
  * @subpackage sensors
9
  *
10
- * @since 1.0.0
11
  */
12
 
13
  // Exit if accessed directly.
@@ -29,7 +29,7 @@ if ( ! defined( 'ABSPATH' ) ) {
29
  * 4009 User revoked from Super Admin privileges
30
  * 4014 User opened the profile page of another user
31
  *
32
- * @package wsal
33
  * @subpackage sensors
34
  */
35
  class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
@@ -44,7 +44,7 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
44
  /**
45
  * {@inheritDoc}
46
  */
47
- public function HookEvents() {
48
  add_action( 'profile_update', array( $this, 'event_user_updated' ), 10, 2 );
49
  add_action( 'set_user_role', array( $this, 'event_user_role_changed' ), 10, 3 );
50
  add_action( 'delete_user', array( $this, 'event_user_deleted' ) );
@@ -68,6 +68,8 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
68
  * @param int $user_id ID of the user metadata is for.
69
  * @param string $meta_key Metadata key.
70
  * @param mixed $_meta_value Metadata value. Serialized if non-scalar.
 
 
71
  */
72
  public function event_application_password_added( $meta_id, $user_id, $meta_key, $_meta_value ) {
73
 
@@ -95,15 +97,21 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
95
 
96
  $current_user = get_user_by( 'id', $user_id );
97
  $current_userdata = get_userdata( $user_id );
98
- $current_user_roles = implode( ', ', array_map( array(
99
- $this,
100
- 'filter_role_names'
101
- ), $current_userdata->roles ) );
 
 
 
 
 
 
102
  $event_id = ( 'user-edit' === $referer_check ) ? 4026 : 4025;
103
 
104
  // Note, firstname and lastname fields are purposefully spaces to avoid NULL.
105
  if ( isset( $_POST['name'] ) ) {
106
- $this->plugin->alerts->Trigger(
107
  $event_id,
108
  array(
109
  'roles' => $current_user_roles,
@@ -120,7 +128,7 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
120
  $event_id = ( 'user-edit' === $referer_check ) ? 4028 : 4027;
121
 
122
  // Note, firstname and lastname fields are purposefully spaces to avoid NULL.
123
- $this->plugin->alerts->Trigger(
124
  $event_id,
125
  array(
126
  'roles' => $current_user_roles,
@@ -139,7 +147,7 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
139
  $event_id = ( 'user-edit' === $referer_check ) ? 4026 : 4025;
140
 
141
  // Note, firstname and lastname fields are purposefully spaces to avoid NULL.
142
- $this->plugin->alerts->Trigger(
143
  $event_id,
144
  array(
145
  'roles' => $current_user_roles,
@@ -170,7 +178,7 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
170
  if ( $old_userdata->user_pass !== $new_userdata->user_pass ) {
171
  $event = get_current_user_id() === $user_id ? 4003 : 4004;
172
  $user_roles = implode( ', ', array_map( array( $this, 'filter_role_names' ), $new_userdata->roles ) );
173
- $this->plugin->alerts->Trigger(
174
  $event,
175
  array(
176
  'TargetUserID' => $user_id,
@@ -189,7 +197,7 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
189
  if ( $old_userdata->user_email !== $new_userdata->user_email ) {
190
  $event = get_current_user_id() === $user_id ? 4005 : 4006;
191
  $user_roles = implode( ', ', array_map( array( $this, 'filter_role_names' ), $new_userdata->roles ) );
192
- $this->plugin->alerts->Trigger(
193
  $event,
194
  array(
195
  'TargetUserID' => $user_id,
@@ -207,7 +215,7 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
207
  // Alert if display name is changed.
208
  if ( $old_userdata->display_name !== $new_userdata->display_name ) {
209
  $user_roles = implode( ', ', array_map( array( $this, 'filter_role_names' ), $new_userdata->roles ) );
210
- $this->plugin->alerts->Trigger(
211
  4020,
212
  array(
213
  'TargetUsername' => $new_userdata->user_login,
@@ -224,7 +232,7 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
224
  // Alert if website URL is changed.
225
  if ( $old_userdata->user_url !== $new_userdata->user_url ) {
226
  $user_roles = implode( ', ', array_map( array( $this, 'filter_role_names' ), $new_userdata->roles ) );
227
- $this->plugin->alerts->Trigger(
228
  4021,
229
  array(
230
  'TargetUsername' => $new_userdata->user_login,
@@ -241,7 +249,7 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
241
  // Alert if role has changed via Members plugin.
242
  if ( isset( $_POST['members_user_roles'] ) && ! empty( $_POST['members_user_roles'] ) ) {
243
  if ( $old_userdata->roles !== $_POST['members_user_roles'] ) {
244
- $this->event_user_role_changed( $user_id, $_POST['members_user_roles'], $old_userdata->roles, true );
245
  }
246
  }
247
  }
@@ -274,7 +282,7 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
274
 
275
  // Alert if roles are changed.
276
  if ( $old_roles !== $new_roles ) {
277
- $this->plugin->alerts->TriggerIf(
278
  4002,
279
  array(
280
  'TargetUserID' => $user_id,
@@ -284,9 +292,9 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
284
  'FirstName' => $user->user_firstname,
285
  'LastName' => $user->user_lastname,
286
  'EditUserLink' => add_query_arg( 'user_id', $user_id, admin_url( 'user-edit.php' ) ),
287
- 'multisite_text' => $this->plugin->IsMultisite() ? get_current_blog_id() : false,
288
  ),
289
- array( $this, 'MustNotContainUserChanges' )
290
  );
291
  }
292
  }
@@ -299,7 +307,7 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
299
  public function event_user_deleted( $user_id ) {
300
  $user = get_userdata( $user_id );
301
  $role = is_array( $user->roles ) ? implode( ', ', $user->roles ) : $user->roles;
302
- $this->plugin->alerts->TriggerIf(
303
  4007,
304
  array(
305
  'TargetUserID' => $user_id,
@@ -311,7 +319,7 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
311
  'Roles' => $role ? $role : 'none',
312
  ),
313
  ),
314
- array( $this, 'MustNotContainCreateUser' )
315
  );
316
  }
317
 
@@ -326,10 +334,10 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
326
  }
327
 
328
  $current_user = wp_get_current_user();
329
- $updated = isset( $_GET['updated'] ); // @codingStandardsIgnoreLine
330
  if ( $current_user && ( $user->ID !== $current_user->ID ) && ! $updated ) {
331
  $user_roles = implode( ', ', array_map( array( $this, 'filter_role_names' ), $user->roles ) );
332
- $this->plugin->alerts->Trigger(
333
  4014,
334
  array(
335
  'UserChanger' => $current_user->user_login,
@@ -347,7 +355,7 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
347
  * Triggered when a user accesses the admin area.
348
  */
349
  public function get_super_admins() {
350
- $this->old_superadmins = $this->IsMultisite() ? get_super_admins() : null;
351
  }
352
 
353
  /**
@@ -362,7 +370,7 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
362
  public function event_super_access_granted( $user_id ) {
363
  $user = get_userdata( $user_id );
364
  if ( $user && ! in_array( $user->user_login, $this->old_superadmins, true ) ) {
365
- $this->plugin->alerts->Trigger(
366
  4008,
367
  array(
368
  'TargetUserID' => $user_id,
@@ -388,7 +396,7 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
388
  public function event_super_access_revoked( $user_id ) {
389
  $user = get_userdata( $user_id );
390
  if ( $user && in_array( $user->user_login, $this->old_superadmins, true ) ) {
391
- $this->plugin->alerts->Trigger(
392
  4009,
393
  array(
394
  'TargetUserID' => $user_id,
@@ -411,12 +419,18 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
411
  $current_user = get_user_by( 'login', $user_login );
412
 
413
  $current_userdata = get_userdata( $current_user->ID );
414
- $current_user_roles = implode( ', ', array_map( array(
415
- $this,
416
- 'filter_role_names'
417
- ), $current_userdata->roles ) );
 
 
 
 
 
 
418
 
419
- $this->plugin->alerts->Trigger(
420
  4029,
421
  array(
422
  'roles' => $current_user_roles,
@@ -448,8 +462,8 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
448
  *
449
  * @param WSAL_AlertManager $mgr - Instance of WSAL_AlertManager.
450
  */
451
- public function MustNotContainCreateUser( WSAL_AlertManager $mgr ) {
452
- return ! $mgr->WillTrigger( 4012 );
453
  }
454
 
455
  /**
@@ -457,13 +471,13 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
457
  *
458
  * @param WSAL_AlertManager $mgr - Instance of WSAL_AlertManager.
459
  */
460
- public function MustNotContainUserChanges( WSAL_AlertManager $mgr ) {
461
  return ! (
462
- $mgr->WillOrHasTriggered( 4010 )
463
- || $mgr->WillOrHasTriggered( 4011 )
464
- || $mgr->WillOrHasTriggered( 4012 )
465
- || $mgr->WillOrHasTriggered( 4000 )
466
- || $mgr->WillOrHasTriggered( 4001 )
467
  );
468
  }
469
 
@@ -495,10 +509,10 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
495
  'LastName' => ! empty( $user->user_lastname ) ? $user->user_lastname : '',
496
  );
497
 
498
- $event_code = $this->plugin->IsMultisite() ? 4012 : 4001;
499
  if ( 4001 === $event_code ) {
500
  $new_user_data['Roles'] = is_array( $user->roles ) ? implode( ', ', $user->roles ) : $user->roles;
501
- } else if ( 4012 === $event_code ) {
502
  $new_user_data['Email'] = $user->user_email;
503
  }
504
 
@@ -508,6 +522,6 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
508
  'EditUserLink' => add_query_arg( 'user_id', $user_id, admin_url( 'user-edit.php' ) ),
509
  );
510
 
511
- $this->plugin->alerts->Trigger( $event_code, $event_data, $this->plugin->IsMultisite() );
512
  }
513
  }
4
  *
5
  * User profile sensor file.
6
  *
7
+ * @package wsal
8
  * @subpackage sensors
9
  *
10
+ * @since 1.0.0
11
  */
12
 
13
  // Exit if accessed directly.
29
  * 4009 User revoked from Super Admin privileges
30
  * 4014 User opened the profile page of another user
31
  *
32
+ * @package wsal
33
  * @subpackage sensors
34
  */
35
  class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
44
  /**
45
  * {@inheritDoc}
46
  */
47
+ public function hook_events() {
48
  add_action( 'profile_update', array( $this, 'event_user_updated' ), 10, 2 );
49
  add_action( 'set_user_role', array( $this, 'event_user_role_changed' ), 10, 3 );
50
  add_action( 'delete_user', array( $this, 'event_user_deleted' ) );
68
  * @param int $user_id ID of the user metadata is for.
69
  * @param string $meta_key Metadata key.
70
  * @param mixed $_meta_value Metadata value. Serialized if non-scalar.
71
+ *
72
+ * phpcs:disable WordPress.Security.NonceVerification.Missing
73
  */
74
  public function event_application_password_added( $meta_id, $user_id, $meta_key, $_meta_value ) {
75
 
97
 
98
  $current_user = get_user_by( 'id', $user_id );
99
  $current_userdata = get_userdata( $user_id );
100
+ $current_user_roles = implode(
101
+ ', ',
102
+ array_map(
103
+ array(
104
+ $this,
105
+ 'filter_role_names',
106
+ ),
107
+ $current_userdata->roles
108
+ )
109
+ );
110
  $event_id = ( 'user-edit' === $referer_check ) ? 4026 : 4025;
111
 
112
  // Note, firstname and lastname fields are purposefully spaces to avoid NULL.
113
  if ( isset( $_POST['name'] ) ) {
114
+ $this->plugin->alerts->trigger_event(
115
  $event_id,
116
  array(
117
  'roles' => $current_user_roles,
128
  $event_id = ( 'user-edit' === $referer_check ) ? 4028 : 4027;
129
 
130
  // Note, firstname and lastname fields are purposefully spaces to avoid NULL.
131
+ $this->plugin->alerts->trigger_event(
132
  $event_id,
133
  array(
134
  'roles' => $current_user_roles,
147
  $event_id = ( 'user-edit' === $referer_check ) ? 4026 : 4025;
148
 
149
  // Note, firstname and lastname fields are purposefully spaces to avoid NULL.
150
+ $this->plugin->alerts->trigger_event(
151
  $event_id,
152
  array(
153
  'roles' => $current_user_roles,
178
  if ( $old_userdata->user_pass !== $new_userdata->user_pass ) {
179
  $event = get_current_user_id() === $user_id ? 4003 : 4004;
180
  $user_roles = implode( ', ', array_map( array( $this, 'filter_role_names' ), $new_userdata->roles ) );
181
+ $this->plugin->alerts->trigger_event(
182
  $event,
183
  array(
184
  'TargetUserID' => $user_id,
197
  if ( $old_userdata->user_email !== $new_userdata->user_email ) {
198
  $event = get_current_user_id() === $user_id ? 4005 : 4006;
199
  $user_roles = implode( ', ', array_map( array( $this, 'filter_role_names' ), $new_userdata->roles ) );
200
+ $this->plugin->alerts->trigger_event(
201
  $event,
202
  array(
203
  'TargetUserID' => $user_id,
215
  // Alert if display name is changed.
216
  if ( $old_userdata->display_name !== $new_userdata->display_name ) {
217
  $user_roles = implode( ', ', array_map( array( $this, 'filter_role_names' ), $new_userdata->roles ) );
218
+ $this->plugin->alerts->trigger_event(
219
  4020,
220
  array(
221
  'TargetUsername' => $new_userdata->user_login,
232
  // Alert if website URL is changed.
233
  if ( $old_userdata->user_url !== $new_userdata->user_url ) {
234
  $user_roles = implode( ', ', array_map( array( $this, 'filter_role_names' ), $new_userdata->roles ) );
235
+ $this->plugin->alerts->trigger_event(
236
  4021,
237
  array(
238
  'TargetUsername' => $new_userdata->user_login,
249
  // Alert if role has changed via Members plugin.
250
  if ( isset( $_POST['members_user_roles'] ) && ! empty( $_POST['members_user_roles'] ) ) {
251
  if ( $old_userdata->roles !== $_POST['members_user_roles'] ) {
252
+ $this->event_user_role_changed( $user_id, $_POST['members_user_roles'], $old_userdata->roles, true ); // phpcs:ignore
253
  }
254
  }
255
  }
282
 
283
  // Alert if roles are changed.
284
  if ( $old_roles !== $new_roles ) {
285
+ $this->plugin->alerts->trigger_event_if(
286
  4002,
287
  array(
288
  'TargetUserID' => $user_id,
292
  'FirstName' => $user->user_firstname,
293
  'LastName' => $user->user_lastname,
294
  'EditUserLink' => add_query_arg( 'user_id', $user_id, admin_url( 'user-edit.php' ) ),
295
+ 'multisite_text' => $this->plugin->is_multisite() ? get_current_blog_id() : false,
296
  ),
297
+ array( $this, 'must_not_contain_user_changes' )
298
  );
299
  }
300
  }
307
  public function event_user_deleted( $user_id ) {
308
  $user = get_userdata( $user_id );
309
  $role = is_array( $user->roles ) ? implode( ', ', $user->roles ) : $user->roles;
310
+ $this->plugin->alerts->trigger_event_if(
311
  4007,
312
  array(
313
  'TargetUserID' => $user_id,
319
  'Roles' => $role ? $role : 'none',
320
  ),
321
  ),
322
+ array( $this, 'must_not_contain_create_user' )
323
  );
324
  }
325
 
334
  }
335
 
336
  $current_user = wp_get_current_user();
337
+ $updated = isset( $_GET['updated'] ); // phpcs:ignore
338
  if ( $current_user && ( $user->ID !== $current_user->ID ) && ! $updated ) {
339
  $user_roles = implode( ', ', array_map( array( $this, 'filter_role_names' ), $user->roles ) );
340
+ $this->plugin->alerts->trigger_event(
341
  4014,
342
  array(
343
  'UserChanger' => $current_user->user_login,
355
  * Triggered when a user accesses the admin area.
356
  */
357
  public function get_super_admins() {
358
+ $this->old_superadmins = $this->is_multisite() ? get_super_admins() : null;
359
  }
360
 
361
  /**
370
  public function event_super_access_granted( $user_id ) {
371
  $user = get_userdata( $user_id );
372
  if ( $user && ! in_array( $user->user_login, $this->old_superadmins, true ) ) {
373
+ $this->plugin->alerts->trigger_event(
374
  4008,
375
  array(
376
  'TargetUserID' => $user_id,
396
  public function event_super_access_revoked( $user_id ) {
397
  $user = get_userdata( $user_id );
398
  if ( $user && in_array( $user->user_login, $this->old_superadmins, true ) ) {
399
+ $this->plugin->alerts->trigger_event(
400
  4009,
401
  array(
402
  'TargetUserID' => $user_id,
419
  $current_user = get_user_by( 'login', $user_login );
420
 
421
  $current_userdata = get_userdata( $current_user->ID );
422
+ $current_user_roles = implode(
423
+ ', ',
424
+ array_map(
425
+ array(
426
+ $this,
427
+ 'filter_role_names',
428
+ ),
429
+ $current_userdata->roles
430
+ )
431
+ );
432
 
433
+ $this->plugin->alerts->trigger_event(
434
  4029,
435
  array(
436
  'roles' => $current_user_roles,
462
  *
463
  * @param WSAL_AlertManager $mgr - Instance of WSAL_AlertManager.
464
  */
465
+ public function must_not_contain_create_user( WSAL_AlertManager $mgr ) {
466
+ return ! $mgr->will_trigger( 4012 );
467
  }
468
 
469
  /**
471
  *
472
  * @param WSAL_AlertManager $mgr - Instance of WSAL_AlertManager.
473
  */
474
+ public function must_not_contain_user_changes( WSAL_AlertManager $mgr ) {
475
  return ! (
476
+ $mgr->will_or_has_triggered( 4010 )
477
+ || $mgr->will_or_has_triggered( 4011 )
478
+ || $mgr->will_or_has_triggered( 4012 )
479
+ || $mgr->will_or_has_triggered( 4000 )
480
+ || $mgr->will_or_has_triggered( 4001 )
481
  );
482
  }
483
 
509
  'LastName' => ! empty( $user->user_lastname ) ? $user->user_lastname : '',
510
  );
511
 
512
+ $event_code = $this->plugin->is_multisite() ? 4012 : 4001;
513
  if ( 4001 === $event_code ) {
514
  $new_user_data['Roles'] = is_array( $user->roles ) ? implode( ', ', $user->roles ) : $user->roles;
515
+ } elseif ( 4012 === $event_code ) {
516
  $new_user_data['Email'] = $user->user_email;
517
  }
518
 
522
  'EditUserLink' => add_query_arg( 'user_id', $user_id, admin_url( 'user-edit.php' ) ),
523
  );
524
 
525
+ $this->plugin->alerts->trigger_event( $event_code, $event_data, $this->plugin->is_multisite() );
526
  }
527
  }
classes/Sensors/Widgets.php CHANGED
@@ -4,8 +4,9 @@
4
  *
5
  * Widgets sensor class file.
6
  *
7
- * @since 1.0.0
8
- * @package wsal
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -22,7 +23,7 @@ if ( ! defined( 'ABSPATH' ) ) {
22
  * 2045 User moved widget
23
  * 2071 User changed widget position
24
  *
25
- * @package wsal
26
  * @subpackage sensors
27
  */
28
  class WSAL_Sensors_Widgets extends WSAL_AbstractSensor {
@@ -32,24 +33,24 @@ class WSAL_Sensors_Widgets extends WSAL_AbstractSensor {
32
  *
33
  * @var array
34
  */
35
- protected $_widget_move_data = null;
36
 
37
  /**
38
- * Listening to events using WP hooks.
39
  */
40
- public function HookEvents() {
41
  if ( current_user_can( 'edit_theme_options' ) ) {
42
- add_action( 'admin_init', array( $this, 'EventWidgetMove' ) );
43
- add_action( 'admin_init', array( $this, 'EventWidgetPostMove' ) );
44
  }
45
- add_action( 'sidebar_admin_setup', array( $this, 'EventWidgetActivity' ) );
46
  }
47
 
48
  /**
49
  * Triggered when a user accesses the admin area.
50
  * Moved widget.
51
  */
52
- public function EventWidgetMove() {
53
  // Filter $_POST array for security.
54
  $post_array = filter_input_array( INPUT_POST );
55
 
@@ -59,7 +60,7 @@ class WSAL_Sensors_Widgets extends WSAL_AbstractSensor {
59
 
60
  if ( isset( $post_array ) && ! empty( $post_array['sidebars'] ) ) {
61
  $current_sidebars = $post_array['sidebars'];
62
- $sidebars = array();
63
  foreach ( $current_sidebars as $key => $val ) {
64
  $sb = array();
65
  if ( ! empty( $val ) ) {
@@ -74,15 +75,15 @@ class WSAL_Sensors_Widgets extends WSAL_AbstractSensor {
74
  $sidebars[ $key ] = $sb;
75
  }
76
  $current_sidebars = $sidebars;
77
- $db_sidebars = get_option( 'sidebars_widgets' );
78
- $widget_name = $from_sidebar = $to_sidebar = '';
79
  foreach ( $current_sidebars as $sidebar_name => $values ) {
80
  if ( is_array( $values ) && ! empty( $values ) && isset( $db_sidebars[ $sidebar_name ] ) ) {
81
  foreach ( $values as $widget_name ) {
82
- if ( ! in_array( $widget_name, $db_sidebars[ $sidebar_name ] ) ) {
83
  $to_sidebar = $sidebar_name;
84
  foreach ( $db_sidebars as $name => $v ) {
85
- if ( is_array( $v ) && ! empty( $v ) && in_array( $widget_name, $v ) ) {
86
  $from_sidebar = $name;
87
  continue;
88
  }
@@ -101,16 +102,18 @@ class WSAL_Sensors_Widgets extends WSAL_AbstractSensor {
101
  // as at this moment the $wp_registered_sidebars variable is not yet populated
102
  // so we cannot retrieve the name for sidebar-1 || sidebar-2
103
  // we will then check for this variable in the EventWidgetPostMove() event.
104
- $this->_widget_move_data = array(
105
  'widget' => $widget_name,
106
- 'from' => $from_sidebar,
107
- 'to' => $to_sidebar,
108
  );
 
109
  return;
110
  }
111
 
112
- $this->plugin->alerts->Trigger(
113
- 2045, array(
 
114
  'WidgetName' => $widget_name,
115
  'OldSidebar' => $from_sidebar,
116
  'NewSidebar' => $to_sidebar,
@@ -123,12 +126,12 @@ class WSAL_Sensors_Widgets extends WSAL_AbstractSensor {
123
  * Triggered when a user accesses the admin area.
124
  * Changed widget position or moved widget.
125
  */
126
- public function EventWidgetPostMove() {
127
  // Filter $_POST array for security.
128
  $post_array = filter_input_array( INPUT_POST );
129
 
130
  // #!-- generates the event 2071
131
- if ( isset( $post_array['action'] ) && ('widgets-order' == $post_array['action']) ) {
132
  if ( isset( $post_array['sidebars'] ) ) {
133
  // Get the sidebars from $post_array.
134
  $request_sidebars = array();
@@ -158,20 +161,21 @@ class WSAL_Sensors_Widgets extends WSAL_AbstractSensor {
158
  foreach ( $request_sidebars as $sidebar_name => $widgets ) {
159
  if ( isset( $sidebar_widgets[ $sidebar_name ] ) ) {
160
  foreach ( $sidebar_widgets[ $sidebar_name ] as $i => $widget_name ) {
161
- $index = array_search( $widget_name, $widgets );
162
  // Check to see whether or not the widget has been moved.
163
- if ( $i != $index ) {
164
  $sn = $sidebar_name;
165
  // Try to retrieve the real name of the sidebar, otherwise fall-back to id: $sidebar_name.
166
  if ( $wp_registered_sidebars && isset( $wp_registered_sidebars[ $sidebar_name ] ) ) {
167
  $sn = $wp_registered_sidebars[ $sidebar_name ]['name'];
168
  }
169
- $this->plugin->alerts->Trigger(
170
- 2071, array(
171
- 'WidgetName' => $widget_name,
 
172
  'OldPosition' => $i + 1,
173
  'NewPosition' => $index + 1,
174
- 'Sidebar' => $sn,
175
  )
176
  );
177
  }
@@ -182,29 +186,28 @@ class WSAL_Sensors_Widgets extends WSAL_AbstractSensor {
182
  }
183
  }
184
  // #!--
185
- if ( $this->_widget_move_data ) {
186
- $widget_name = $this->_widget_move_data['widget'];
187
- $from_sidebar = $this->_widget_move_data['from'];
188
- $to_sidebar = $this->_widget_move_data['to'];
189
 
190
  global $wp_registered_sidebars;
191
 
192
  if ( preg_match( '/^sidebar-/', $from_sidebar ) ) {
193
  $from_sidebar = isset( $wp_registered_sidebars[ $from_sidebar ] )
194
- ? $wp_registered_sidebars[ $from_sidebar ]['name']
195
- : $from_sidebar
196
- ;
197
  }
198
 
199
  if ( preg_match( '/^sidebar-/', $to_sidebar ) ) {
200
  $to_sidebar = isset( $wp_registered_sidebars[ $to_sidebar ] )
201
- ? $wp_registered_sidebars[ $to_sidebar ]['name']
202
- : $to_sidebar
203
- ;
204
  }
205
 
206
- $this->plugin->alerts->Trigger(
207
- 2045, array(
 
208
  'WidgetName' => $widget_name,
209
  'OldSidebar' => $from_sidebar,
210
  'NewSidebar' => $to_sidebar,
@@ -215,8 +218,10 @@ class WSAL_Sensors_Widgets extends WSAL_AbstractSensor {
215
 
216
  /**
217
  * Widgets Activity (added, modified, deleted).
 
 
218
  */
219
- public function EventWidgetActivity() {
220
  // Filter $_POST array for security.
221
  $post_array = filter_input_array( INPUT_POST );
222
 
@@ -229,32 +234,34 @@ class WSAL_Sensors_Widgets extends WSAL_AbstractSensor {
229
  }
230
 
231
  global $wp_registered_sidebars;
232
- $can_check_sidebar = (empty( $wp_registered_sidebars ) ? false : true);
233
 
234
  switch ( true ) {
235
  // Added widget.
236
- case isset( $post_array['add_new'] ) && 'multi' == $post_array['add_new']:
237
  $sidebar = isset( $post_array['sidebar'] ) ? $post_array['sidebar'] : null;
238
  if ( $can_check_sidebar && preg_match( '/^sidebar-/', $sidebar ) ) {
239
  $sidebar = $wp_registered_sidebars[ $sidebar ]['name'];
240
  }
241
- $this->plugin->alerts->Trigger(
242
- 2042, array(
 
243
  'WidgetName' => $post_array['id_base'],
244
- 'Sidebar' => $sidebar,
245
  )
246
  );
247
  break;
248
  // Deleted widget.
249
- case isset( $post_array['delete_widget'] ) && intval( $post_array['delete_widget'] ) == 1:
250
  $sidebar = isset( $post_array['sidebar'] ) ? $post_array['sidebar'] : null;
251
  if ( $can_check_sidebar && preg_match( '/^sidebar-/', $sidebar ) ) {
252
  $sidebar = $wp_registered_sidebars[ $sidebar ]['name'];
253
  }
254
- $this->plugin->alerts->Trigger(
255
- 2044, array(
 
256
  'WidgetName' => $post_array['id_base'],
257
- 'Sidebar' => $sidebar,
258
  )
259
  );
260
  break;
@@ -271,7 +278,7 @@ class WSAL_Sensors_Widgets extends WSAL_AbstractSensor {
271
  }
272
 
273
  $widget_name = $post_array['id_base'];
274
- $sidebar = isset( $post_array['sidebar'] ) ? $post_array['sidebar'] : null;
275
  $widget_data = isset( $post_array[ "widget-$widget_name" ][ $widget_id ] )
276
  ? $post_array[ "widget-$widget_name" ][ $widget_id ]
277
  : null;
@@ -287,28 +294,29 @@ class WSAL_Sensors_Widgets extends WSAL_AbstractSensor {
287
 
288
  // Transform 'on' -> 1.
289
  foreach ( $widget_data as $k => $v ) {
290
- if ( 'on' == $v ) {
291
  $widget_data[ $k ] = 1;
292
  }
293
  }
294
 
295
  // Compare - checks for any changes inside widgets.
296
- $diff = array_diff_assoc( $widget_data, $widget_db_data[ $widget_id ] );
297
  $count = count( $diff );
298
  if ( $count > 0 ) {
299
  if ( $can_check_sidebar && preg_match( '/^sidebar-/', $sidebar ) ) {
300
  $sidebar = $wp_registered_sidebars[ $sidebar ]['name'];
301
  }
302
- $this->plugin->alerts->Trigger(
303
- 2043, array(
 
304
  'WidgetName' => $widget_name,
305
- 'Sidebar' => $sidebar,
306
  )
307
  );
308
  }
309
  break;
310
  default:
311
- // fallback for any other cases would go here
312
  break;
313
  }
314
  }
4
  *
5
  * Widgets sensor class file.
6
  *
7
+ * @since 1.0.0
8
+ * @package wsal
9
+ * @subpackage sensors
10
  */
11
 
12
  // Exit if accessed directly.
23
  * 2045 User moved widget
24
  * 2071 User changed widget position
25
  *
26
+ * @package wsal
27
  * @subpackage sensors
28
  */
29
  class WSAL_Sensors_Widgets extends WSAL_AbstractSensor {
33
  *
34
  * @var array
35
  */
36
+ protected $widget_move_data = null;
37
 
38
  /**
39
+ * {@inheritDoc}
40
  */
41
+ public function hook_events() {
42
  if ( current_user_can( 'edit_theme_options' ) ) {
43
+ add_action( 'admin_init', array( $this, 'event_widget_move' ) );
44
+ add_action( 'admin_init', array( $this, 'event_widget_post_move' ) );
45
  }
46
+ add_action( 'sidebar_admin_setup', array( $this, 'event_widget_activity' ) );
47
  }
48
 
49
  /**
50
  * Triggered when a user accesses the admin area.
51
  * Moved widget.
52
  */
53
+ public function event_widget_move() {
54
  // Filter $_POST array for security.
55
  $post_array = filter_input_array( INPUT_POST );
56
 
60
 
61
  if ( isset( $post_array ) && ! empty( $post_array['sidebars'] ) ) {
62
  $current_sidebars = $post_array['sidebars'];
63
+ $sidebars = array();
64
  foreach ( $current_sidebars as $key => $val ) {
65
  $sb = array();
66
  if ( ! empty( $val ) ) {
75
  $sidebars[ $key ] = $sb;
76
  }
77
  $current_sidebars = $sidebars;
78
+ $db_sidebars = get_option( 'sidebars_widgets' );
79
+ $widget_name = $from_sidebar = $to_sidebar = ''; // phpcs:ignore Squiz.PHP.DisallowMultipleAssignments.Found
80
  foreach ( $current_sidebars as $sidebar_name => $values ) {
81
  if ( is_array( $values ) && ! empty( $values ) && isset( $db_sidebars[ $sidebar_name ] ) ) {
82
  foreach ( $values as $widget_name ) {
83
+ if ( ! in_array( $widget_name, $db_sidebars[ $sidebar_name ] ) ) { // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
84
  $to_sidebar = $sidebar_name;
85
  foreach ( $db_sidebars as $name => $v ) {
86
+ if ( is_array( $v ) && ! empty( $v ) && in_array( $widget_name, $v ) ) { // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
87
  $from_sidebar = $name;
88
  continue;
89
  }
102
  // as at this moment the $wp_registered_sidebars variable is not yet populated
103
  // so we cannot retrieve the name for sidebar-1 || sidebar-2
104
  // we will then check for this variable in the EventWidgetPostMove() event.
105
+ $this->widget_move_data = array(
106
  'widget' => $widget_name,
107
+ 'from' => $from_sidebar,
108
+ 'to' => $to_sidebar,
109
  );
110
+
111
  return;
112
  }
113
 
114
+ $this->plugin->alerts->trigger_event(
115
+ 2045,
116
+ array(
117
  'WidgetName' => $widget_name,
118
  'OldSidebar' => $from_sidebar,
119
  'NewSidebar' => $to_sidebar,
126
  * Triggered when a user accesses the admin area.
127
  * Changed widget position or moved widget.
128
  */
129
+ public function event_widget_post_move() {
130
  // Filter $_POST array for security.
131
  $post_array = filter_input_array( INPUT_POST );
132
 
133
  // #!-- generates the event 2071
134
+ if ( isset( $post_array['action'] ) && ( 'widgets-order' === $post_array['action'] ) ) {
135
  if ( isset( $post_array['sidebars'] ) ) {
136
  // Get the sidebars from $post_array.
137
  $request_sidebars = array();
161
  foreach ( $request_sidebars as $sidebar_name => $widgets ) {
162
  if ( isset( $sidebar_widgets[ $sidebar_name ] ) ) {
163
  foreach ( $sidebar_widgets[ $sidebar_name ] as $i => $widget_name ) {
164
+ $index = array_search( $widget_name, $widgets ); // phpcs:ignore
165
  // Check to see whether or not the widget has been moved.
166
+ if ( $i != $index ) { // phpcs:ignore
167
  $sn = $sidebar_name;
168
  // Try to retrieve the real name of the sidebar, otherwise fall-back to id: $sidebar_name.
169
  if ( $wp_registered_sidebars && isset( $wp_registered_sidebars[ $sidebar_name ] ) ) {
170
  $sn = $wp_registered_sidebars[ $sidebar_name ]['name'];
171
  }
172
+ $this->plugin->alerts->trigger_event(
173
+ 2071,
174
+ array(
175
+ 'WidgetName' => $widget_name,
176
  'OldPosition' => $i + 1,
177
  'NewPosition' => $index + 1,
178
+ 'Sidebar' => $sn,
179
  )
180
  );
181
  }
186
  }
187
  }
188
  // #!--
189
+ if ( $this->widget_move_data ) {
190
+ $widget_name = $this->widget_move_data['widget'];
191
+ $from_sidebar = $this->widget_move_data['from'];
192
+ $to_sidebar = $this->widget_move_data['to'];
193
 
194
  global $wp_registered_sidebars;
195
 
196
  if ( preg_match( '/^sidebar-/', $from_sidebar ) ) {
197
  $from_sidebar = isset( $wp_registered_sidebars[ $from_sidebar ] )
198
+ ? $wp_registered_sidebars[ $from_sidebar ]['name']
199
+ : $from_sidebar;
 
200
  }
201
 
202
  if ( preg_match( '/^sidebar-/', $to_sidebar ) ) {
203
  $to_sidebar = isset( $wp_registered_sidebars[ $to_sidebar ] )
204
+ ? $wp_registered_sidebars[ $to_sidebar ]['name']
205
+ : $to_sidebar;
 
206
  }
207
 
208
+ $this->plugin->alerts->trigger_event(
209
+ 2045,
210
+ array(
211
  'WidgetName' => $widget_name,
212
  'OldSidebar' => $from_sidebar,
213
  'NewSidebar' => $to_sidebar,
218
 
219
  /**
220
  * Widgets Activity (added, modified, deleted).
221
+ *
222
+ * phpcs:disable WordPress.Arrays.ArrayKeySpacingRestrictions.NoSpacesAroundArrayKeys
223
  */
224
+ public function event_widget_activity() {
225
  // Filter $_POST array for security.
226
  $post_array = filter_input_array( INPUT_POST );
227
 
234
  }
235
 
236
  global $wp_registered_sidebars;
237
+ $can_check_sidebar = ! empty( $wp_registered_sidebars );
238
 
239
  switch ( true ) {
240
  // Added widget.
241
+ case isset( $post_array['add_new'] ) && 'multi' === $post_array['add_new']:
242
  $sidebar = isset( $post_array['sidebar'] ) ? $post_array['sidebar'] : null;
243
  if ( $can_check_sidebar && preg_match( '/^sidebar-/', $sidebar ) ) {
244
  $sidebar = $wp_registered_sidebars[ $sidebar ]['name'];
245
  }
246
+ $this->plugin->alerts->trigger_event(
247
+ 2042,
248
+ array(
249
  'WidgetName' => $post_array['id_base'],
250
+ 'Sidebar' => $sidebar,
251
  )
252
  );
253
  break;
254
  // Deleted widget.
255
+ case isset( $post_array['delete_widget'] ) && 1 === intval( $post_array['delete_widget'] ):
256
  $sidebar = isset( $post_array['sidebar'] ) ? $post_array['sidebar'] : null;
257
  if ( $can_check_sidebar && preg_match( '/^sidebar-/', $sidebar ) ) {
258
  $sidebar = $wp_registered_sidebars[ $sidebar ]['name'];
259
  }
260
+ $this->plugin->alerts->trigger_event(
261
+ 2044,
262
+ array(
263
  'WidgetName' => $post_array['id_base'],
264
+ 'Sidebar' => $sidebar,
265
  )
266
  );
267
  break;
278
  }
279
 
280
  $widget_name = $post_array['id_base'];
281
+ $sidebar = isset( $post_array['sidebar'] ) ? $post_array['sidebar'] : null;
282
  $widget_data = isset( $post_array[ "widget-$widget_name" ][ $widget_id ] )
283
  ? $post_array[ "widget-$widget_name" ][ $widget_id ]
284
  : null;
294
 
295
  // Transform 'on' -> 1.
296
  foreach ( $widget_data as $k => $v ) {
297
+ if ( 'on' === $v ) {
298
  $widget_data[ $k ] = 1;
299
  }
300
  }
301
 
302
  // Compare - checks for any changes inside widgets.
303
+ $diff = array_diff_assoc( $widget_data, $widget_db_data[ $widget_id ] );
304
  $count = count( $diff );
305
  if ( $count > 0 ) {
306
  if ( $can_check_sidebar && preg_match( '/^sidebar-/', $sidebar ) ) {
307
  $sidebar = $wp_registered_sidebars[ $sidebar ]['name'];
308
  }
309
+ $this->plugin->alerts->trigger_event(
310
+ 2043,
311
+ array(
312
  'WidgetName' => $widget_name,
313
+ 'Sidebar' => $sidebar,
314
  )
315
  );
316
  }
317
  break;
318
  default:
319
+ // Fallback for any other cases would go here.
320
  break;
321
  }
322
  }
classes/Settings.php CHANGED
@@ -31,7 +31,7 @@ class WSAL_Settings {
31
  *
32
  * @var WpSecurityAuditLog
33
  */
34
- protected $_plugin;
35
 
36
  const ERROR_CODE_INVALID_IP = 901;
37
 
@@ -47,70 +47,70 @@ class WSAL_Settings {
47
  *
48
  * @var string
49
  */
50
- protected $_pruning = 0;
51
 
52
  /**
53
  * IDs of disabled alerts.
54
  *
55
  * @var array
56
  */
57
- protected $_disabled = null;
58
 
59
  /**
60
  * Allowed Plugin Viewers.
61
  *
62
  * @var array
63
  */
64
- protected $_viewers = null;
65
 
66
  /**
67
  * Alerts per page.
68
  *
69
  * @var int
70
  */
71
- protected $_perpage = null;
72
 
73
  /**
74
  * Users excluded from monitoring.
75
  *
76
  * @var array
77
  */
78
- protected $_excluded_users = array();
79
 
80
  /**
81
  * Roles excluded from monitoring.
82
  *
83
  * @var array
84
  */
85
- protected $_excluded_roles = array();
86
 
87
  /**
88
  * Custom post meta fields excluded from monitoring.
89
  *
90
  * @var array
91
  */
92
- protected $_excluded_post_meta = array();
93
 
94
  /**
95
  * Custom user meta fields excluded from monitoring.
96
  *
97
  * @var array
98
  */
99
- protected $_excluded_user_meta = array();
100
 
101
  /**
102
  * Custom Post Types excluded from monitoring.
103
  *
104
  * @var array
105
  */
106
- protected $_post_types = array();
107
 
108
  /**
109
  * IP excluded from monitoring.
110
  *
111
  * @var array
112
  */
113
- protected $_excluded_ip = array();
114
 
115
  /**
116
  * Alerts enabled in Geek mode.
@@ -140,10 +140,10 @@ class WSAL_Settings {
140
  * @param WpSecurityAuditLog $plugin - Instance of WpSecurityAuditLog.
141
  */
142
  public function __construct( WpSecurityAuditLog $plugin ) {
143
- $this->_plugin = $plugin;
144
  // some settings here may be called before the options helper is setup.
145
- if ( ! isset( $this->_plugin->options_helper ) ) {
146
- $this->_plugin->include_options_helper();
147
  }
148
  add_action( 'deactivated_plugin', array( $this, 'reset_stealth_mode' ), 10, 1 );
149
  }
@@ -154,14 +154,14 @@ class WSAL_Settings {
154
  */
155
  public function set_basic_mode() {
156
  // Disable alerts of geek mode and alerts to be always disabled.
157
- $this->SetDisabledAlerts( array_merge( $this->geek_alerts, $this->always_disabled_alerts ) );
158
  }
159
 
160
  /**
161
  * Enable Geek Mode.
162
  */
163
  public function set_geek_mode() {
164
- $this->SetDisabledAlerts( $this->always_disabled_alerts ); // Disable alerts to be always disabled.
165
  }
166
 
167
 
@@ -170,8 +170,8 @@ class WSAL_Settings {
170
  *
171
  * @return boolean
172
  */
173
- public function IsWidgetsEnabled() {
174
- return ! $this->_plugin->GetGlobalBooleanSetting( 'disable-widgets' );
175
  }
176
 
177
  /**
@@ -179,8 +179,8 @@ class WSAL_Settings {
179
  *
180
  * @param boolean $newvalue - True if enabled.
181
  */
182
- public function SetWidgetsEnabled( $newvalue ) {
183
- $this->_plugin->SetGlobalBooleanSetting( 'disable-widgets', ! $newvalue );
184
  }
185
 
186
  /**
@@ -191,7 +191,7 @@ class WSAL_Settings {
191
  * @return boolean
192
  */
193
  public function is_admin_bar_notif() {
194
- return ! $this->_plugin->GetGlobalBooleanSetting( 'disable-admin-bar-notif', true );
195
  }
196
 
197
  /**
@@ -202,7 +202,7 @@ class WSAL_Settings {
202
  * @param boolean $newvalue - True if enabled.
203
  */
204
  public function set_admin_bar_notif( $newvalue ) {
205
- $this->_plugin->SetGlobalBooleanSetting( 'disable-admin-bar-notif', ! $newvalue, true );
206
  }
207
 
208
  /**
@@ -213,7 +213,7 @@ class WSAL_Settings {
213
  * @return string
214
  */
215
  public function get_admin_bar_notif_updates() {
216
- return $this->_plugin->GetGlobalSetting( 'admin-bar-notif-updates', 'page-refresh' );
217
  }
218
 
219
  /**
@@ -224,7 +224,7 @@ class WSAL_Settings {
224
  * @param string $newvalue - New option value.
225
  */
226
  public function set_admin_bar_notif_updates( $newvalue ) {
227
- $this->_plugin->SetGlobalSetting( 'admin-bar-notif-updates', $newvalue, true );
228
  }
229
 
230
  /**
@@ -232,8 +232,8 @@ class WSAL_Settings {
232
  *
233
  * @return boolean
234
  */
235
- public function IsRefreshAlertsEnabled() {
236
- return ! $this->_plugin->GetGlobalSetting( 'disable-refresh' );
237
  }
238
 
239
  /**
@@ -241,8 +241,8 @@ class WSAL_Settings {
241
  *
242
  * @param boolean $newvalue - True if enabled.
243
  */
244
- public function SetRefreshAlertsEnabled( $newvalue ) {
245
- $this->_plugin->SetGlobalSetting( 'disable-refresh', ! $newvalue );
246
  }
247
 
248
  /**
@@ -250,7 +250,7 @@ class WSAL_Settings {
250
  *
251
  * @return int
252
  */
253
- public function GetDashboardWidgetMaxAlerts() {
254
  return 5;
255
  }
256
 
@@ -259,7 +259,7 @@ class WSAL_Settings {
259
  *
260
  * @return int
261
  */
262
- public function GetMaxAllowedAlerts() {
263
  return 5000;
264
  }
265
 
@@ -268,7 +268,7 @@ class WSAL_Settings {
268
  *
269
  * @return string
270
  */
271
- public function GetDefaultPruningDate() {
272
  return '6 months';
273
  }
274
 
@@ -277,14 +277,14 @@ class WSAL_Settings {
277
  *
278
  * @return string
279
  */
280
- public function GetPruningDate() {
281
- if ( ! $this->_pruning ) {
282
- $this->_pruning = $this->_plugin->GetGlobalSetting( 'pruning-date' );
283
- if ( ! strtotime( $this->_pruning ) ) {
284
- $this->_pruning = $this->GetDefaultPruningDate();
285
  }
286
  }
287
- return $this->_pruning;
288
  }
289
 
290
  /**
@@ -292,10 +292,10 @@ class WSAL_Settings {
292
  *
293
  * @param string $newvalue - The new pruning date.
294
  */
295
- public function SetPruningDate( $newvalue ) {
296
  if ( strtotime( $newvalue ) ) {
297
- $this->_plugin->SetGlobalSetting( 'pruning-date', $newvalue );
298
- $this->_pruning = $newvalue;
299
  }
300
  }
301
 
@@ -305,7 +305,7 @@ class WSAL_Settings {
305
  * @return string
306
  */
307
  public function get_pruning_unit() {
308
- return $this->_plugin->GetGlobalSetting( 'pruning-unit', 'months' );
309
  }
310
 
311
  /**
@@ -314,7 +314,7 @@ class WSAL_Settings {
314
  * @param string $newvalue – New value of pruning unit.
315
  */
316
  public function set_pruning_unit( $newvalue ) {
317
- $this->_plugin->SetGlobalSetting( 'pruning-unit', $newvalue );
318
  }
319
 
320
  /**
@@ -322,9 +322,9 @@ class WSAL_Settings {
322
  *
323
  * @return integer
324
  */
325
- public function GetPruningLimit() {
326
- $val = (int) $this->_plugin->GetGlobalSetting( 'pruning-limit' );
327
- return $val ? $val : $this->GetMaxAllowedAlerts();
328
  }
329
 
330
  /**
@@ -332,37 +332,56 @@ class WSAL_Settings {
332
  *
333
  * @param integer $newvalue - The new maximum number of alerts.
334
  */
335
- public function SetPruningLimit( $newvalue ) {
336
- $newvalue = max( /*min(*/ (int) $newvalue/*, $this->GetMaxAllowedAlerts())*/, 1 );
337
- $this->_plugin->SetGlobalSetting( 'pruning-limit', $newvalue );
338
  }
339
 
340
- public function SetPruningDateEnabled( $enabled ) {
 
 
 
 
 
341
 
342
- $old_setting = $this->_plugin->GetGlobalBooleanSetting( 'pruning-date-e', false );
343
- $enable = \WSAL\Helpers\Options::string_to_bool( $enabled );
344
  if ( $old_setting !== $enable ) {
345
- $event_id = 6052;
346
- $alert_data = [
347
- 'new_setting' => ( $enable ) ? 'Delete events older than ' . $this->_pruning = $this->_plugin->GetGlobalSetting( 'pruning-date' ) . ' ' . $this->_plugin->GetGlobalSetting( 'pruning-unit', 'months' ) : 'Keep all data',
348
- 'previous_setting' => ( $old_setting ) ? 'Delete events older than ' . $this->_pruning = $this->_plugin->GetGlobalSetting( 'pruning-date' ) . ' ' . $this->_plugin->GetGlobalSetting( 'pruning-unit', 'months' ) : 'Keep all data',
349
- ];
350
- $this->_plugin->alerts->Trigger( $event_id, $alert_data );
351
  }
352
 
353
- $this->_plugin->SetGlobalBooleanSetting( 'pruning-date-e', $enabled );
354
  }
355
 
356
- public function SetPruningLimitEnabled( $enabled ) {
357
- $this->_plugin->SetGlobalBooleanSetting( 'pruning-limit-e', $enabled );
 
 
 
 
 
358
  }
359
 
360
- public function IsPruningDateEnabled() {
361
- return $this->_plugin->GetGlobalBooleanSetting( 'pruning-date-e' );
 
 
 
 
 
362
  }
363
 
364
- public function IsPruningLimitEnabled() {
365
- return $this->_plugin->GetGlobalBooleanSetting( 'pruning-limit-e' );
 
 
 
 
 
366
  }
367
 
368
  /**
@@ -380,17 +399,17 @@ class WSAL_Settings {
380
  * @param bool $enable - Enable/Disable.
381
  */
382
  public function set_login_page_notification( $enable ) {
383
- //Only trigger an event if an actual changes is made.
384
- $old_setting = $this->_plugin->GetGlobalBooleanSetting( 'login_page_notification', false );
385
- $enable = \WSAL\Helpers\Options::string_to_bool( $enable );
386
  if ( $old_setting !== $enable ) {
387
- $event_id = 6046;
388
- $alert_data = [
389
  'EventType' => ( $enable ) ? 'enabled' : 'disabled',
390
- ];
391
- $this->_plugin->alerts->Trigger( $event_id, $alert_data );
392
  }
393
- $this->_plugin->SetGlobalBooleanSetting( 'login_page_notification', $enable );
394
  }
395
 
396
  /**
@@ -399,7 +418,7 @@ class WSAL_Settings {
399
  * @return bool - True if set, false if not.
400
  */
401
  public function is_login_page_notification() {
402
- return $this->_plugin->GetGlobalBooleanSetting( 'login_page_notification', false );
403
  }
404
 
405
  /**
@@ -408,12 +427,12 @@ class WSAL_Settings {
408
  * @param string $text - Login Page Notification Text.
409
  */
410
  public function set_login_page_notification_text( $text ) {
411
- $text = wp_kses( $text, $this->_plugin->allowed_html_tags );
412
- $old_setting = $this->_plugin->GetGlobalSetting( 'login_page_notification_text' );
413
  if ( ! empty( $old_setting ) && ! empty( $text ) && ! is_null( $old_setting ) && $old_setting !== $text ) {
414
- $this->_plugin->alerts->Trigger( 6047 );
415
  }
416
- $this->_plugin->SetGlobalSetting( 'login_page_notification_text', $text );
417
  }
418
 
419
  /**
@@ -422,10 +441,15 @@ class WSAL_Settings {
422
  * @return string|bool - Text if set, false if not.
423
  */
424
  public function get_login_page_notification_text() {
425
- return $this->_plugin->GetGlobalSetting( 'login_page_notification_text', false );
426
  }
427
 
428
- public function GetDefaultDisabledAlerts() {
 
 
 
 
 
429
  return array( 0000, 0001, 0002, 0003, 0004, 0005 );
430
  }
431
 
@@ -434,14 +458,14 @@ class WSAL_Settings {
434
  *
435
  * @return array
436
  */
437
- public function GetDisabledAlerts() {
438
- if ( ! $this->_disabled ) {
439
- $this->_disabled = implode( ',', $this->GetDefaultDisabledAlerts() );
440
- $this->_disabled = $this->_plugin->GetGlobalSetting( 'disabled-alerts', $this->_disabled );
441
- $this->_disabled = ( '' == $this->_disabled ) ? array() : explode( ',', $this->_disabled );
442
- $this->_disabled = array_map( 'intval', $this->_disabled );
443
  }
444
- return $this->_disabled;
445
  }
446
 
447
  /**
@@ -449,48 +473,52 @@ class WSAL_Settings {
449
  *
450
  * @param array $types IDs alerts to disable.
451
  */
452
- public function SetDisabledAlerts( $types ) {
453
- $this->_disabled = array_unique( array_map( 'intval', $types ) );
454
- $this->_plugin->SetGlobalSetting( 'disabled-alerts', implode( ',', $this->_disabled ) );
455
  }
456
 
457
  /**
 
 
458
  * @return bool
459
  */
460
- public function IsIncognito() {
461
- return $this->_plugin->GetGlobalBooleanSetting( 'hide-plugin' );
462
  }
463
 
464
  /**
465
- * @param bool $enabled
 
 
466
  */
467
- public function SetIncognito( $enabled ) {
468
- $old_value = $this->_plugin->GetGlobalSetting( 'hide-plugin' );
469
- $old_value = ( $old_value === "yes" ) ? true : false;
470
  if ( $old_value !== $enabled ) {
471
- $alert_data = [
472
  'EventType' => ( $enabled ) ? 'enabled' : 'disabled',
473
- ];
474
- $this->_plugin->alerts->Trigger( 6051, $alert_data );
475
  }
476
 
477
- $this->_plugin->SetGlobalBooleanSetting( 'hide-plugin', $enabled );
478
  }
479
 
480
  /**
481
  * Checking if the data will be removed.
482
  */
483
- public function IsDeleteData() {
484
- return $this->_plugin->GetGlobalBooleanSetting( 'delete-data' );
485
  }
486
 
487
  /**
488
  * Sets the plugin setting that allows data deletion on plugin uninstall.
489
  *
490
- * @param mixed $enabled
491
  */
492
- public function SetDeleteData( $enabled ) {
493
- $this->_plugin->SetGlobalBooleanSetting( 'delete-data', $enabled );
494
  }
495
 
496
  /**
@@ -498,14 +526,14 @@ class WSAL_Settings {
498
  *
499
  * @param array $users_or_roles – Users/Roles.
500
  */
501
- public function SetAllowedPluginViewers( $users_or_roles ) {
502
 
503
- $old_value = $this->_plugin->GetGlobalSetting( 'plugin-viewers' );
504
- $changes = $this->determine_added_and_removed_items( $old_value, implode( ',', $users_or_roles ) );
505
 
506
- if ( ! empty( $changes[ 'added' ] ) ) {
507
- foreach ( $changes[ 'added' ] as $user ) {
508
- $this->_plugin->alerts->Trigger(
509
  6050,
510
  array(
511
  'user' => $user,
@@ -516,14 +544,14 @@ class WSAL_Settings {
516
  }
517
  }
518
 
519
- if ( ! empty( $changes[ 'removed' ] ) && ! empty( $old_value ) ) {
520
- foreach ( $changes[ 'removed' ] as $user ) {
521
  if ( ! empty( $user ) ) {
522
- $this->_plugin->alerts->Trigger(
523
  6050,
524
  array(
525
  'user' => $user,
526
- 'previous_users' => ( empty( $old_value ) ) ? $this->tidy_blank_values( $old_value ) : str_replace( ',', ', ', $old_value ),
527
  'EventType' => 'removed',
528
  )
529
  );
@@ -531,19 +559,20 @@ class WSAL_Settings {
531
  }
532
  }
533
 
534
-
535
- $this->_viewers = $users_or_roles;
536
- $this->_plugin->SetGlobalSetting( 'plugin-viewers', implode( ',', $this->_viewers ), true );
537
  }
538
 
539
  /**
540
  * Get Plugin Viewers.
 
 
541
  */
542
- public function GetAllowedPluginViewers() {
543
- if ( is_null( $this->_viewers ) ) {
544
- $this->_viewers = array_unique( array_filter( explode( ',', $this->_plugin->GetGlobalSetting( 'plugin-viewers' ) ) ) );
545
  }
546
- return $this->_viewers;
547
  }
548
 
549
  /**
@@ -553,17 +582,17 @@ class WSAL_Settings {
553
  * @since 3.2.3
554
  */
555
  public function set_restrict_plugin_setting( $setting ) {
556
- $old_value = $this->_plugin->GetGlobalSetting( 'restrict-plugin-settings', 'only_admins' );
557
 
558
  if ( ! is_null( $old_value ) && $old_value !== $setting ) {
559
- $alert_data = [
560
- 'new_setting' => ucfirst( str_replace( '_', ' ', $setting ) ),
561
- 'previous_setting' => ucfirst( str_replace( '_', ' ', $old_value ) ),
562
- ];
563
- $this->_plugin->alerts->Trigger( 6049, $alert_data );
564
  }
565
 
566
- $this->_plugin->SetGlobalSetting( 'restrict-plugin-settings', $setting, true );
567
  }
568
 
569
  /**
@@ -572,7 +601,7 @@ class WSAL_Settings {
572
  * @since 3.2.3
573
  */
574
  public function get_restrict_plugin_setting() {
575
- return $this->_plugin->GetGlobalSetting( 'restrict-plugin-settings', 'only_admins' );
576
  }
577
 
578
  /**
@@ -581,7 +610,7 @@ class WSAL_Settings {
581
  * @since 4.1.3
582
  */
583
  public function get_restrict_log_viewer() {
584
- return $this->_plugin->GetGlobalSetting( 'restrict-log-viewer', 'only_admins' );
585
  }
586
 
587
  /**
@@ -591,19 +620,29 @@ class WSAL_Settings {
591
  * @since 4.1.3
592
  */
593
  public function set_restrict_log_viewer( $setting ) {
594
- $this->_plugin->SetGlobalSetting( 'restrict-log-viewer', $setting, true );
595
  }
596
 
597
- public function SetViewPerPage( $newvalue ) {
598
- $this->_perpage = max( $newvalue, 1 );
599
- $this->_plugin->SetGlobalSetting( 'items-per-page', $this->_perpage );
 
 
 
 
 
600
  }
601
 
602
- public function GetViewPerPage() {
603
- if ( is_null( $this->_perpage ) ) {
604
- $this->_perpage = (int) $this->_plugin->GetGlobalSetting( 'items-per-page', 10 );
 
 
 
 
 
605
  }
606
- return $this->_perpage;
607
  }
608
 
609
  /**
@@ -612,8 +651,8 @@ class WSAL_Settings {
612
  * @param string $action Type of action, either 'view' or 'edit'.
613
  * @return boolean If user has access or not.
614
  */
615
- public function CurrentUserCan( $action ) {
616
- return $this->UserCan( wp_get_current_user(), $action );
617
  }
618
 
619
  /**
@@ -621,8 +660,8 @@ class WSAL_Settings {
621
  *
622
  * @return array
623
  */
624
- protected function GetSuperAdmins() {
625
- return $this->_plugin->IsMultisite() ? get_super_admins() : array();
626
  }
627
 
628
  /**
@@ -630,8 +669,8 @@ class WSAL_Settings {
630
  *
631
  * @return string[]
632
  */
633
- protected function GetAdmins() {
634
- if ( $this->_plugin->IsMultisite() ) {
635
  if ( empty( $this->site_admins ) ) {
636
  /**
637
  * Get list of admins.
@@ -647,7 +686,7 @@ class WSAL_Settings {
647
  . " AND CAST($wpdb->usermeta.meta_value AS CHAR) LIKE '%\"administrator\"%'";
648
 
649
  // Get admins.
650
- $this->site_admins = $wpdb->get_col( $sql );
651
  }
652
  } else {
653
  if ( empty( $this->site_admins ) ) {
@@ -667,61 +706,61 @@ class WSAL_Settings {
667
  * @param string $action - Type of action, either 'view' or 'edit'.
668
  * @return boolean If user has access or not.
669
  */
670
- public function UserCan( $user, $action ) {
671
  if ( is_int( $user ) ) {
672
  $user = get_userdata( $user );
673
  }
674
 
675
- // by default the user has no privileges
676
  $result = false;
677
 
678
- $is_multisite = $this->_plugin->IsMultisite();
679
  switch ( $action ) {
680
  case 'view':
681
  if ( ! $is_multisite ) {
682
- // non-multisite piggybacks on the plugin settings access
683
  switch ( $this->get_restrict_plugin_setting() ) {
684
  case 'only_admins':
685
- // allow access only if the user is and admin
686
- $result = in_array( 'administrator', $user->roles );
687
  break;
688
  case 'only_me':
689
- // allow access only if the user matches the only user allowed access
690
- $result = $user->ID == $this->get_only_me_user_id();
691
  break;
692
  default:
693
- // no other options to allow access here
694
  $result = false;
695
  }
696
  } else {
697
- // multisite MUST respect the log viewer restriction settings plus also additional users and roles
698
- // defined in the extra option
699
  switch ( $this->get_restrict_log_viewer() ) {
700
  case 'only_me':
701
- // allow access only if the user matches the only user allowed access
702
- $result = ( $user->ID == $this->get_only_me_user_id() );
703
  break;
704
  case 'only_superadmins':
705
- // allow access only for super admins
706
  if ( function_exists( 'is_super_admin' ) && is_super_admin( $user->ID ) ) {
707
  $result = true;
708
  }
709
  break;
710
  case 'only_admins':
711
- // allow access only for super admins and admins
712
- $result = in_array( 'administrator', $user->roles ) || ( function_exists( 'is_super_admin' ) && is_super_admin( $user->ID ) );
713
  break;
714
  default:
715
- // fallback for any other cases would go here
716
  break;
717
  }
718
  }
719
 
720
  if ( ! $result ) {
721
- // user is still not allowed to view the logs, let's check the additional users and roles
722
- // settings
723
- $extra_viewers = $this->GetAllowedPluginViewers();
724
- if ( in_array( $user->user_login, $extra_viewers ) ) {
725
  $result = true;
726
  } elseif ( ! empty( array_intersect( $extra_viewers, $user->roles ) ) ) {
727
  $result = true;
@@ -730,9 +769,9 @@ class WSAL_Settings {
730
  break;
731
  case 'edit':
732
  if ( $is_multisite ) {
733
- // no one has access to settings on sub site inside a network
734
  if ( wp_doing_ajax() ) {
735
- // AJAX calls are an exception
736
  $result = true;
737
  } elseif ( ! is_network_admin() ) {
738
  $result = false;
@@ -742,12 +781,12 @@ class WSAL_Settings {
742
 
743
  $restrict_plugin_setting = $this->get_restrict_plugin_setting();
744
  if ( 'only_me' === $restrict_plugin_setting ) {
745
- $result = ( $user->ID == $this->get_only_me_user_id() );
746
  } elseif ( 'only_admins' === $restrict_plugin_setting ) {
747
  if ( $is_multisite ) {
748
  $result = ( function_exists( 'is_super_admin' ) && is_super_admin( $user->ID ) );
749
  } else {
750
- $result = in_array( 'administrator', $user->roles );
751
  }
752
  }
753
  break;
@@ -768,8 +807,15 @@ class WSAL_Settings {
768
  return apply_filters( 'wsal_user_can', $result, $user, $action );
769
  }
770
 
771
- public function GetCurrentUserRoles( $base_roles = null ) {
772
- if ( null == $base_roles ) {
 
 
 
 
 
 
 
773
  $base_roles = wp_get_current_user()->roles;
774
  }
775
  if ( is_multisite() && function_exists( 'is_super_admin' ) && is_super_admin() ) {
@@ -778,33 +824,60 @@ class WSAL_Settings {
778
  return $base_roles;
779
  }
780
 
781
- public function IsLoginSuperAdmin( $username ) {
 
 
 
 
 
 
 
782
  $user_id = username_exists( $username );
783
  return function_exists( 'is_super_admin' ) && is_super_admin( $user_id );
784
  }
785
 
786
- public function IsMainIPFromProxy() {
787
- return $this->_plugin->GetGlobalBooleanSetting( 'use-proxy-ip' );
 
 
 
 
 
788
  }
789
 
790
- public function SetMainIPFromProxy( $enabled ) {
791
- $old_value = $this->_plugin->GetGlobalBooleanSetting( 'use-proxy-ip' );
792
- $enabled = \WSAL\Helpers\Options::string_to_bool( $enabled );
 
 
 
 
 
793
  if ( $old_value !== $enabled ) {
794
- $alert_data = [
795
  'EventType' => ( $enabled ) ? 'enabled' : 'disabled',
796
- ];
797
- $this->_plugin->alerts->Trigger( 6048, $alert_data );
798
  }
799
- $this->_plugin->SetGlobalBooleanSetting( 'use-proxy-ip', $enabled );
800
  }
801
 
802
- public function IsInternalIPsFiltered() {
803
- return $this->_plugin->GetGlobalSetting( 'filter-internal-ip' );
 
 
 
 
 
804
  }
805
 
806
- public function SetInternalIPsFiltering( $enabled ) {
807
- $this->_plugin->SetGlobalSetting( 'filter-internal-ip', $enabled );
 
 
 
 
 
808
  }
809
 
810
  /**
@@ -812,19 +885,19 @@ class WSAL_Settings {
812
  *
813
  * @return string|null
814
  */
815
- public function GetMainClientIP() {
816
  $result = null;
817
 
818
- if ( $this->IsMainIPFromProxy() ) {
819
  // TODO: The algorithm below just gets the first IP in the list...we might want to make this more intelligent somehow.
820
- $result = $this->GetClientIPs();
821
  $result = reset( $result );
822
  $result = isset( $result[0] ) ? $result[0] : null;
823
  } elseif ( isset( $_SERVER['REMOTE_ADDR'] ) ) {
824
  $ip = sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) );
825
- $result = $this->NormalizeIP( $ip );
826
 
827
- if ( ! $this->ValidateIP( $result ) ) {
828
  $result = 'Error ' . self::ERROR_CODE_INVALID_IP . ': Invalid IP Address';
829
  }
830
  }
@@ -837,7 +910,7 @@ class WSAL_Settings {
837
  *
838
  * @return array
839
  */
840
- public function GetClientIPs() {
841
  $ips = array();
842
 
843
  $proxy_headers = array(
@@ -849,18 +922,17 @@ class WSAL_Settings {
849
  'HTTP_FORWARDED_FOR',
850
  'HTTP_FORWARDED',
851
  'REMOTE_ADDR',
852
- // Cloudflare
853
  'HTTP_CF-Connecting-IP',
854
- 'HTTP_TRUE_CLIENT_IP'
855
  );
856
  foreach ( $proxy_headers as $key ) {
857
  if ( isset( $_SERVER[ $key ] ) ) {
858
  $ips[ $key ] = array();
859
 
860
- foreach ( explode( ',', $_SERVER[ $key ] ) as $ip ) {
861
- $ip = $this->NormalizeIP( $ip );
862
-
863
- if ( $this->ValidateIP( $ip ) ) {
864
  $ips[ $key ][] = $ip;
865
  }
866
  }
@@ -875,8 +947,10 @@ class WSAL_Settings {
875
  *
876
  * @param string $ip - IP address.
877
  * @return string
 
 
878
  */
879
- protected function NormalizeIP( $ip ) {
880
  $ip = trim( $ip );
881
 
882
  if ( strpos( $ip, ':' ) !== false && substr_count( $ip, '.' ) === 3 && strpos( $ip, '[' ) === false ) {
@@ -898,10 +972,10 @@ class WSAL_Settings {
898
  * @param string $ip - IP address.
899
  * @return string|bool
900
  */
901
- protected function ValidateIP( $ip ) {
902
  $opts = FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6;
903
 
904
- if ( $this->IsInternalIPsFiltered() ) {
905
  $opts = $opts | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE;
906
  }
907
 
@@ -923,16 +997,18 @@ class WSAL_Settings {
923
  }
924
 
925
  /**
926
- * Users excluded from monitoring.
 
 
927
  */
928
- public function SetExcludedMonitoringUsers( $users ) {
929
 
930
- $old_value = $this->_plugin->GetGlobalSetting( 'excluded-users', [] );
931
- $changes = $this->determine_added_and_removed_items( $old_value, implode( ',', $users ) );
932
 
933
- if ( ! empty( $changes[ 'added' ] ) ) {
934
- foreach ( $changes[ 'added' ] as $user ) {
935
- $this->_plugin->alerts->Trigger(
936
  6053,
937
  array(
938
  'user' => $user,
@@ -942,28 +1018,33 @@ class WSAL_Settings {
942
  );
943
  }
944
  }
945
- if ( ! empty( $changes[ 'removed' ] ) && ! empty( $old_value ) ) {
946
- foreach ( $changes[ 'removed' ] as $user ) {
947
- $this->_plugin->alerts->Trigger(
948
  6053,
949
  array(
950
  'user' => $user,
951
- 'previous_users' => ( empty( $old_value ) ) ? $this->tidy_blank_values( $old_value ) : str_replace( ',', ', ', $old_value ),
952
  'EventType' => 'removed',
953
  )
954
  );
955
  }
956
  }
957
 
958
- $this->_excluded_users = $users;
959
- $this->_plugin->SetGlobalSetting( 'excluded-users', esc_html( implode( ',', $this->_excluded_users ) ) );
960
  }
961
 
962
- public function GetExcludedMonitoringUsers() {
963
- if ( empty( $this->_excluded_users ) ) {
964
- $this->_excluded_users = array_unique( array_filter( explode( ',', $this->_plugin->GetGlobalSetting( 'excluded-users' ) ) ) );
 
 
 
 
 
965
  }
966
- return $this->_excluded_users;
967
  }
968
 
969
  /**
@@ -974,12 +1055,12 @@ class WSAL_Settings {
974
  */
975
  public function set_excluded_post_types( $post_types ) {
976
 
977
- $old_value = $this->_plugin->GetGlobalSetting( 'custom-post-types', [] );
978
- $changes = $this->determine_added_and_removed_items( $old_value, implode( ',', $post_types ) );
979
 
980
- if ( ! empty( $changes[ 'added' ] ) ) {
981
- foreach ( $changes[ 'added' ] as $post_type ) {
982
- $this->_plugin->alerts->Trigger(
983
  6056,
984
  array(
985
  'post_type' => $post_type,
@@ -990,21 +1071,21 @@ class WSAL_Settings {
990
  }
991
  }
992
 
993
- if ( ! empty( $changes[ 'removed' ] ) && ! empty( $old_value ) ) {
994
- foreach ( $changes[ 'removed' ] as $post_type ) {
995
- $this->_plugin->alerts->Trigger(
996
  6056,
997
  array(
998
  'post_type' => $post_type,
999
- 'previous_types' => ( empty( $old_value ) ) ? $this->tidy_blank_values( $old_value ) : str_replace( ',', ', ', $old_value ),
1000
  'EventType' => 'removed',
1001
  )
1002
  );
1003
  }
1004
  }
1005
 
1006
- $this->_post_types = $post_types;
1007
- $this->_plugin->SetGlobalSetting( 'custom-post-types', esc_html( implode( ',', $this->_post_types ) ) );
1008
  }
1009
 
1010
  /**
@@ -1013,10 +1094,10 @@ class WSAL_Settings {
1013
  * @since 2.6.7
1014
  */
1015
  public function get_excluded_post_types() {
1016
- if ( empty( $this->_post_types ) ) {
1017
- $this->_post_types = array_unique( array_filter( explode( ',', $this->_plugin->GetGlobalSetting( 'custom-post-types' ) ) ) );
1018
  }
1019
- return $this->_post_types;
1020
  }
1021
 
1022
  /**
@@ -1024,15 +1105,15 @@ class WSAL_Settings {
1024
  *
1025
  * @param array $roles - Array of roles.
1026
  */
1027
- public function SetExcludedMonitoringRoles( $roles ) {
1028
 
1029
  // Trigger alert.
1030
- $old_value = $this->_plugin->GetGlobalSetting( 'excluded-roles', [] );
1031
- $changes = $this->determine_added_and_removed_items( $old_value, implode( ',', $roles ) );
1032
 
1033
- if ( ! empty( $changes[ 'added' ] ) ) {
1034
- foreach ( $changes[ 'added' ] as $user ) {
1035
- $this->_plugin->alerts->Trigger(
1036
  6054,
1037
  array(
1038
  'role' => $user,
@@ -1042,70 +1123,70 @@ class WSAL_Settings {
1042
  );
1043
  }
1044
  }
1045
- if ( ! empty( $changes[ 'removed' ] ) && ! empty( $old_value ) ) {
1046
- foreach ( $changes[ 'removed' ] as $user ) {
1047
- $this->_plugin->alerts->Trigger(
1048
  6054,
1049
  array(
1050
  'role' => $user,
1051
- 'previous_users' => ( empty( $old_value ) ) ? $this->tidy_blank_values( $old_value ) : str_replace( ',', ', ', $old_value ),
1052
  'EventType' => 'removed',
1053
  )
1054
  );
1055
  }
1056
  }
1057
 
1058
- $this->_excluded_roles = $roles;
1059
- $this->_plugin->SetGlobalSetting( 'excluded-roles', esc_html( implode( ',', $roles ) ) );
1060
  }
1061
 
1062
  /**
1063
  * Get roles excluded from monitoring.
1064
  */
1065
- public function GetExcludedMonitoringRoles() {
1066
- if ( empty( $this->_excluded_roles ) ) {
1067
- $this->_excluded_roles = array_unique( array_filter( explode( ',', $this->_plugin->GetGlobalSetting( 'excluded-roles' ) ) ) );
1068
  }
1069
- return $this->_excluded_roles;
1070
  }
1071
 
1072
  /**
1073
  * Updates custom post meta fields excluded from monitoring.
1074
  *
1075
- * @param array $custom
1076
  */
1077
- public function SetExcludedPostMetaFields( $custom ) {
1078
- $old_value = $this->GetExcludedPostMetaFields();
1079
- $changes = $this->determine_added_and_removed_items( $old_value, implode( ',', $custom ) );
1080
 
1081
- if ( ! empty( $changes[ 'added' ] ) ) {
1082
- foreach ( $changes[ 'added' ] as $custom_field ) {
1083
- $this->_plugin->alerts->Trigger(
1084
  6057,
1085
  array(
1086
  'custom_field' => $custom_field,
1087
  'previous_fields' => ( empty( $old_value ) ) ? $this->tidy_blank_values( $old_value ) : str_replace( ',', ', ', $old_value ),
1088
- 'EventType' => 'added',
1089
  )
1090
  );
1091
  }
1092
  }
1093
 
1094
- if ( ! empty( $changes[ 'removed' ] ) && ! empty( $old_value ) ) {
1095
- foreach ( $changes[ 'removed' ] as $custom_field ) {
1096
- $this->_plugin->alerts->Trigger(
1097
  6057,
1098
  array(
1099
  'custom_field' => $custom_field,
1100
- 'previous_fields' => ( empty( $old_value ) ) ? $this->tidy_blank_values( $old_value ) : str_replace( ',', ', ', $old_value ),
1101
- 'EventType' => 'removed',
1102
  )
1103
  );
1104
  }
1105
  }
1106
 
1107
- $this->_excluded_post_meta = $custom;
1108
- $this->_plugin->SetGlobalSetting( 'excluded-post-meta', esc_html( implode( ',', $this->_excluded_post_meta ) ) );
1109
  }
1110
 
1111
  /**
@@ -1113,54 +1194,54 @@ class WSAL_Settings {
1113
  *
1114
  * @return array
1115
  */
1116
- public function GetExcludedPostMetaFields() {
1117
- if ( empty( $this->_excluded_post_meta ) ) {
1118
- $this->_excluded_post_meta = array_unique( array_filter( explode( ',', $this->_plugin->GetGlobalSetting( 'excluded-post-meta' ) ) ) );
1119
- asort( $this->_excluded_post_meta );
1120
  }
1121
- return $this->_excluded_post_meta;
1122
  }
1123
 
1124
  /**
1125
  * Updates custom user meta fields excluded from monitoring.
1126
  *
1127
- * @param array $custom
1128
  *
1129
  * @since 4.3.2
1130
  */
1131
- public function SetExcludedUserMetaFields( $custom ) {
1132
 
1133
- $old_value = $this->GetExcludedUserMetaFields();
1134
- $changes = $this->determine_added_and_removed_items( $old_value, implode( ',', $custom ) );
1135
 
1136
- if ( ! empty( $changes[ 'added' ] ) ) {
1137
- foreach ( $changes[ 'added' ] as $custom_field ) {
1138
- $this->_plugin->alerts->Trigger(
1139
  6058,
1140
  array(
1141
  'custom_field' => $custom_field,
1142
  'previous_fields' => ( empty( $old_value ) ) ? $this->tidy_blank_values( $old_value ) : str_replace( ',', ', ', $old_value ),
1143
- 'EventType' => 'added',
1144
  )
1145
  );
1146
  }
1147
  }
1148
 
1149
- if ( ! empty( $changes[ 'removed' ] ) && ! empty( $old_value ) ) {
1150
- foreach ( $changes[ 'removed' ] as $custom_field ) {
1151
- $this->_plugin->alerts->Trigger(
1152
  6058,
1153
  array(
1154
  'custom_field' => $custom_field,
1155
- 'previous_fields' => ( empty( $old_value ) ) ? $this->tidy_blank_values( $old_value ) : str_replace( ',', ', ', $old_value ),
1156
- 'EventType' => 'removed',
1157
  )
1158
  );
1159
  }
1160
  }
1161
 
1162
- $this->_excluded_user_meta = $custom;
1163
- $this->_plugin->SetGlobalSetting( 'excluded-user-meta', esc_html( implode( ',', $this->_excluded_user_meta ) ) );
1164
  }
1165
 
1166
  /**
@@ -1169,25 +1250,27 @@ class WSAL_Settings {
1169
  * @return array
1170
  * @since 4.3.2
1171
  */
1172
- public function GetExcludedUserMetaFields() {
1173
- if ( empty( $this->_excluded_user_meta ) ) {
1174
- $this->_excluded_user_meta = array_unique( array_filter( explode( ',', $this->_plugin->GetGlobalSetting( 'excluded-user-meta' ) ) ) );
1175
- asort( $this->_excluded_user_meta );
1176
  }
1177
 
1178
- return $this->_excluded_user_meta;
1179
  }
1180
 
1181
  /**
1182
  * IP excluded from monitoring.
 
 
1183
  */
1184
- public function SetExcludedMonitoringIP( $ip ) {
1185
- $old_value = $this->_plugin->GetGlobalSetting( 'excluded-ip', [] );
1186
- $changes = $this->determine_added_and_removed_items( $old_value, implode( ',', $ip ) );
1187
 
1188
- if ( ! empty( $changes[ 'added' ] ) ) {
1189
- foreach ( $changes[ 'added' ] as $user ) {
1190
- $this->_plugin->alerts->Trigger(
1191
  6055,
1192
  array(
1193
  'ip' => $user,
@@ -1197,28 +1280,33 @@ class WSAL_Settings {
1197
  );
1198
  }
1199
  }
1200
- if ( ! empty( $changes[ 'removed' ] ) && ! empty( $old_value ) ) {
1201
- foreach ( $changes[ 'removed' ] as $user ) {
1202
- $this->_plugin->alerts->Trigger(
1203
  6055,
1204
  array(
1205
  'ip' => $user,
1206
- 'previous_ips' => ( empty( $old_value ) ) ? $this->tidy_blank_values( $old_value ) : str_replace( ',', ', ', $old_value ),
1207
  'EventType' => 'removed',
1208
  )
1209
  );
1210
  }
1211
  }
1212
 
1213
- $this->_excluded_ip = $ip;
1214
- $this->_plugin->SetGlobalSetting( 'excluded-ip', esc_html( implode( ',', $this->_excluded_ip ) ) );
1215
  }
1216
 
1217
- public function GetExcludedMonitoringIP() {
1218
- if ( empty( $this->_excluded_ip ) ) {
1219
- $this->_excluded_ip = array_unique( array_filter( explode( ',', $this->_plugin->GetGlobalSetting( 'excluded-ip' ) ) ) );
 
 
 
 
 
1220
  }
1221
- return $this->_excluded_ip;
1222
  }
1223
 
1224
  /**
@@ -1228,16 +1316,17 @@ class WSAL_Settings {
1228
  * Note: Format returned by this function is not compatible with JavaScript date and time picker widgets. Use
1229
  * functions GetTimeFormat and GetDateFormat for those.
1230
  *
1231
- * @param boolean $line_break - True if line break otherwise false.
 
1232
  *
1233
  * @return string
1234
  */
1235
- public function GetDatetimeFormat( $line_break = true, $use_nb_space_for_am_pm = true ) {
1236
- $result = $this->GetDateFormat();
1237
 
1238
  $result .= $line_break ? '<\b\r>' : ' ';
1239
 
1240
- $time_format = $this->GetTimeFormat();
1241
  $has_am_pm = false;
1242
  $am_pm_fraction = false;
1243
  $am_pm_pattern = '/(?i)(\s+A)/';
@@ -1252,11 +1341,10 @@ class WSAL_Settings {
1252
  $time_format .= ':s'; // Add seconds to time format.
1253
  }
1254
 
1255
- if ($this->get_show_milliseconds()) {
1256
  $time_format .= '.$$$'; // Add milliseconds to time format.
1257
  }
1258
 
1259
-
1260
  if ( $has_am_pm ) {
1261
  $time_format .= preg_replace( '/\s/', $use_nb_space_for_am_pm ? '&\n\b\s\p;' : ' ', $am_pm_fraction );
1262
  }
@@ -1276,7 +1364,7 @@ class WSAL_Settings {
1276
  *
1277
  * @return string
1278
  */
1279
- public function GetDateFormat( $sanitized = false ) {
1280
  if ( $sanitized ) {
1281
  return 'Y-m-d';
1282
  }
@@ -1294,7 +1382,7 @@ class WSAL_Settings {
1294
  *
1295
  * @return string
1296
  */
1297
- public function GetTimeFormat( $sanitize = false ) {
1298
  $result = get_option( 'time_format' );
1299
  if ( $sanitize ) {
1300
  $search = array( 'a', 'A', 'T', ' ' );
@@ -1309,12 +1397,19 @@ class WSAL_Settings {
1309
  *
1310
  * Server's timezone or WordPress' timezone.
1311
  */
1312
- public function GetTimezone() {
1313
- return $this->_plugin->GetGlobalSetting( 'timezone', 'wp' );
1314
  }
1315
 
1316
- public function SetTimezone( $newvalue ) {
1317
- $this->_plugin->SetGlobalSetting( 'timezone', $newvalue );
 
 
 
 
 
 
 
1318
  }
1319
 
1320
  /**
@@ -1326,7 +1421,7 @@ class WSAL_Settings {
1326
  * @return bool
1327
  */
1328
  public function get_show_milliseconds() {
1329
- return $this->_plugin->GetGlobalBooleanSetting( 'show_milliseconds', true );
1330
  }
1331
 
1332
  /**
@@ -1339,7 +1434,7 @@ class WSAL_Settings {
1339
  * @param mixed $newvalue ideally always bool. If not bool then it's cast to true.
1340
  */
1341
  public function set_show_milliseconds( $newvalue ) {
1342
- $this->_plugin->SetGlobalBooleanSetting( 'show_milliseconds', $newvalue );
1343
  }
1344
 
1345
 
@@ -1347,7 +1442,7 @@ class WSAL_Settings {
1347
  * Get type of username to display.
1348
  */
1349
  public function get_type_username() {
1350
- return $this->_plugin->GetGlobalSetting( 'type_username', 'display_name' );
1351
  }
1352
 
1353
  /**
@@ -1357,7 +1452,7 @@ class WSAL_Settings {
1357
  * @since 2.6.5
1358
  */
1359
  public function set_type_username( $newvalue ) {
1360
- $this->_plugin->SetGlobalSetting( 'type_username', $newvalue );
1361
  }
1362
 
1363
  /**
@@ -1365,7 +1460,7 @@ class WSAL_Settings {
1365
  *
1366
  * @return array
1367
  */
1368
- public function GetColumns() {
1369
  $columns = array(
1370
  'alert_code' => '1',
1371
  'type' => '1',
@@ -1379,11 +1474,11 @@ class WSAL_Settings {
1379
  'info' => '1',
1380
  );
1381
 
1382
- if ( $this->_plugin->IsMultisite() ) {
1383
  $columns = array_slice( $columns, 0, 6, true ) + array( 'site' => '1' ) + array_slice( $columns, 6, null, true );
1384
  }
1385
 
1386
- $selected = $this->GetColumnsSelected();
1387
 
1388
  if ( ! empty( $selected ) ) {
1389
  $columns = array(
@@ -1398,7 +1493,7 @@ class WSAL_Settings {
1398
  'message' => '0',
1399
  );
1400
 
1401
- if ( $this->_plugin->IsMultisite() ) {
1402
  $columns = array_slice( $columns, 0, 6, true ) + array( 'site' => '0' ) + array_slice( $columns, 6, null, true );
1403
  }
1404
 
@@ -1409,20 +1504,40 @@ class WSAL_Settings {
1409
  return $columns;
1410
  }
1411
 
1412
- public function GetColumnsSelected() {
1413
- return $this->_plugin->GetGlobalSetting( 'columns', array() );
 
 
 
 
 
1414
  }
1415
 
1416
- public function SetColumns( $columns ) {
1417
- $this->_plugin->SetGlobalSetting( 'columns', json_encode( $columns ) );
 
 
 
 
 
1418
  }
1419
 
1420
- public function IsWPBackend() {
1421
- return $this->_plugin->GetGlobalBooleanSetting( 'wp-backend' );
 
 
 
 
 
1422
  }
1423
 
1424
- public function SetWPBackend( $enabled ) {
1425
- $this->_plugin->SetGlobalBooleanSetting( 'wp-backend', $enabled );
 
 
 
 
 
1426
  }
1427
 
1428
  /**
@@ -1431,7 +1546,7 @@ class WSAL_Settings {
1431
  * @param string $use – Setting value.
1432
  */
1433
  public function set_use_email( $use ) {
1434
- $this->_plugin->SetGlobalSetting( 'use-email', $use );
1435
  }
1436
 
1437
  /**
@@ -1440,23 +1555,45 @@ class WSAL_Settings {
1440
  * @return string
1441
  */
1442
  public function get_use_email() {
1443
- return $this->_plugin->GetGlobalSetting( 'use-email', 'default_email' );
1444
  }
1445
 
1446
- public function SetFromEmail( $email_address ) {
1447
- $this->_plugin->SetGlobalSetting( 'from-email', trim( $email_address ) );
 
 
 
 
 
1448
  }
1449
 
1450
- public function GetFromEmail() {
1451
- return $this->_plugin->GetGlobalSetting( 'from-email' );
 
 
 
 
 
1452
  }
1453
 
1454
- public function SetDisplayName( $display_name ) {
1455
- $this->_plugin->SetGlobalSetting( 'display-name', trim( $display_name ) );
 
 
 
 
 
 
 
1456
  }
1457
 
1458
- public function GetDisplayName() {
1459
- return $this->_plugin->GetGlobalSetting( 'display-name' );
 
 
 
 
 
1460
  }
1461
 
1462
  /**
@@ -1467,9 +1604,9 @@ class WSAL_Settings {
1467
  */
1468
  public function set_failed_login_limit( $value ) {
1469
  if ( ! empty( $value ) ) {
1470
- $this->_plugin->SetGlobalSetting( 'log-failed-login-limit', abs( $value ) );
1471
  } else {
1472
- $this->_plugin->SetGlobalSetting( 'log-failed-login-limit', - 1 );
1473
  }
1474
  }
1475
 
@@ -1480,7 +1617,7 @@ class WSAL_Settings {
1480
  * @since 2.6.3
1481
  */
1482
  public function get_failed_login_limit() {
1483
- return intval($this->_plugin->GetGlobalSetting( 'log-failed-login-limit', 10 ));
1484
  }
1485
 
1486
  /**
@@ -1491,9 +1628,9 @@ class WSAL_Settings {
1491
  */
1492
  public function set_visitor_failed_login_limit( $value ) {
1493
  if ( ! empty( $value ) ) {
1494
- $this->_plugin->SetGlobalSetting( 'log-visitor-failed-login-limit', abs( $value ) );
1495
  } else {
1496
- $this->_plugin->SetGlobalSetting( 'log-visitor-failed-login-limit', - 1 );
1497
  }
1498
  }
1499
 
@@ -1504,7 +1641,7 @@ class WSAL_Settings {
1504
  * @since 2.6.3
1505
  */
1506
  public function get_visitor_failed_login_limit() {
1507
- return intval( $this->_plugin->GetGlobalSetting( 'log-visitor-failed-login-limit', 10 ) );
1508
  }
1509
 
1510
 
@@ -1524,7 +1661,7 @@ class WSAL_Settings {
1524
  }
1525
 
1526
  // Check if the token matched users.
1527
- if ( in_array( $token, $users ) ) {
1528
  return 'user';
1529
  }
1530
 
@@ -1532,7 +1669,7 @@ class WSAL_Settings {
1532
  $roles = array_keys( get_editable_roles() );
1533
 
1534
  // Check if the token matched user roles.
1535
- if ( in_array( $token, $roles ) ) {
1536
  return 'role';
1537
  }
1538
 
@@ -1548,7 +1685,7 @@ class WSAL_Settings {
1548
  }
1549
 
1550
  // Check if the token matched post types.
1551
- if ( in_array( $token, $post_types ) ) {
1552
  return 'cpts';
1553
  }
1554
 
@@ -1594,15 +1731,15 @@ class WSAL_Settings {
1594
  */
1595
  public function set_mainwp_child_stealth_mode() {
1596
  if (
1597
- ! $this->_plugin->GetGlobalBooleanSetting( 'mwp-child-stealth-mode', false ) // MainWP Child Stealth Mode is not already active.
1598
  && WpSecurityAuditLog::is_mainwp_active() // And if MainWP Child plugin is installed & active.
1599
  ) {
1600
  // Check if freemius state is anonymous.
1601
- if ( ! wsal_freemius()->is_premium() && 'anonymous' === $this->_plugin->GetGlobalSetting( 'freemius_state', 'anonymous' ) ) {
1602
  // Update Freemius state to skipped.
1603
- $this->_plugin->SetGlobalSetting( 'wsal_freemius_state', 'skipped', true );
1604
 
1605
- if ( ! $this->_plugin->IsMultisite() ) {
1606
  wsal_freemius()->skip_connection(); // Opt out.
1607
  } else {
1608
  wsal_freemius()->skip_connection( null, true ); // Opt out for all websites.
@@ -1617,13 +1754,13 @@ class WSAL_Settings {
1617
  FS_Admin_Notices::instance( 'wp-security-audit-log' )->remove_sticky( 'trial_promotion' );
1618
  }
1619
 
1620
- $this->SetIncognito( true ); // Incognito mode to hide WSAL on plugins page.
1621
  $this->set_restrict_log_viewer( 'only_me' );
1622
  $this->set_restrict_plugin_setting( 'only_me' );
1623
  // Current user with fallback to default admin (in case this is triggered using WP CLI or something similar).
1624
  $only_me_user_id = is_user_logged_in() ? get_current_user_id() : 1;
1625
  $this->set_only_me_user_id( $only_me_user_id );
1626
- $this->_plugin->SetGlobalBooleanSetting( 'mwp-child-stealth-mode', true ); // Save stealth mode option.
1627
  }
1628
  }
1629
 
@@ -1633,11 +1770,11 @@ class WSAL_Settings {
1633
  * @since 3.2.3.3
1634
  */
1635
  public function deactivate_mainwp_child_stealth_mode() {
1636
- $this->SetIncognito( false ); // Disable incognito mode to hide WSAL on plugins page.
1637
  $this->set_restrict_plugin_setting( 'only_admins' );
1638
  $this->set_restrict_log_viewer( 'only_admins' );
1639
  $this->set_admin_blocking_plugin_support( false );
1640
- $this->_plugin->SetGlobalBooleanSetting( 'mwp-child-stealth-mode', false ); // Disable stealth mode option.
1641
  }
1642
 
1643
  /**
@@ -1650,7 +1787,7 @@ class WSAL_Settings {
1650
  return;
1651
  }
1652
 
1653
- if ( $this->_plugin->GetGlobalBooleanSetting( 'mwp-child-stealth-mode', false ) ) {
1654
  $this->deactivate_mainwp_child_stealth_mode();
1655
  }
1656
  }
@@ -1661,7 +1798,7 @@ class WSAL_Settings {
1661
  * @return boolean
1662
  */
1663
  public function is_stealth_mode() {
1664
- return $this->_plugin->GetGlobalBooleanSetting( 'mwp-child-stealth-mode', false );
1665
  }
1666
 
1667
  /**
@@ -1674,7 +1811,7 @@ class WSAL_Settings {
1674
  public function get_view_site_id() {
1675
  switch ( true ) {
1676
  // Non-multisite.
1677
- case ! $this->_plugin->IsMultisite():
1678
  return 0;
1679
  // Multisite + main site view.
1680
  case $this->is_main_blog() && ! $this->is_specific_view():
@@ -1707,7 +1844,7 @@ class WSAL_Settings {
1707
  * @return bool
1708
  */
1709
  protected function is_specific_view() {
1710
- return isset( $_REQUEST['wsal-cbid'] ) && 0 !== (int) $_REQUEST['wsal-cbid']; // @codingStandardsIgnoreLine
1711
  }
1712
 
1713
  /**
@@ -1718,7 +1855,7 @@ class WSAL_Settings {
1718
  * @return int
1719
  */
1720
  protected function get_specific_view() {
1721
- return isset( $_REQUEST['wsal-cbid'] ) ? (int) sanitize_text_field( wp_unslash( $_REQUEST['wsal-cbid'] ) ) : 0; // @codingStandardsIgnoreLine
1722
  }
1723
 
1724
  /**
@@ -1736,7 +1873,7 @@ class WSAL_Settings {
1736
  if ( ! is_null( $limit ) ) {
1737
  $sql .= ' LIMIT ' . $limit;
1738
  }
1739
- $res = $wpdb->get_results( $sql );
1740
  foreach ( $res as $row ) {
1741
  $row->blogname = get_blog_option( $row->blog_id, 'blogname' );
1742
  }
@@ -1753,7 +1890,7 @@ class WSAL_Settings {
1753
  public function get_site_count() {
1754
  global $wpdb;
1755
  $sql = 'SELECT COUNT(*) FROM ' . $wpdb->blogs;
1756
- return (int) $wpdb->get_var( $sql );
1757
  }
1758
 
1759
  /**
@@ -1779,7 +1916,7 @@ class WSAL_Settings {
1779
  * @return string
1780
  */
1781
  public function get_events_type_nav() {
1782
- return $this->_plugin->GetGlobalSetting( 'events-nav-type', 'infinite-scroll' );
1783
  }
1784
 
1785
  /**
@@ -1792,7 +1929,7 @@ class WSAL_Settings {
1792
  * @param string $nav_type - Navigation type.
1793
  */
1794
  public function set_events_type_nav( $nav_type ) {
1795
- $this->_plugin->SetGlobalSetting( 'events-nav-type', $nav_type );
1796
  }
1797
 
1798
  /**
@@ -1802,7 +1939,7 @@ class WSAL_Settings {
1802
  */
1803
  public function get_plugin_settings() {
1804
  global $wpdb;
1805
- return $wpdb->get_results( "SELECT * FROM $wpdb->options WHERE option_name LIKE 'wsal_%'" );
1806
  }
1807
 
1808
  /**
@@ -2021,7 +2158,7 @@ class WSAL_Settings {
2021
  * @since 4.1.3
2022
  */
2023
  public function set_only_me_user_id( $user_id ) {
2024
- $this->_plugin->SetGlobalSetting( 'only-me-user-id', $user_id, true );
2025
  }
2026
 
2027
  /**
@@ -2031,16 +2168,16 @@ class WSAL_Settings {
2031
  * @since 4.1.3
2032
  */
2033
  public function get_only_me_user_id() {
2034
- return $this->_plugin->GetGlobalSetting( 'only-me-user-id' );
2035
  }
2036
 
2037
  /**
2038
  * Save admin blocking plugin support enabled.
2039
  *
2040
- * @param bool $enabled
2041
  */
2042
  public function set_admin_blocking_plugin_support( $enabled ) {
2043
- $this->_plugin->SetGlobalBooleanSetting( 'admin-blocking-plugins-support', $enabled );
2044
  }
2045
 
2046
  /**
@@ -2053,21 +2190,42 @@ class WSAL_Settings {
2053
  * @return bool
2054
  */
2055
  public function get_admin_blocking_plugin_support() {
2056
- return $this->_plugin->GetGlobalBooleanSetting( 'admin-blocking-plugins-support', false );
2057
  }
2058
 
 
 
 
 
 
2059
  public function get_mainwp_enforced_settings() {
2060
- return $this->_plugin->GetGlobalSetting( 'mainwp_enforced_settings', array() );
2061
  }
2062
 
 
 
 
 
 
2063
  public function set_mainwp_enforced_settings( $settings ) {
2064
- $this->_plugin->SetGlobalSetting( 'mainwp_enforced_settings', $settings );
2065
  }
2066
 
 
 
 
2067
  public function delete_mainwp_enforced_settings() {
2068
- $this->_plugin->DeleteGlobalSetting( 'mainwp_enforced_settings' );
2069
  }
2070
 
 
 
 
 
 
 
 
 
2071
  public function determine_added_and_removed_items( $old_value, $value ) {
2072
  $old_value = ( ! is_array( $old_value ) ) ? explode( ',', $old_value ) : $old_value;
2073
  $value = ( ! is_array( $value ) ) ? explode( ',', $value ) : $value;
@@ -2078,6 +2236,13 @@ class WSAL_Settings {
2078
  return $return;
2079
  }
2080
 
 
 
 
 
 
 
 
2081
  public function tidy_blank_values( $value ) {
2082
  return ( empty( $value ) ) ? __( 'None provided', 'wp-security-audit-log' ) : $value;
2083
  }
@@ -2089,7 +2254,7 @@ class WSAL_Settings {
2089
  * @since 4.3.2
2090
  */
2091
  public function get_database_version() {
2092
- return (int) $this->_plugin->GetGlobalSetting( 'db_version', 0 );
2093
  }
2094
 
2095
  /**
@@ -2099,7 +2264,7 @@ class WSAL_Settings {
2099
  * @since 4.3.2
2100
  */
2101
  public function set_database_version( $version ) {
2102
- $this->_plugin->SetGlobalSetting( 'db_version', $version, true );
2103
  }
2104
 
2105
  }
31
  *
32
  * @var WpSecurityAuditLog
33
  */
34
+ protected $plugin;
35
 
36
  const ERROR_CODE_INVALID_IP = 901;
37
 
47
  *
48
  * @var string
49
  */
50
+ protected $pruning = 0;
51
 
52
  /**
53
  * IDs of disabled alerts.
54
  *
55
  * @var array
56
  */
57
+ protected $disabled = null;
58
 
59
  /**
60
  * Allowed Plugin Viewers.
61
  *
62
  * @var array
63
  */
64
+ protected $viewers = null;
65
 
66
  /**
67
  * Alerts per page.
68
  *
69
  * @var int
70
  */
71
+ protected $per_page = null;
72
 
73
  /**
74
  * Users excluded from monitoring.
75
  *
76
  * @var array
77
  */
78
+ protected $excluded_users = array();
79
 
80
  /**
81
  * Roles excluded from monitoring.
82
  *
83
  * @var array
84
  */
85
+ protected $excluded_roles = array();
86
 
87
  /**
88
  * Custom post meta fields excluded from monitoring.
89
  *
90
  * @var array
91
  */
92
+ protected $excluded_post_meta = array();
93
 
94
  /**
95
  * Custom user meta fields excluded from monitoring.
96
  *
97
  * @var array
98
  */
99
+ protected $excluded_user_meta = array();
100
 
101
  /**
102
  * Custom Post Types excluded from monitoring.
103
  *
104
  * @var array
105
  */
106
+ protected $post_types = array();
107
 
108
  /**
109
  * IP excluded from monitoring.
110
  *
111
  * @var array
112
  */
113
+ protected $excluded_ip = array();
114
 
115
  /**
116
  * Alerts enabled in Geek mode.
140
  * @param WpSecurityAuditLog $plugin - Instance of WpSecurityAuditLog.
141
  */
142
  public function __construct( WpSecurityAuditLog $plugin ) {
143
+ $this->plugin = $plugin;
144
  // some settings here may be called before the options helper is setup.
145
+ if ( ! isset( $this->plugin->options_helper ) ) {
146
+ $this->plugin->include_options_helper();
147
  }
148
  add_action( 'deactivated_plugin', array( $this, 'reset_stealth_mode' ), 10, 1 );
149
  }
154
  */
155
  public function set_basic_mode() {
156
  // Disable alerts of geek mode and alerts to be always disabled.
157
+ $this->set_disabled_alerts( array_merge( $this->geek_alerts, $this->always_disabled_alerts ) );
158
  }
159
 
160
  /**
161
  * Enable Geek Mode.
162
  */
163
  public function set_geek_mode() {
164
+ $this->set_disabled_alerts( $this->always_disabled_alerts ); // Disable alerts to be always disabled.
165
  }
166
 
167
 
170
  *
171
  * @return boolean
172
  */
173
+ public function is_widgets_enabled() {
174
+ return ! $this->plugin->get_global_boolean_setting( 'disable-widgets' );
175
  }
176
 
177
  /**
179
  *
180
  * @param boolean $newvalue - True if enabled.
181
  */
182
+ public function set_widgets_enabled( $newvalue ) {
183
+ $this->plugin->set_global_boolean_setting( 'disable-widgets', ! $newvalue );
184
  }
185
 
186
  /**
191
  * @return boolean
192
  */
193
  public function is_admin_bar_notif() {
194
+ return ! $this->plugin->get_global_boolean_setting( 'disable-admin-bar-notif', true );
195
  }
196
 
197
  /**
202
  * @param boolean $newvalue - True if enabled.
203
  */
204
  public function set_admin_bar_notif( $newvalue ) {
205
+ $this->plugin->set_global_boolean_setting( 'disable-admin-bar-notif', ! $newvalue, true );
206
  }
207
 
208
  /**
213
  * @return string
214
  */
215
  public function get_admin_bar_notif_updates() {
216
+ return $this->plugin->get_global_setting( 'admin-bar-notif-updates', 'page-refresh' );
217
  }
218
 
219
  /**
224
  * @param string $newvalue - New option value.
225
  */
226
  public function set_admin_bar_notif_updates( $newvalue ) {
227
+ $this->plugin->set_global_setting( 'admin-bar-notif-updates', $newvalue, true );
228
  }
229
 
230
  /**
232
  *
233
  * @return boolean
234
  */
235
+ public function is_refresh_alerts_enabled() {
236
+ return ! $this->plugin->get_global_setting( 'disable-refresh' );
237
  }
238
 
239
  /**
241
  *
242
  * @param boolean $newvalue - True if enabled.
243
  */
244
+ public function set_refresh_alerts_enabled( $newvalue ) {
245
+ $this->plugin->set_global_setting( 'disable-refresh', ! $newvalue );
246
  }
247
 
248
  /**
250
  *
251
  * @return int
252
  */
253
+ public function get_dashboard_widget_max_alerts() {
254
  return 5;
255
  }
256
 
259
  *
260
  * @return int
261
  */
262
+ public function get_max_allowed_alerts() {
263
  return 5000;
264
  }
265
 
268
  *
269
  * @return string
270
  */
271
+ public function get_default_pruning_date() {
272
  return '6 months';
273
  }
274
 
277
  *
278
  * @return string
279
  */
280
+ public function get_pruning_date() {
281
+ if ( ! $this->pruning ) {
282
+ $this->pruning = $this->plugin->get_global_setting( 'pruning-date' );
283
+ if ( ! strtotime( $this->pruning ) ) {
284
+ $this->pruning = $this->get_default_pruning_date();
285
  }
286
  }
287
+ return $this->pruning;
288
  }
289
 
290
  /**
292
  *
293
  * @param string $newvalue - The new pruning date.
294
  */
295
+ public function set_pruning_date( $newvalue ) {
296
  if ( strtotime( $newvalue ) ) {
297
+ $this->plugin->set_global_setting( 'pruning-date', $newvalue );
298
+ $this->pruning = $newvalue;
299
  }
300
  }
301
 
305
  * @return string
306
  */
307
  public function get_pruning_unit() {
308
+ return $this->plugin->get_global_setting( 'pruning-unit', 'months' );
309
  }
310
 
311
  /**
314
  * @param string $newvalue – New value of pruning unit.
315
  */
316
  public function set_pruning_unit( $newvalue ) {
317
+ $this->plugin->set_global_setting( 'pruning-unit', $newvalue );
318
  }
319
 
320
  /**
322
  *
323
  * @return integer
324
  */
325
+ public function get_pruning_limit() {
326
+ $val = (int) $this->plugin->get_global_setting( 'pruning-limit' );
327
+ return $val ? $val : $this->get_max_allowed_alerts();
328
  }
329
 
330
  /**
332
  *
333
  * @param integer $newvalue - The new maximum number of alerts.
334
  */
335
+ public function set_pruning_limit( $newvalue ) {
336
+ $this->plugin->set_global_setting( 'pruning-limit', max( (int) $newvalue, 1 ) );
 
337
  }
338
 
339
+ /**
340
+ * Enables or disables time based retention period.
341
+ *
342
+ * @param bool $enabled If true, time based retention period is enabled.
343
+ */
344
+ public function set_pruning_date_enabled( $enabled ) {
345
 
346
+ $old_setting = $this->plugin->get_global_boolean_setting( 'pruning-date-e', false );
347
+ $enable = \WSAL\Helpers\Options::string_to_bool( $enabled );
348
  if ( $old_setting !== $enable ) {
349
+ $this->pruning = $this->plugin->get_global_setting( 'pruning-date' ) . ' ' . $this->plugin->get_global_setting( 'pruning-unit', 'months' );
350
+ $alert_data = array(
351
+ 'new_setting' => ( $enable ) ? 'Delete events older than ' . $this->pruning : 'Keep all data',
352
+ 'previous_setting' => ( $old_setting ) ? 'Delete events older than ' . $this->pruning : 'Keep all data',
353
+ );
354
+ $this->plugin->alerts->trigger_event( 6052, $alert_data );
355
  }
356
 
357
+ $this->plugin->set_global_boolean_setting( 'pruning-date-e', $enabled );
358
  }
359
 
360
+ /**
361
+ * Sets the plugin setting that enabled data pruning limit.
362
+ *
363
+ * @param bool $enabled If true, the limit is enabled.
364
+ */
365
+ public function set_pruning_limit_enabled( $enabled ) {
366
+ $this->plugin->set_global_boolean_setting( 'pruning-limit-e', $enabled );
367
  }
368
 
369
+ /**
370
+ * Checks if the time based retention period is enabled.
371
+ *
372
+ * @return bool
373
+ */
374
+ public function is_pruning_date_enabled() {
375
+ return $this->plugin->get_global_boolean_setting( 'pruning-date-e' );
376
  }
377
 
378
+ /**
379
+ * Checks if the data pruning limit is enabled.
380
+ *
381
+ * @return bool
382
+ */
383
+ public function is_pruning_limit_enabled() {
384
+ return $this->plugin->get_global_boolean_setting( 'pruning-limit-e' );
385
  }
386
 
387
  /**
399
  * @param bool $enable - Enable/Disable.
400
  */
401
  public function set_login_page_notification( $enable ) {
402
+ // Only trigger an event if an actual changes is made.
403
+ $old_setting = $this->plugin->get_global_boolean_setting( 'login_page_notification', false );
404
+ $enable = \WSAL\Helpers\Options::string_to_bool( $enable );
405
  if ( $old_setting !== $enable ) {
406
+ $event_id = 6046;
407
+ $alert_data = array(
408
  'EventType' => ( $enable ) ? 'enabled' : 'disabled',
409
+ );
410
+ $this->plugin->alerts->trigger_event( $event_id, $alert_data );
411
  }
412
+ $this->plugin->set_global_boolean_setting( 'login_page_notification', $enable );
413
  }
414
 
415
  /**
418
  * @return bool - True if set, false if not.
419
  */
420
  public function is_login_page_notification() {
421
+ return $this->plugin->get_global_boolean_setting( 'login_page_notification', false );
422
  }
423
 
424
  /**
427
  * @param string $text - Login Page Notification Text.
428
  */
429
  public function set_login_page_notification_text( $text ) {
430
+ $text = wp_kses( $text, $this->plugin->allowed_html_tags );
431
+ $old_setting = $this->plugin->get_global_setting( 'login_page_notification_text' );
432
  if ( ! empty( $old_setting ) && ! empty( $text ) && ! is_null( $old_setting ) && $old_setting !== $text ) {
433
+ $this->plugin->alerts->trigger_event( 6047 );
434
  }
435
+ $this->plugin->set_global_setting( 'login_page_notification_text', $text );
436
  }
437
 
438
  /**
441
  * @return string|bool - Text if set, false if not.
442
  */
443
  public function get_login_page_notification_text() {
444
+ return $this->plugin->get_global_setting( 'login_page_notification_text', false );
445
  }
446
 
447
+ /**
448
+ * Retrieves a list of alerts disabled by default.
449
+ *
450
+ * @return int[] List of alerts disabled by default.
451
+ */
452
+ public function get_default_disabled_alerts() {
453
  return array( 0000, 0001, 0002, 0003, 0004, 0005 );
454
  }
455
 
458
  *
459
  * @return array
460
  */
461
+ public function get_disabled_alerts() {
462
+ if ( ! $this->disabled ) {
463
+ $this->disabled = implode( ',', $this->get_default_disabled_alerts() );
464
+ $this->disabled = $this->plugin->get_global_setting( 'disabled-alerts', $this->disabled );
465
+ $this->disabled = ( '' === $this->disabled ) ? array() : explode( ',', $this->disabled );
466
+ $this->disabled = array_map( 'intval', $this->disabled );
467
  }
468
+ return $this->disabled;
469
  }
470
 
471
  /**
473
  *
474
  * @param array $types IDs alerts to disable.
475
  */
476
+ public function set_disabled_alerts( $types ) {
477
+ $this->disabled = array_unique( array_map( 'intval', $types ) );
478
+ $this->plugin->set_global_setting( 'disabled-alerts', implode( ',', $this->disabled ) );
479
  }
480
 
481
  /**
482
+ * Checks if the plugin is in incognito mode.
483
+ *
484
  * @return bool
485
  */
486
+ public function is_incognito() {
487
+ return $this->plugin->get_global_boolean_setting( 'hide-plugin' );
488
  }
489
 
490
  /**
491
+ * Enables or disables plugin's incognito mode.
492
+ *
493
+ * @param bool $enabled If true, the incognito mode gets enabled.
494
  */
495
+ public function set_incognito( $enabled ) {
496
+ $old_value = $this->plugin->get_global_setting( 'hide-plugin' );
497
+ $old_value = ( 'yes' === $old_value );
498
  if ( $old_value !== $enabled ) {
499
+ $alert_data = array(
500
  'EventType' => ( $enabled ) ? 'enabled' : 'disabled',
501
+ );
502
+ $this->plugin->alerts->trigger_event( 6051, $alert_data );
503
  }
504
 
505
+ $this->plugin->set_global_boolean_setting( 'hide-plugin', $enabled );
506
  }
507
 
508
  /**
509
  * Checking if the data will be removed.
510
  */
511
+ public function is_delete_data() {
512
+ return $this->plugin->get_global_boolean_setting( 'delete-data' );
513
  }
514
 
515
  /**
516
  * Sets the plugin setting that allows data deletion on plugin uninstall.
517
  *
518
+ * @param mixed $enabled If true, data deletion on plugin uninstall gets enabled.
519
  */
520
+ public function set_delete_data( $enabled ) {
521
+ $this->plugin->set_global_boolean_setting( 'delete-data', $enabled );
522
  }
523
 
524
  /**
526
  *
527
  * @param array $users_or_roles – Users/Roles.
528
  */
529
+ public function set_allowed_plugin_viewers( $users_or_roles ) {
530
 
531
+ $old_value = $this->plugin->get_global_setting( 'plugin-viewers' );
532
+ $changes = $this->determine_added_and_removed_items( $old_value, implode( ',', $users_or_roles ) );
533
 
534
+ if ( ! empty( $changes['added'] ) ) {
535
+ foreach ( $changes['added'] as $user ) {
536
+ $this->plugin->alerts->trigger_event(
537
  6050,
538
  array(
539
  'user' => $user,
544
  }
545
  }
546
 
547
+ if ( ! empty( $changes['removed'] ) && ! empty( $old_value ) ) {
548
+ foreach ( $changes['removed'] as $user ) {
549
  if ( ! empty( $user ) ) {
550
+ $this->plugin->alerts->trigger_event(
551
  6050,
552
  array(
553
  'user' => $user,
554
+ 'previous_users' => empty( $old_value ) ? $this->tidy_blank_values( $old_value ) : str_replace( ',', ', ', $old_value ),
555
  'EventType' => 'removed',
556
  )
557
  );
559
  }
560
  }
561
 
562
+ $this->viewers = $users_or_roles;
563
+ $this->plugin->set_global_setting( 'plugin-viewers', implode( ',', $this->viewers ), true );
 
564
  }
565
 
566
  /**
567
  * Get Plugin Viewers.
568
+ *
569
+ * @return array List of users allowed to view the plugin.
570
  */
571
+ public function get_allowed_plugin_viewers() {
572
+ if ( is_null( $this->viewers ) ) {
573
+ $this->viewers = array_unique( array_filter( explode( ',', $this->plugin->get_global_setting( 'plugin-viewers' ) ) ) );
574
  }
575
+ return $this->viewers;
576
  }
577
 
578
  /**
582
  * @since 3.2.3
583
  */
584
  public function set_restrict_plugin_setting( $setting ) {
585
+ $old_value = $this->plugin->get_global_setting( 'restrict-plugin-settings', 'only_admins' );
586
 
587
  if ( ! is_null( $old_value ) && $old_value !== $setting ) {
588
+ $alert_data = array(
589
+ 'new_setting' => ucfirst( str_replace( '_', ' ', $setting ) ),
590
+ 'previous_setting' => ucfirst( str_replace( '_', ' ', $old_value ) ),
591
+ );
592
+ $this->plugin->alerts->trigger_event( 6049, $alert_data );
593
  }
594
 
595
+ $this->plugin->set_global_setting( 'restrict-plugin-settings', $setting, true );
596
  }
597
 
598
  /**
601
  * @since 3.2.3
602
  */
603
  public function get_restrict_plugin_setting() {
604
+ return $this->plugin->get_global_setting( 'restrict-plugin-settings', 'only_admins' );
605
  }
606
 
607
  /**
610
  * @since 4.1.3
611
  */
612
  public function get_restrict_log_viewer() {
613
+ return $this->plugin->get_global_setting( 'restrict-log-viewer', 'only_admins' );
614
  }
615
 
616
  /**
620
  * @since 4.1.3
621
  */
622
  public function set_restrict_log_viewer( $setting ) {
623
+ $this->plugin->set_global_setting( 'restrict-log-viewer', $setting, true );
624
  }
625
 
626
+ /**
627
+ * Sets the number of items per page for the audit log viewer.
628
+ *
629
+ * @param int $newvalue Number of items per page for the audit log viewer.
630
+ */
631
+ public function set_views_per_page( $newvalue ) {
632
+ $this->per_page = max( intval( $newvalue ), 1 );
633
+ $this->plugin->set_global_setting( 'items-per-page', $this->per_page );
634
  }
635
 
636
+ /**
637
+ * Gets the number of items per page for the audit log viewer.
638
+ *
639
+ * @return int Number of items per page for the audit log viewer.
640
+ */
641
+ public function get_views_per_page() {
642
+ if ( is_null( $this->per_page ) ) {
643
+ $this->per_page = (int) $this->plugin->get_global_setting( 'items-per-page', 10 );
644
  }
645
+ return $this->per_page;
646
  }
647
 
648
  /**
651
  * @param string $action Type of action, either 'view' or 'edit'.
652
  * @return boolean If user has access or not.
653
  */
654
+ public function current_user_can( $action ) {
655
+ return $this->user_can( wp_get_current_user(), $action );
656
  }
657
 
658
  /**
660
  *
661
  * @return array
662
  */
663
+ protected function get_super_admins() {
664
+ return $this->plugin->is_multisite() ? get_super_admins() : array();
665
  }
666
 
667
  /**
669
  *
670
  * @return string[]
671
  */
672
+ protected function get_admins() {
673
+ if ( $this->plugin->is_multisite() ) {
674
  if ( empty( $this->site_admins ) ) {
675
  /**
676
  * Get list of admins.
686
  . " AND CAST($wpdb->usermeta.meta_value AS CHAR) LIKE '%\"administrator\"%'";
687
 
688
  // Get admins.
689
+ $this->site_admins = $wpdb->get_col( $sql ); // phpcs:ignore
690
  }
691
  } else {
692
  if ( empty( $this->site_admins ) ) {
706
  * @param string $action - Type of action, either 'view' or 'edit'.
707
  * @return boolean If user has access or not.
708
  */
709
+ public function user_can( $user, $action ) {
710
  if ( is_int( $user ) ) {
711
  $user = get_userdata( $user );
712
  }
713
 
714
+ // By default, the user has no privileges.
715
  $result = false;
716
 
717
+ $is_multisite = $this->plugin->is_multisite();
718
  switch ( $action ) {
719
  case 'view':
720
  if ( ! $is_multisite ) {
721
+ // Non-multisite piggybacks on the plugin settings access.
722
  switch ( $this->get_restrict_plugin_setting() ) {
723
  case 'only_admins':
724
+ // Allow access only if the user is and admin.
725
+ $result = in_array( 'administrator', $user->roles, true );
726
  break;
727
  case 'only_me':
728
+ // Allow access only if the user matches the only user allowed access.
729
+ $result = $user->ID === $this->get_only_me_user_id();
730
  break;
731
  default:
732
+ // No other options to allow access here.
733
  $result = false;
734
  }
735
  } else {
736
+ // Multisite MUST respect the log viewer restriction settings plus also additional users and roles
737
+ // defined in the extra option.
738
  switch ( $this->get_restrict_log_viewer() ) {
739
  case 'only_me':
740
+ // Allow access only if the user matches the only user allowed access.
741
+ $result = ( $user->ID === $this->get_only_me_user_id() );
742
  break;
743
  case 'only_superadmins':
744
+ // Allow access only for super admins.
745
  if ( function_exists( 'is_super_admin' ) && is_super_admin( $user->ID ) ) {
746
  $result = true;
747
  }
748
  break;
749
  case 'only_admins':
750
+ // Allow access only for super admins and admins.
751
+ $result = in_array( 'administrator', $user->roles, true ) || ( function_exists( 'is_super_admin' ) && is_super_admin( $user->ID ) );
752
  break;
753
  default:
754
+ // Fallback for any other cases would go here.
755
  break;
756
  }
757
  }
758
 
759
  if ( ! $result ) {
760
+ // User is still not allowed to view the logs, let's check the additional users and roles
761
+ // settings.
762
+ $extra_viewers = $this->get_allowed_plugin_viewers();
763
+ if ( in_array( $user->user_login, $extra_viewers ) ) { // phpcs:ignore
764
  $result = true;
765
  } elseif ( ! empty( array_intersect( $extra_viewers, $user->roles ) ) ) {
766
  $result = true;
769
  break;
770
  case 'edit':
771
  if ( $is_multisite ) {
772
+ // No one has access to settings on sub site inside a network.
773
  if ( wp_doing_ajax() ) {
774
+ // AJAX calls are an exception.
775
  $result = true;
776
  } elseif ( ! is_network_admin() ) {
777
  $result = false;
781
 
782
  $restrict_plugin_setting = $this->get_restrict_plugin_setting();
783
  if ( 'only_me' === $restrict_plugin_setting ) {
784
+ $result = ( $user->ID === $this->get_only_me_user_id() );
785
  } elseif ( 'only_admins' === $restrict_plugin_setting ) {
786
  if ( $is_multisite ) {
787
  $result = ( function_exists( 'is_super_admin' ) && is_super_admin( $user->ID ) );
788
  } else {
789
+ $result = in_array( 'administrator', $user->roles, true );
790
  }
791
  }
792
  break;
807
  return apply_filters( 'wsal_user_can', $result, $user, $action );
808
  }
809
 
810
+ /**
811
+ * Retrieves current user's roles.
812
+ *
813
+ * @param string[] $base_roles An array of base roles.
814
+ *
815
+ * @return string[]
816
+ */
817
+ public function get_current_user_roles( $base_roles = null ) {
818
+ if ( null === $base_roles ) {
819
  $base_roles = wp_get_current_user()->roles;
820
  }
821
  if ( is_multisite() && function_exists( 'is_super_admin' ) && is_super_admin() ) {
824
  return $base_roles;
825
  }
826
 
827
+ /**
828
+ * Checks if given user is a superadmin.
829
+ *
830
+ * @param string $username Username.
831
+ *
832
+ * @return bool True if the user is a superadmin.
833
+ */
834
+ public function is_login_super_admin( $username ) {
835
  $user_id = username_exists( $username );
836
  return function_exists( 'is_super_admin' ) && is_super_admin( $user_id );
837
  }
838
 
839
+ /**
840
+ * Checks if IP address is determined based on proxy.
841
+ *
842
+ * @return bool True if IP address is determined based on proxy.
843
+ */
844
+ public function is_main_ip_from_proxy() {
845
+ return $this->plugin->get_global_boolean_setting( 'use-proxy-ip' );
846
  }
847
 
848
+ /**
849
+ * Sets the setting that decides if IP address should be determined based on proxy.
850
+ *
851
+ * @param bool $enabled True if IP address should be determined based on proxy.
852
+ */
853
+ public function set_main_ip_from_proxy( $enabled ) {
854
+ $old_value = $this->plugin->get_global_boolean_setting( 'use-proxy-ip' );
855
+ $enabled = \WSAL\Helpers\Options::string_to_bool( $enabled );
856
  if ( $old_value !== $enabled ) {
857
+ $alert_data = array(
858
  'EventType' => ( $enabled ) ? 'enabled' : 'disabled',
859
+ );
860
+ $this->plugin->alerts->trigger_event( 6048, $alert_data );
861
  }
862
+ $this->plugin->set_global_boolean_setting( 'use-proxy-ip', $enabled );
863
  }
864
 
865
+ /**
866
+ * Checks if internal IP filtering is enabled.
867
+ *
868
+ * @return bool
869
+ */
870
+ public function is_internal_ips_filtered() {
871
+ return $this->plugin->get_global_boolean_setting( 'filter-internal-ip', false );
872
  }
873
 
874
+ /**
875
+ * Enables or disables the internal IP filtering.
876
+ *
877
+ * @param bool $enabled True if internal IP filtering should be enabled.
878
+ */
879
+ public function set_internal_ips_filtering( $enabled ) {
880
+ $this->plugin->set_global_boolean_setting( 'filter-internal-ip', $enabled );
881
  }
882
 
883
  /**
885
  *
886
  * @return string|null
887
  */
888
+ public function get_main_client_ip() {
889
  $result = null;
890
 
891
+ if ( $this->is_main_ip_from_proxy() ) {
892
  // TODO: The algorithm below just gets the first IP in the list...we might want to make this more intelligent somehow.
893
+ $result = $this->get_client_ips();
894
  $result = reset( $result );
895
  $result = isset( $result[0] ) ? $result[0] : null;
896
  } elseif ( isset( $_SERVER['REMOTE_ADDR'] ) ) {
897
  $ip = sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) );
898
+ $result = $this->normalize_ip( $ip );
899
 
900
+ if ( ! $this->validate_ip( $result ) ) {
901
  $result = 'Error ' . self::ERROR_CODE_INVALID_IP . ': Invalid IP Address';
902
  }
903
  }
910
  *
911
  * @return array
912
  */
913
+ public function get_client_ips() {
914
  $ips = array();
915
 
916
  $proxy_headers = array(
922
  'HTTP_FORWARDED_FOR',
923
  'HTTP_FORWARDED',
924
  'REMOTE_ADDR',
925
+ // Cloudflare.
926
  'HTTP_CF-Connecting-IP',
927
+ 'HTTP_TRUE_CLIENT_IP',
928
  );
929
  foreach ( $proxy_headers as $key ) {
930
  if ( isset( $_SERVER[ $key ] ) ) {
931
  $ips[ $key ] = array();
932
 
933
+ foreach ( explode( ',', $_SERVER[ $key ] ) as $ip ) { // phpcs:ignore
934
+ $ip = $this->normalize_ip( $ip );
935
+ if ( $this->validate_ip( $ip ) ) {
 
936
  $ips[ $key ][] = $ip;
937
  }
938
  }
947
  *
948
  * @param string $ip - IP address.
949
  * @return string
950
+ *
951
+ * phpcs:disable Squiz.PHP.CommentedOutCode.Found
952
  */
953
+ protected function normalize_ip( $ip ) {
954
  $ip = trim( $ip );
955
 
956
  if ( strpos( $ip, ':' ) !== false && substr_count( $ip, '.' ) === 3 && strpos( $ip, '[' ) === false ) {
972
  * @param string $ip - IP address.
973
  * @return string|bool
974
  */
975
+ protected function validate_ip( $ip ) {
976
  $opts = FILTER_FLAG_IPV4 | FILTER_FLAG_IPV6;
977
 
978
+ if ( $this->is_internal_ips_filtered() ) {
979
  $opts = $opts | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE;
980
  }
981
 
997
  }
998
 
999
  /**
1000
+ * Sets the users excluded from monitoring.
1001
+ *
1002
+ * @param array $users Users to be excluded.
1003
  */
1004
+ public function set_excluded_monitoring_users( $users ) {
1005
 
1006
+ $old_value = $this->plugin->get_global_setting( 'excluded-users', array() );
1007
+ $changes = $this->determine_added_and_removed_items( $old_value, implode( ',', $users ) );
1008
 
1009
+ if ( ! empty( $changes['added'] ) ) {
1010
+ foreach ( $changes['added'] as $user ) {
1011
+ $this->plugin->alerts->trigger_event(
1012
  6053,
1013
  array(
1014
  'user' => $user,
1018
  );
1019
  }
1020
  }
1021
+ if ( ! empty( $changes['removed'] ) && ! empty( $old_value ) ) {
1022
+ foreach ( $changes['removed'] as $user ) {
1023
+ $this->plugin->alerts->trigger_event(
1024
  6053,
1025
  array(
1026
  'user' => $user,
1027
+ 'previous_users' => empty( $old_value ) ? $this->tidy_blank_values( $old_value ) : str_replace( ',', ', ', $old_value ),
1028
  'EventType' => 'removed',
1029
  )
1030
  );
1031
  }
1032
  }
1033
 
1034
+ $this->excluded_users = $users;
1035
+ $this->plugin->set_global_setting( 'excluded-users', esc_html( implode( ',', $this->excluded_users ) ) );
1036
  }
1037
 
1038
+ /**
1039
+ * Retrieves the users excluded from monitoring.
1040
+ *
1041
+ * @return array Users excluded from monitoring.
1042
+ */
1043
+ public function get_excluded_monitoring_users() {
1044
+ if ( empty( $this->excluded_users ) ) {
1045
+ $this->excluded_users = array_unique( array_filter( explode( ',', $this->plugin->get_global_setting( 'excluded-users' ) ) ) );
1046
  }
1047
+ return $this->excluded_users;
1048
  }
1049
 
1050
  /**
1055
  */
1056
  public function set_excluded_post_types( $post_types ) {
1057
 
1058
+ $old_value = $this->plugin->get_global_setting( 'custom-post-types', array() );
1059
+ $changes = $this->determine_added_and_removed_items( $old_value, implode( ',', $post_types ) );
1060
 
1061
+ if ( ! empty( $changes['added'] ) ) {
1062
+ foreach ( $changes['added'] as $post_type ) {
1063
+ $this->plugin->alerts->trigger_event(
1064
  6056,
1065
  array(
1066
  'post_type' => $post_type,
1071
  }
1072
  }
1073
 
1074
+ if ( ! empty( $changes['removed'] ) && ! empty( $old_value ) ) {
1075
+ foreach ( $changes['removed'] as $post_type ) {
1076
+ $this->plugin->alerts->trigger_event(
1077
  6056,
1078
  array(
1079
  'post_type' => $post_type,
1080
+ 'previous_types' => empty( $old_value ) ? $this->tidy_blank_values( $old_value ) : str_replace( ',', ', ', $old_value ),
1081
  'EventType' => 'removed',
1082
  )
1083
  );
1084
  }
1085
  }
1086
 
1087
+ $this->post_types = $post_types;
1088
+ $this->plugin->set_global_setting( 'custom-post-types', esc_html( implode( ',', $this->post_types ) ) );
1089
  }
1090
 
1091
  /**
1094
  * @since 2.6.7
1095
  */
1096
  public function get_excluded_post_types() {
1097
+ if ( empty( $this->post_types ) ) {
1098
+ $this->post_types = array_unique( array_filter( explode( ',', $this->plugin->get_global_setting( 'custom-post-types' ) ) ) );
1099
  }
1100
+ return $this->post_types;
1101
  }
1102
 
1103
  /**
1105
  *
1106
  * @param array $roles - Array of roles.
1107
  */
1108
+ public function set_excluded_monitoring_roles( $roles ) {
1109
 
1110
  // Trigger alert.
1111
+ $old_value = $this->plugin->get_global_setting( 'excluded-roles', array() );
1112
+ $changes = $this->determine_added_and_removed_items( $old_value, implode( ',', $roles ) );
1113
 
1114
+ if ( ! empty( $changes['added'] ) ) {
1115
+ foreach ( $changes['added'] as $user ) {
1116
+ $this->plugin->alerts->trigger_event(
1117
  6054,
1118
  array(
1119
  'role' => $user,
1123
  );
1124
  }
1125
  }
1126
+ if ( ! empty( $changes['removed'] ) && ! empty( $old_value ) ) {
1127
+ foreach ( $changes['removed'] as $user ) {
1128
+ $this->plugin->alerts->trigger_event(
1129
  6054,
1130
  array(
1131
  'role' => $user,
1132
+ 'previous_users' => empty( $old_value ) ? $this->tidy_blank_values( $old_value ) : str_replace( ',', ', ', $old_value ),
1133
  'EventType' => 'removed',
1134
  )
1135
  );
1136
  }
1137
  }
1138
 
1139
+ $this->excluded_roles = $roles;
1140
+ $this->plugin->set_global_setting( 'excluded-roles', esc_html( implode( ',', $roles ) ) );
1141
  }
1142
 
1143
  /**
1144
  * Get roles excluded from monitoring.
1145
  */
1146
+ public function get_excluded_monitoring_roles() {
1147
+ if ( empty( $this->excluded_roles ) ) {
1148
+ $this->excluded_roles = array_unique( array_filter( explode( ',', $this->plugin->get_global_setting( 'excluded-roles' ) ) ) );
1149
  }
1150
+ return $this->excluded_roles;
1151
  }
1152
 
1153
  /**
1154
  * Updates custom post meta fields excluded from monitoring.
1155
  *
1156
+ * @param array $custom Excluded post meta fields.
1157
  */
1158
+ public function set_excluded_post_meta_fields( $custom ) {
1159
+ $old_value = $this->get_excluded_post_meta_fields();
1160
+ $changes = $this->determine_added_and_removed_items( $old_value, implode( ',', $custom ) );
1161
 
1162
+ if ( ! empty( $changes['added'] ) ) {
1163
+ foreach ( $changes['added'] as $custom_field ) {
1164
+ $this->plugin->alerts->trigger_event(
1165
  6057,
1166
  array(
1167
  'custom_field' => $custom_field,
1168
  'previous_fields' => ( empty( $old_value ) ) ? $this->tidy_blank_values( $old_value ) : str_replace( ',', ', ', $old_value ),
1169
+ 'EventType' => 'added',
1170
  )
1171
  );
1172
  }
1173
  }
1174
 
1175
+ if ( ! empty( $changes['removed'] ) && ! empty( $old_value ) ) {
1176
+ foreach ( $changes['removed'] as $custom_field ) {
1177
+ $this->plugin->alerts->trigger_event(
1178
  6057,
1179
  array(
1180
  'custom_field' => $custom_field,
1181
+ 'previous_fields' => empty( $old_value ) ? $this->tidy_blank_values( $old_value ) : str_replace( ',', ', ', $old_value ),
1182
+ 'EventType' => 'removed',
1183
  )
1184
  );
1185
  }
1186
  }
1187
 
1188
+ $this->excluded_post_meta = $custom;
1189
+ $this->plugin->set_global_setting( 'excluded-post-meta', esc_html( implode( ',', $this->excluded_post_meta ) ) );
1190
  }
1191
 
1192
  /**
1194
  *
1195
  * @return array
1196
  */
1197
+ public function get_excluded_post_meta_fields() {
1198
+ if ( empty( $this->excluded_post_meta ) ) {
1199
+ $this->excluded_post_meta = array_unique( array_filter( explode( ',', $this->plugin->get_global_setting( 'excluded-post-meta' ) ) ) );
1200
+ asort( $this->excluded_post_meta );
1201
  }
1202
+ return $this->excluded_post_meta;
1203
  }
1204
 
1205
  /**
1206
  * Updates custom user meta fields excluded from monitoring.
1207
  *
1208
+ * @param array $custom Custom user meta fields excluded from monitoring.
1209
  *
1210
  * @since 4.3.2
1211
  */
1212
+ public function set_excluded_user_meta_fields( $custom ) {
1213
 
1214
+ $old_value = $this->get_excluded_user_meta_fields();
1215
+ $changes = $this->determine_added_and_removed_items( $old_value, implode( ',', $custom ) );
1216
 
1217
+ if ( ! empty( $changes['added'] ) ) {
1218
+ foreach ( $changes['added'] as $custom_field ) {
1219
+ $this->plugin->alerts->trigger_event(
1220
  6058,
1221
  array(
1222
  'custom_field' => $custom_field,
1223
  'previous_fields' => ( empty( $old_value ) ) ? $this->tidy_blank_values( $old_value ) : str_replace( ',', ', ', $old_value ),
1224
+ 'EventType' => 'added',
1225
  )
1226
  );
1227
  }
1228
  }
1229
 
1230
+ if ( ! empty( $changes['removed'] ) && ! empty( $old_value ) ) {
1231
+ foreach ( $changes['removed'] as $custom_field ) {
1232
+ $this->plugin->alerts->trigger_event(
1233
  6058,
1234
  array(
1235
  'custom_field' => $custom_field,
1236
+ 'previous_fields' => empty( $old_value ) ? $this->tidy_blank_values( $old_value ) : str_replace( ',', ', ', $old_value ),
1237
+ 'EventType' => 'removed',
1238
  )
1239
  );
1240
  }
1241
  }
1242
 
1243
+ $this->excluded_user_meta = $custom;
1244
+ $this->plugin->set_global_setting( 'excluded-user-meta', esc_html( implode( ',', $this->excluded_user_meta ) ) );
1245
  }
1246
 
1247
  /**
1250
  * @return array
1251
  * @since 4.3.2
1252
  */
1253
+ public function get_excluded_user_meta_fields() {
1254
+ if ( empty( $this->excluded_user_meta ) ) {
1255
+ $this->excluded_user_meta = array_unique( array_filter( explode( ',', $this->plugin->get_global_setting( 'excluded-user-meta' ) ) ) );
1256
+ asort( $this->excluded_user_meta );
1257
  }
1258
 
1259
+ return $this->excluded_user_meta;
1260
  }
1261
 
1262
  /**
1263
  * IP excluded from monitoring.
1264
+ *
1265
+ * @param array $ip IP addresses to exclude from monitoring.
1266
  */
1267
+ public function set_excluded_monitoring_ip( $ip ) {
1268
+ $old_value = $this->plugin->get_global_setting( 'excluded-ip', array() );
1269
+ $changes = $this->determine_added_and_removed_items( $old_value, implode( ',', $ip ) );
1270
 
1271
+ if ( ! empty( $changes['added'] ) ) {
1272
+ foreach ( $changes['added'] as $user ) {
1273
+ $this->plugin->alerts->trigger_event(
1274
  6055,
1275
  array(
1276
  'ip' => $user,
1280
  );
1281
  }
1282
  }
1283
+ if ( ! empty( $changes['removed'] ) && ! empty( $old_value ) ) {
1284
+ foreach ( $changes['removed'] as $user ) {
1285
+ $this->plugin->alerts->trigger_event(
1286
  6055,
1287
  array(
1288
  'ip' => $user,
1289
+ 'previous_ips' => empty( $old_value ) ? $this->tidy_blank_values( $old_value ) : str_replace( ',', ', ', $old_value ),
1290
  'EventType' => 'removed',
1291
  )
1292
  );
1293
  }
1294
  }
1295
 
1296
+ $this->excluded_ip = $ip;
1297
+ $this->plugin->set_global_setting( 'excluded-ip', esc_html( implode( ',', $this->excluded_ip ) ) );
1298
  }
1299
 
1300
+ /**
1301
+ * Retrieves a list of IP addresses to exclude from monitoring.
1302
+ *
1303
+ * @return array List of IP addresses to exclude from monitoring.
1304
+ */
1305
+ public function get_excluded_monitoring_ip() {
1306
+ if ( empty( $this->excluded_ip ) ) {
1307
+ $this->excluded_ip = array_unique( array_filter( explode( ',', $this->plugin->get_global_setting( 'excluded-ip' ) ) ) );
1308
  }
1309
+ return $this->excluded_ip;
1310
  }
1311
 
1312
  /**
1316
  * Note: Format returned by this function is not compatible with JavaScript date and time picker widgets. Use
1317
  * functions GetTimeFormat and GetDateFormat for those.
1318
  *
1319
+ * @param boolean $line_break - True if line break otherwise false.
1320
+ * @param boolean $use_nb_space_for_am_pm True if non-breakable space should be placed before the AM/PM chars.
1321
  *
1322
  * @return string
1323
  */
1324
+ public function get_datetime_format( $line_break = true, $use_nb_space_for_am_pm = true ) {
1325
+ $result = $this->get_date_format();
1326
 
1327
  $result .= $line_break ? '<\b\r>' : ' ';
1328
 
1329
+ $time_format = $this->get_time_format();
1330
  $has_am_pm = false;
1331
  $am_pm_fraction = false;
1332
  $am_pm_pattern = '/(?i)(\s+A)/';
1341
  $time_format .= ':s'; // Add seconds to time format.
1342
  }
1343
 
1344
+ if ( $this->get_show_milliseconds() ) {
1345
  $time_format .= '.$$$'; // Add milliseconds to time format.
1346
  }
1347
 
 
1348
  if ( $has_am_pm ) {
1349
  $time_format .= preg_replace( '/\s/', $use_nb_space_for_am_pm ? '&\n\b\s\p;' : ' ', $am_pm_fraction );
1350
  }
1364
  *
1365
  * @return string
1366
  */
1367
+ public function get_date_format( $sanitized = false ) {
1368
  if ( $sanitized ) {
1369
  return 'Y-m-d';
1370
  }
1382
  *
1383
  * @return string
1384
  */
1385
+ public function get_time_format( $sanitize = false ) {
1386
  $result = get_option( 'time_format' );
1387
  if ( $sanitize ) {
1388
  $search = array( 'a', 'A', 'T', ' ' );
1397
  *
1398
  * Server's timezone or WordPress' timezone.
1399
  */
1400
+ public function get_timezone() {
1401
+ return $this->plugin->get_global_setting( 'timezone', 'wp' );
1402
  }
1403
 
1404
+ /**
1405
+ * Updates the timezone handling setting.
1406
+ *
1407
+ * @param string $newvalue New setting value.
1408
+ *
1409
+ * @return void
1410
+ */
1411
+ public function set_timezone( $newvalue ) {
1412
+ $this->plugin->set_global_setting( 'timezone', $newvalue );
1413
  }
1414
 
1415
  /**
1421
  * @return bool
1422
  */
1423
  public function get_show_milliseconds() {
1424
+ return $this->plugin->get_global_boolean_setting( 'show_milliseconds', true );
1425
  }
1426
 
1427
  /**
1434
  * @param mixed $newvalue ideally always bool. If not bool then it's cast to true.
1435
  */
1436
  public function set_show_milliseconds( $newvalue ) {
1437
+ $this->plugin->set_global_boolean_setting( 'show_milliseconds', $newvalue );
1438
  }
1439
 
1440
 
1442
  * Get type of username to display.
1443
  */
1444
  public function get_type_username() {
1445
+ return $this->plugin->get_global_setting( 'type_username', 'display_name' );
1446
  }
1447
 
1448
  /**
1452
  * @since 2.6.5
1453
  */
1454
  public function set_type_username( $newvalue ) {
1455
+ $this->plugin->set_global_setting( 'type_username', $newvalue );
1456
  }
1457
 
1458
  /**
1460
  *
1461
  * @return array
1462
  */
1463
+ public function get_columns() {
1464
  $columns = array(
1465
  'alert_code' => '1',
1466
  'type' => '1',
1474
  'info' => '1',
1475
  );
1476
 
1477
+ if ( $this->plugin->is_multisite() ) {
1478
  $columns = array_slice( $columns, 0, 6, true ) + array( 'site' => '1' ) + array_slice( $columns, 6, null, true );
1479
  }
1480
 
1481
+ $selected = $this->get_columns_selected();
1482
 
1483
  if ( ! empty( $selected ) ) {
1484
  $columns = array(
1493
  'message' => '0',
1494
  );
1495
 
1496
+ if ( $this->plugin->is_multisite() ) {
1497
  $columns = array_slice( $columns, 0, 6, true ) + array( 'site' => '0' ) + array_slice( $columns, 6, null, true );
1498
  }
1499
 
1504
  return $columns;
1505
  }
1506
 
1507
+ /**
1508
+ * Gets the list of columns selected for display in the audit log viewer.
1509
+ *
1510
+ * @return array List of columns selected for display in the audit log viewer
1511
+ */
1512
+ public function get_columns_selected() {
1513
+ return $this->plugin->get_global_setting( 'columns', array() );
1514
  }
1515
 
1516
+ /**
1517
+ * Sets the list of columns selected for display in the audit log viewer.
1518
+ *
1519
+ * @param array $columns List of columns selected for display in the audit log viewer.
1520
+ */
1521
+ public function set_columns( $columns ) {
1522
+ $this->plugin->set_global_setting( 'columns', json_encode( $columns ) ); // phpcs:ignore
1523
  }
1524
 
1525
+ /**
1526
+ * Checks if the monitoring of background events is enabled.
1527
+ *
1528
+ * @return bool True if the monitoring of background events is enabled.
1529
+ */
1530
+ public function is_wp_backend() {
1531
+ return $this->plugin->get_global_boolean_setting( 'wp-backend' );
1532
  }
1533
 
1534
+ /**
1535
+ * Enables or disables the monitoring of background events.
1536
+ *
1537
+ * @param bool $enabled True if the monitoring of background events should be enabled.
1538
+ */
1539
+ public function set_wp_backend( $enabled ) {
1540
+ $this->plugin->set_global_boolean_setting( 'wp-backend', $enabled );
1541
  }
1542
 
1543
  /**
1546
  * @param string $use – Setting value.
1547
  */
1548
  public function set_use_email( $use ) {
1549
+ $this->plugin->set_global_setting( 'use-email', $use );
1550
  }
1551
 
1552
  /**
1555
  * @return string
1556
  */
1557
  public function get_use_email() {
1558
+ return $this->plugin->get_global_setting( 'use-email', 'default_email' );
1559
  }
1560
 
1561
+ /**
1562
+ * Sets the "From" email address.
1563
+ *
1564
+ * @param string $email_address The "From" email address.
1565
+ */
1566
+ public function set_from_email( $email_address ) {
1567
+ $this->plugin->set_global_setting( 'from-email', trim( $email_address ) );
1568
  }
1569
 
1570
+ /**
1571
+ * Get the "From" email address.
1572
+ *
1573
+ * @return string The "From" email address.
1574
+ */
1575
+ public function get_from_email() {
1576
+ return $this->plugin->get_global_setting( 'from-email' );
1577
  }
1578
 
1579
+ /**
1580
+ * Sets the user display name for the event audit log.
1581
+ *
1582
+ * @param string $display_name User display name setting.
1583
+ *
1584
+ * @return void
1585
+ */
1586
+ public function set_display_name( $display_name ) {
1587
+ $this->plugin->set_global_setting( 'display-name', trim( $display_name ) );
1588
  }
1589
 
1590
+ /**
1591
+ * Gets the user display name for the event audit log.
1592
+ *
1593
+ * @return string User display name setting.
1594
+ */
1595
+ public function get_display_name() {
1596
+ return $this->plugin->get_global_setting( 'display-name' );
1597
  }
1598
 
1599
  /**
1604
  */
1605
  public function set_failed_login_limit( $value ) {
1606
  if ( ! empty( $value ) ) {
1607
+ $this->plugin->set_global_setting( 'log-failed-login-limit', abs( $value ) );
1608
  } else {
1609
+ $this->plugin->set_global_setting( 'log-failed-login-limit', - 1 );
1610
  }
1611
  }
1612
 
1617
  * @since 2.6.3
1618
  */
1619
  public function get_failed_login_limit() {
1620
+ return intval( $this->plugin->get_global_setting( 'log-failed-login-limit', 10 ) );
1621
  }
1622
 
1623
  /**
1628
  */
1629
  public function set_visitor_failed_login_limit( $value ) {
1630
  if ( ! empty( $value ) ) {
1631
+ $this->plugin->set_global_setting( 'log-visitor-failed-login-limit', abs( $value ) );
1632
  } else {
1633
+ $this->plugin->set_global_setting( 'log-visitor-failed-login-limit', - 1 );
1634
  }
1635
  }
1636
 
1641
  * @since 2.6.3
1642
  */
1643
  public function get_visitor_failed_login_limit() {
1644
+ return intval( $this->plugin->get_global_setting( 'log-visitor-failed-login-limit', 10 ) );
1645
  }
1646
 
1647
 
1661
  }
1662
 
1663
  // Check if the token matched users.
1664
+ if ( in_array( $token, $users ) ) { // phpcs:ignore
1665
  return 'user';
1666
  }
1667
 
1669
  $roles = array_keys( get_editable_roles() );
1670
 
1671
  // Check if the token matched user roles.
1672
+ if ( in_array( $token, $roles, true ) ) {
1673
  return 'role';
1674
  }
1675
 
1685
  }
1686
 
1687
  // Check if the token matched post types.
1688
+ if ( in_array( $token, $post_types, true ) ) {
1689
  return 'cpts';
1690
  }
1691
 
1731
  */
1732
  public function set_mainwp_child_stealth_mode() {
1733
  if (
1734
+ ! $this->plugin->get_global_boolean_setting( 'mwp-child-stealth-mode', false ) // MainWP Child Stealth Mode is not already active.
1735
  && WpSecurityAuditLog::is_mainwp_active() // And if MainWP Child plugin is installed & active.
1736
  ) {
1737
  // Check if freemius state is anonymous.
1738
+ if ( ! wsal_freemius()->is_premium() && 'anonymous' === $this->plugin->get_global_setting( 'freemius_state', 'anonymous' ) ) {
1739
  // Update Freemius state to skipped.
1740
+ $this->plugin->set_global_setting( 'wsal_freemius_state', 'skipped', true );
1741
 
1742
+ if ( ! $this->plugin->is_multisite() ) {
1743
  wsal_freemius()->skip_connection(); // Opt out.
1744
  } else {
1745
  wsal_freemius()->skip_connection( null, true ); // Opt out for all websites.
1754
  FS_Admin_Notices::instance( 'wp-security-audit-log' )->remove_sticky( 'trial_promotion' );
1755
  }
1756
 
1757
+ $this->set_incognito( true ); // Incognito mode to hide WSAL on plugins page.
1758
  $this->set_restrict_log_viewer( 'only_me' );
1759
  $this->set_restrict_plugin_setting( 'only_me' );
1760
  // Current user with fallback to default admin (in case this is triggered using WP CLI or something similar).
1761
  $only_me_user_id = is_user_logged_in() ? get_current_user_id() : 1;
1762
  $this->set_only_me_user_id( $only_me_user_id );
1763
+ $this->plugin->set_global_boolean_setting( 'mwp-child-stealth-mode', true ); // Save stealth mode option.
1764
  }
1765
  }
1766
 
1770
  * @since 3.2.3.3
1771
  */
1772
  public function deactivate_mainwp_child_stealth_mode() {
1773
+ $this->set_incognito( false ); // Disable incognito mode to hide WSAL on plugins page.
1774
  $this->set_restrict_plugin_setting( 'only_admins' );
1775
  $this->set_restrict_log_viewer( 'only_admins' );
1776
  $this->set_admin_blocking_plugin_support( false );
1777
+ $this->plugin->set_global_boolean_setting( 'mwp-child-stealth-mode', false ); // Disable stealth mode option.
1778
  }
1779
 
1780
  /**
1787
  return;
1788
  }
1789
 
1790
+ if ( $this->plugin->get_global_boolean_setting( 'mwp-child-stealth-mode', false ) ) {
1791
  $this->deactivate_mainwp_child_stealth_mode();
1792
  }
1793
  }
1798
  * @return boolean
1799
  */
1800
  public function is_stealth_mode() {
1801
+ return $this->plugin->get_global_boolean_setting( 'mwp-child-stealth-mode', false );
1802
  }
1803
 
1804
  /**
1811
  public function get_view_site_id() {
1812
  switch ( true ) {
1813
  // Non-multisite.
1814
+ case ! $this->plugin->is_multisite():
1815
  return 0;
1816
  // Multisite + main site view.
1817
  case $this->is_main_blog() && ! $this->is_specific_view():
1844
  * @return bool
1845
  */
1846
  protected function is_specific_view() {
1847
+ return isset( $_REQUEST['wsal-cbid'] ) && 0 !== (int) $_REQUEST['wsal-cbid']; // phpcs:ignore
1848
  }
1849
 
1850
  /**
1855
  * @return int
1856
  */
1857
  protected function get_specific_view() {
1858
+ return isset( $_REQUEST['wsal-cbid'] ) ? (int) sanitize_text_field( wp_unslash( $_REQUEST['wsal-cbid'] ) ) : 0; // phpcs:ignore
1859
  }
1860
 
1861
  /**
1873
  if ( ! is_null( $limit ) ) {
1874
  $sql .= ' LIMIT ' . $limit;
1875
  }
1876
+ $res = $wpdb->get_results( $sql ); // phpcs:ignore
1877
  foreach ( $res as $row ) {
1878
  $row->blogname = get_blog_option( $row->blog_id, 'blogname' );
1879
  }
1890
  public function get_site_count() {
1891
  global $wpdb;
1892
  $sql = 'SELECT COUNT(*) FROM ' . $wpdb->blogs;
1893
+ return (int) $wpdb->get_var( $sql ); // phpcs:ignore
1894
  }
1895
 
1896
  /**
1916
  * @return string
1917
  */
1918
  public function get_events_type_nav() {
1919
+ return $this->plugin->get_global_setting( 'events-nav-type', 'infinite-scroll' );
1920
  }
1921
 
1922
  /**
1929
  * @param string $nav_type - Navigation type.
1930
  */
1931
  public function set_events_type_nav( $nav_type ) {
1932
+ $this->plugin->set_global_setting( 'events-nav-type', $nav_type );
1933
  }
1934
 
1935
  /**
1939
  */
1940
  public function get_plugin_settings() {
1941
  global $wpdb;
1942
+ return $wpdb->get_results( "SELECT * FROM $wpdb->options WHERE option_name LIKE 'wsal_%'" ); // phpcs:ignore
1943
  }
1944
 
1945
  /**
2158
  * @since 4.1.3
2159
  */
2160
  public function set_only_me_user_id( $user_id ) {
2161
+ $this->plugin->set_global_setting( 'only-me-user-id', $user_id, true );
2162
  }
2163
 
2164
  /**
2168
  * @since 4.1.3
2169
  */
2170
  public function get_only_me_user_id() {
2171
+ return (int) $this->plugin->get_global_setting( 'only-me-user-id' );
2172
  }
2173
 
2174
  /**
2175
  * Save admin blocking plugin support enabled.
2176
  *
2177
+ * @param bool $enabled True, if admin blocking plugin support should be enabled.
2178
  */
2179
  public function set_admin_blocking_plugin_support( $enabled ) {
2180
+ $this->plugin->set_global_boolean_setting( 'admin-blocking-plugins-support', $enabled );
2181
  }
2182
 
2183
  /**
2190
  * @return bool
2191
  */
2192
  public function get_admin_blocking_plugin_support() {
2193
+ return $this->plugin->get_global_boolean_setting( 'admin-blocking-plugins-support', false );
2194
  }
2195
 
2196
+ /**
2197
+ * Retrieves the settings enforced by MainWP from local database.
2198
+ *
2199
+ * @return array Settings enforced by MainWP.
2200
+ */
2201
  public function get_mainwp_enforced_settings() {
2202
+ return $this->plugin->get_global_setting( 'mainwp_enforced_settings', array() );
2203
  }
2204
 
2205
+ /**
2206
+ * Stores the settings enforced by MainWP in local database.
2207
+ *
2208
+ * @param array $settings Enforced settings.
2209
+ */
2210
  public function set_mainwp_enforced_settings( $settings ) {
2211
+ $this->plugin->set_global_setting( 'mainwp_enforced_settings', $settings );
2212
  }
2213
 
2214
+ /**
2215
+ * Deletes the settings enforced by MainWP from local database.
2216
+ */
2217
  public function delete_mainwp_enforced_settings() {
2218
+ $this->plugin->delete_global_setting( 'mainwp_enforced_settings' );
2219
  }
2220
 
2221
+ /**
2222
+ * Determines added and removed items between 2 arrays.
2223
+ *
2224
+ * @param array|string $old_value Old list. Support comma separated string.
2225
+ * @param array|string $value New list. Support comma separated string.
2226
+ *
2227
+ * @return array
2228
+ */
2229
  public function determine_added_and_removed_items( $old_value, $value ) {
2230
  $old_value = ( ! is_array( $old_value ) ) ? explode( ',', $old_value ) : $old_value;
2231
  $value = ( ! is_array( $value ) ) ? explode( ',', $value ) : $value;
2236
  return $return;
2237
  }
2238
 
2239
+ /**
2240
+ * Tidies-up the blank values.
2241
+ *
2242
+ * @param string $value Value.
2243
+ *
2244
+ * @return string Tidies up value.
2245
+ */
2246
  public function tidy_blank_values( $value ) {
2247
  return ( empty( $value ) ) ? __( 'None provided', 'wp-security-audit-log' ) : $value;
2248
  }
2254
  * @since 4.3.2
2255
  */
2256
  public function get_database_version() {
2257
+ return (int) $this->plugin->get_global_setting( 'db_version', 0 );
2258
  }
2259
 
2260
  /**
2264
  * @since 4.3.2
2265
  */
2266
  public function set_database_version( $version ) {
2267
+ $this->plugin->set_global_setting( 'db_version', $version, true );
2268
  }
2269
 
2270
  }
classes/ThirdPartyExtensions/AbstractExtension.php CHANGED
@@ -1,30 +1,48 @@
1
  <?php
 
 
 
 
 
 
2
 
3
  if ( ! class_exists( 'WSAL_AbstractExtension' ) ) {
4
 
 
 
 
 
 
 
5
  abstract class WSAL_AbstractExtension {
6
 
7
  /**
 
 
8
  * @var WSAL_AbstractExtension[]
9
  * @since 4.3.2
10
  */
11
- private static $extensions = [];
12
 
13
  /**
 
 
14
  * @var WSAL_AbstractExtension[]
15
  * @since 4.3.2
16
  */
17
  private static $post_types_map;
18
 
19
  /**
20
- * @param string $post_type
 
 
21
  *
22
  * @return WSAL_AbstractExtension|null
23
  * @since 4.3.2
24
  */
25
  public static function get_extension_for_post_type( $post_type ) {
26
  if ( is_null( self::$post_types_map ) ) {
27
- self::$post_types_map = [];
28
  if ( ! empty( self::$extensions ) ) {
29
  foreach ( self::$extensions as $extension ) {
30
  $post_types = $extension->get_custom_post_types();
@@ -46,13 +64,15 @@ if ( ! class_exists( 'WSAL_AbstractExtension' ) ) {
46
 
47
  /**
48
  * WSAL_AbstractExtension constructor.
49
- *
50
  */
51
  public function __construct() {
52
  array_push( self::$extensions, $this );
53
  $this->add_filters();
54
  }
55
 
 
 
 
56
  public function add_filters() {
57
  add_filter( 'wsal_filter_installable_plugins', array( $this, 'filter_installable_plugins' ), 10, 1 );
58
  add_filter( 'wsal_addon_event_codes', array( $this, 'add_event_codes' ), 10, 1 );
@@ -95,17 +115,32 @@ if ( ! class_exists( 'WSAL_AbstractExtension' ) ) {
95
  * @since 4.3.2
96
  */
97
  public function get_custom_post_types() {
98
- return [];
99
  }
100
 
 
 
 
 
 
101
  abstract public function get_plugin_name();
102
 
 
 
 
 
 
103
  abstract public function get_plugin_icon_url();
104
 
 
 
 
 
 
105
  abstract public function get_color();
106
 
107
  /**
108
- * Gets the filename of the plugin this extension is targetting.
109
  *
110
  * @return string Filename.
111
  *
1
  <?php
2
+ /**
3
+ * Abstract WSAL extension class.
4
+ *
5
+ * @package wsal
6
+ * @subpackage add-ons
7
+ */
8
 
9
  if ( ! class_exists( 'WSAL_AbstractExtension' ) ) {
10
 
11
+ /**
12
+ * Abstract class to provide basic information about a specific WSAL extension.
13
+ *
14
+ * @package wsal
15
+ * @subpackage add-ons
16
+ */
17
  abstract class WSAL_AbstractExtension {
18
 
19
  /**
20
+ * List of extensions.
21
+ *
22
  * @var WSAL_AbstractExtension[]
23
  * @since 4.3.2
24
  */
25
+ private static $extensions = array();
26
 
27
  /**
28
+ * A map of custom post types specific to each extension (if any).
29
+ *
30
  * @var WSAL_AbstractExtension[]
31
  * @since 4.3.2
32
  */
33
  private static $post_types_map;
34
 
35
  /**
36
+ * Retrieves an extension class associated with given pst type.
37
+ *
38
+ * @param string $post_type Post type.
39
  *
40
  * @return WSAL_AbstractExtension|null
41
  * @since 4.3.2
42
  */
43
  public static function get_extension_for_post_type( $post_type ) {
44
  if ( is_null( self::$post_types_map ) ) {
45
+ self::$post_types_map = array();
46
  if ( ! empty( self::$extensions ) ) {
47
  foreach ( self::$extensions as $extension ) {
48
  $post_types = $extension->get_custom_post_types();
64
 
65
  /**
66
  * WSAL_AbstractExtension constructor.
 
67
  */
68
  public function __construct() {
69
  array_push( self::$extensions, $this );
70
  $this->add_filters();
71
  }
72
 
73
+ /**
74
+ * Initialises necessary filters.
75
+ */
76
  public function add_filters() {
77
  add_filter( 'wsal_filter_installable_plugins', array( $this, 'filter_installable_plugins' ), 10, 1 );
78
  add_filter( 'wsal_addon_event_codes', array( $this, 'add_event_codes' ), 10, 1 );
115
  * @since 4.3.2
116
  */
117
  public function get_custom_post_types() {
118
+ return array();
119
  }
120
 
121
+ /**
122
+ * Retrieves a plugin name.
123
+ *
124
+ * @return string Plugin name.
125
+ */
126
  abstract public function get_plugin_name();
127
 
128
+ /**
129
+ * Gets a plugin icon URL.
130
+ *
131
+ * @return string Plugin icon URL.
132
+ */
133
  abstract public function get_plugin_icon_url();
134
 
135
+ /**
136
+ * Retrieves the color to use when showing some info about the extension.
137
+ *
138
+ * @return string HEX color.
139
+ */
140
  abstract public function get_color();
141
 
142
  /**
143
+ * Gets the filename of the plugin this extension is targeting.
144
  *
145
  * @return string Filename.
146
  *
classes/ThirdPartyExtensions/BBPressExtension.php CHANGED
@@ -1,9 +1,24 @@
1
  <?php
 
 
 
 
 
 
2
 
3
  if ( ! class_exists( 'WSAL_BBPressExtension' ) ) {
4
 
 
 
 
 
 
 
5
  class WSAL_BBPressExtension extends WSAL_AbstractExtension {
6
 
 
 
 
7
  public function filter_installable_plugins( $plugins ) {
8
  $new_plugin = array(
9
  array(
@@ -22,6 +37,9 @@ if ( ! class_exists( 'WSAL_BBPressExtension' ) ) {
22
  return array_merge( $plugins, $new_plugin );
23
  }
24
 
 
 
 
25
  public function add_event_codes( $addon_event_codes ) {
26
  $new_event_codes = array(
27
  'bbpress' => array(
@@ -34,22 +52,37 @@ if ( ! class_exists( 'WSAL_BBPressExtension' ) ) {
34
  return array_merge( $addon_event_codes, $new_event_codes );
35
  }
36
 
 
 
 
37
  public function get_custom_post_types() {
38
  return array( 'forum', 'topic', 'reply' );
39
  }
40
 
 
 
 
41
  public function get_plugin_name() {
42
- return 'BBPress';
43
  }
44
 
 
 
 
45
  public function get_plugin_icon_url() {
46
  return 'https://ps.w.org/wp-security-audit-log-add-on-for-bbpress/assets/icon-128x128.png?rev=2253395';
47
  }
48
 
 
 
 
49
  public function get_color() {
50
  return '#8dc770';
51
  }
52
 
 
 
 
53
  public function get_plugin_filename() {
54
  return 'wp-security-audit-log-add-on-for-bbpress/wsal-bbpress.php';
55
  }
1
  <?php
2
+ /**
3
+ * The bbPress extension class.
4
+ *
5
+ * @package wsal
6
+ * @subpackage add-ons
7
+ */
8
 
9
  if ( ! class_exists( 'WSAL_BBPressExtension' ) ) {
10
 
11
+ /**
12
+ * Class provides basic information about WSAL extension for bbPress.
13
+ *
14
+ * @package wsal
15
+ * @subpackage add-ons
16
+ */
17
  class WSAL_BBPressExtension extends WSAL_AbstractExtension {
18
 
19
+ /**
20
+ * {@inheritDoc}
21
+ */
22
  public function filter_installable_plugins( $plugins ) {
23
  $new_plugin = array(
24
  array(
37
  return array_merge( $plugins, $new_plugin );
38
  }
39
 
40
+ /**
41
+ * {@inheritDoc}
42
+ */
43
  public function add_event_codes( $addon_event_codes ) {
44
  $new_event_codes = array(
45
  'bbpress' => array(
52
  return array_merge( $addon_event_codes, $new_event_codes );
53
  }
54
 
55
+ /**
56
+ * {@inheritDoc}
57
+ */
58
  public function get_custom_post_types() {
59
  return array( 'forum', 'topic', 'reply' );
60
  }
61
 
62
+ /**
63
+ * {@inheritDoc}
64
+ */
65
  public function get_plugin_name() {
66
+ return 'bbPress';
67
  }
68
 
69
+ /**
70
+ * {@inheritDoc}
71
+ */
72
  public function get_plugin_icon_url() {
73
  return 'https://ps.w.org/wp-security-audit-log-add-on-for-bbpress/assets/icon-128x128.png?rev=2253395';
74
  }
75
 
76
+ /**
77
+ * {@inheritDoc}
78
+ */
79
  public function get_color() {
80
  return '#8dc770';
81
  }
82
 
83
+ /**
84
+ * {@inheritDoc}
85
+ */
86
  public function get_plugin_filename() {
87
  return 'wp-security-audit-log-add-on-for-bbpress/wsal-bbpress.php';
88
  }
classes/ThirdPartyExtensions/GravityFormsExtension.php CHANGED
@@ -1,9 +1,24 @@
1
  <?php
 
 
 
 
 
 
2
 
3
  if ( ! class_exists( 'WSAL_GravityFormsExtension' ) ) {
4
 
 
 
 
 
 
 
5
  class WSAL_GravityFormsExtension extends WSAL_AbstractExtension {
6
 
 
 
 
7
  public function filter_installable_plugins( $plugins ) {
8
  $new_plugin = array(
9
  array(
@@ -14,13 +29,16 @@ if ( ! class_exists( 'WSAL_GravityFormsExtension' ) ) {
14
  'plugin_url' => 'https://downloads.wordpress.org/plugin/activity-log-gravity-forms.latest-stable.zip',
15
  'event_tab_id' => '#cat-gravity-forms',
16
  'plugin_description' => __( 'Keep a record of when someone adds, modifies or deletes forms, entries and more in the Gravity Forms plugin.', 'wp-security-audit-log' ),
17
- )
18
  );
19
 
20
  // combine the two arrays.
21
  return array_merge( $plugins, $new_plugin );
22
  }
23
 
 
 
 
24
  public function add_event_codes( $addon_event_codes ) {
25
  $new_event_codes = array(
26
  'gravityforms' => array(
@@ -30,21 +48,33 @@ if ( ! class_exists( 'WSAL_GravityFormsExtension' ) ) {
30
  );
31
 
32
  // combine the two arrays.
33
- return array_merge( $addon_event_codes, $new_event_codes );
34
  }
35
 
 
 
 
36
  public function get_plugin_name() {
37
  return 'Gravity Forms';
38
  }
39
 
 
 
 
40
  public function get_plugin_icon_url() {
41
  return 'https://ps.w.org/activity-log-gravity-forms/assets/icon-128x128.png?rev=2465070';
42
  }
43
 
 
 
 
44
  public function get_color() {
45
  return '#F15A29';
46
  }
47
 
 
 
 
48
  public function get_plugin_filename() {
49
  return 'activity-log-gravity-forms/activity-log-gravity-forms.php';
50
  }
1
  <?php
2
+ /**
3
+ * Gravity Forms extension class.
4
+ *
5
+ * @package wsal
6
+ * @subpackage add-ons
7
+ */
8
 
9
  if ( ! class_exists( 'WSAL_GravityFormsExtension' ) ) {
10
 
11
+ /**
12
+ * Class provides basic information about WSAL extension for Gravity Forms.
13
+ *
14
+ * @package wsal
15
+ * @subpackage add-ons
16
+ */
17
  class WSAL_GravityFormsExtension extends WSAL_AbstractExtension {
18
 
19
+ /**
20
+ * {@inheritDoc}
21
+ */
22
  public function filter_installable_plugins( $plugins ) {
23
  $new_plugin = array(
24
  array(
29
  'plugin_url' => 'https://downloads.wordpress.org/plugin/activity-log-gravity-forms.latest-stable.zip',
30
  'event_tab_id' => '#cat-gravity-forms',
31
  'plugin_description' => __( 'Keep a record of when someone adds, modifies or deletes forms, entries and more in the Gravity Forms plugin.', 'wp-security-audit-log' ),
32
+ ),
33
  );
34
 
35
  // combine the two arrays.
36
  return array_merge( $plugins, $new_plugin );
37
  }
38
 
39
+ /**
40
+ * {@inheritDoc}
41
+ */
42
  public function add_event_codes( $addon_event_codes ) {
43
  $new_event_codes = array(
44
  'gravityforms' => array(
48
  );
49
 
50
  // combine the two arrays.
51
+ return array_merge( $addon_event_codes, $new_event_codes );
52
  }
53
 
54
+ /**
55
+ * {@inheritDoc}
56
+ */
57
  public function get_plugin_name() {
58
  return 'Gravity Forms';
59
  }
60
 
61
+ /**
62
+ * {@inheritDoc}
63
+ */
64
  public function get_plugin_icon_url() {
65
  return 'https://ps.w.org/activity-log-gravity-forms/assets/icon-128x128.png?rev=2465070';
66
  }
67
 
68
+ /**
69
+ * {@inheritDoc}
70
+ */
71
  public function get_color() {
72
  return '#F15A29';
73
  }
74
 
75
+ /**
76
+ * {@inheritDoc}
77
+ */
78
  public function get_plugin_filename() {
79
  return 'activity-log-gravity-forms/activity-log-gravity-forms.php';
80
  }
classes/ThirdPartyExtensions/TablePressExtension.php CHANGED
@@ -1,9 +1,24 @@
1
  <?php
 
 
 
 
 
 
2
 
3
  if ( ! class_exists( 'WSAL_TablePressExtension' ) ) {
4
 
 
 
 
 
 
 
5
  class WSAL_TablePressExtension extends WSAL_AbstractExtension {
6
 
 
 
 
7
  public function filter_installable_plugins( $plugins ) {
8
  $new_plugin = array(
9
  array(
@@ -22,6 +37,9 @@ if ( ! class_exists( 'WSAL_TablePressExtension' ) ) {
22
  return array_merge( $plugins, $new_plugin );
23
  }
24
 
 
 
 
25
  public function add_event_codes( $addon_event_codes ) {
26
  $new_event_codes = array(
27
  'yoast' => array(
@@ -34,22 +52,37 @@ if ( ! class_exists( 'WSAL_TablePressExtension' ) ) {
34
  return array_merge( $addon_event_codes, $new_event_codes );
35
  }
36
 
 
 
 
37
  public function get_custom_post_types() {
38
  return array( 'tablepress_table' );
39
  }
40
 
 
 
 
41
  public function get_plugin_name() {
42
  return 'TablePress';
43
  }
44
 
 
 
 
45
  public function get_plugin_icon_url() {
46
  return 'https://ps.w.org/activity-log-tablepress/assets/icon-128x128.png?rev=2393849';
47
  }
48
 
 
 
 
49
  public function get_color() {
50
  return '#a4286a';
51
  }
52
 
 
 
 
53
  public function get_plugin_filename() {
54
  return 'activity-log-tablepress/wsal-tablepress.php';
55
  }
1
  <?php
2
+ /**
3
+ * TablePress extension class.
4
+ *
5
+ * @package wsal
6
+ * @subpackage add-ons
7
+ */
8
 
9
  if ( ! class_exists( 'WSAL_TablePressExtension' ) ) {
10
 
11
+ /**
12
+ * Class provides basic information about WSAL extension for TablePress.
13
+ *
14
+ * @package wsal
15
+ * @subpackage add-ons
16
+ */
17
  class WSAL_TablePressExtension extends WSAL_AbstractExtension {
18
 
19
+ /**
20
+ * {@inheritDoc}
21
+ */
22
  public function filter_installable_plugins( $plugins ) {
23
  $new_plugin = array(
24
  array(
37
  return array_merge( $plugins, $new_plugin );
38
  }
39
 
40
+ /**
41
+ * {@inheritDoc}
42
+ */
43
  public function add_event_codes( $addon_event_codes ) {
44
  $new_event_codes = array(
45
  'yoast' => array(
52
  return array_merge( $addon_event_codes, $new_event_codes );
53
  }
54
 
55
+ /**
56
+ * {@inheritDoc}
57
+ */
58
  public function get_custom_post_types() {
59
  return array( 'tablepress_table' );
60
  }
61
 
62
+ /**
63
+ * {@inheritDoc}
64
+ */
65
  public function get_plugin_name() {
66
  return 'TablePress';
67
  }
68
 
69
+ /**
70
+ * {@inheritDoc}
71
+ */
72
  public function get_plugin_icon_url() {
73
  return 'https://ps.w.org/activity-log-tablepress/assets/icon-128x128.png?rev=2393849';
74
  }
75
 
76
+ /**
77
+ * {@inheritDoc}
78
+ */
79
  public function get_color() {
80
  return '#a4286a';
81
  }
82
 
83
+ /**
84
+ * {@inheritDoc}
85
+ */
86
  public function get_plugin_filename() {
87
  return 'activity-log-tablepress/wsal-tablepress.php';
88
  }
classes/ThirdPartyExtensions/WFCMExtension.php CHANGED
@@ -1,13 +1,31 @@
1
  <?php
 
 
 
 
 
 
2
 
3
  if ( ! class_exists( 'WSAL_WFCMExtension' ) ) {
4
 
 
 
 
 
 
 
5
  class WSAL_WFCMExtension extends WSAL_AbstractExtension {
6
 
 
 
 
7
  public function __construct() {
8
- add_filter( 'wsal_append_dailynotification_email_content', [ $this, 'append_dailynotification_email_content' ], 10, 2 );
9
  }
10
 
 
 
 
11
  public function filter_installable_plugins( $plugins ) {
12
  $new_plugin = array(
13
  array(
@@ -19,13 +37,16 @@ if ( ! class_exists( 'WSAL_WFCMExtension' ) ) {
19
  'plugin_url' => 'https://downloads.wordpress.org/plugin/website-file-changes-monitor.latest-stable.zip',
20
  'event_tab_id' => '#cat-wfcm',
21
  'plugin_description' => 'To keep a log of file changes please install Website File Changes Monitor, a plugin which is also developed by us.',
22
- )
23
  );
24
 
25
  // combine the two arrays.
26
  return array_merge( $plugins, $new_plugin );
27
  }
28
 
 
 
 
29
  public function add_event_codes( $addon_event_codes ) {
30
  $new_event_codes = array(
31
  'wfcm' => array(
@@ -38,18 +59,35 @@ if ( ! class_exists( 'WSAL_WFCMExtension' ) ) {
38
  return array_merge( $addon_event_codes, $new_event_codes );
39
  }
40
 
 
 
 
41
  public function get_plugin_name() {
42
  return 'Website File Changes Monitor';
43
  }
44
 
 
 
 
45
  public function get_plugin_icon_url() {
46
  return 'https://ps.w.org/website-file-changes-monitor/assets/icon-128x128.png?rev=2393849';
47
  }
48
 
 
 
 
49
  public function get_color() {
50
  return '#a4286a';
51
  }
52
 
 
 
 
 
 
 
 
 
53
  public function append_dailynotification_email_content( $body, $events ) {
54
 
55
  if ( ! empty( $events ) ) {
@@ -69,7 +107,7 @@ if ( ! class_exists( 'WSAL_WFCMExtension' ) ) {
69
  if ( ! empty( $files_added ) || ! empty( $files_modified ) || ! empty( $files_deleted ) ) {
70
  $body .= '<!-- Website File Changes Start --><tr><td><table width="100%" cellpadding="0" cellspacing="0" border="0"><!-- Title Start --><tr><td style="font-family: Verdana, sans-serif; font-weight: bold; font-size: 20px; line-height: 28px; color: #404040; text-align: left; padding-bottom: 13px;">Website File Changes</td></tr><!-- Title End --><!-- Desc Start --><!-- Table Border Start --><tr><td style="padding-bottom: 40px;"><table width="100%" cellpadding="0" cellspacing="0" border="0">';
71
 
72
- $body .= '<tr><td style="font-family: Verdana, sans-serif; font-weight: normal; font-size: 16px; line-height: 28px; color: #404040;padding-bottom: 20px;">During the last file integrity scan on '. date( 'd/m/Y', get_option( 'wfcm_last-scan-timestamp' ) ) .' at '. date( 'H:i:s', get_option( 'wfcm_last-scan-timestamp' ) ) .' we detected the following file changes:</td></tr>';
73
 
74
  if ( ! empty( $files_added ) ) {
75
  $body .= '<tr><td style="font-family: Verdana, sans-serif; font-weight: normal; font-size: 16px; line-height: 28px; color: #404040;padding-bottom: 5px;"><img src="' . $this->media['check'] . '" style="height: 14px; width: 14px; position: relative; top: 1px;" /> New files identified</td></tr>';
@@ -88,11 +126,11 @@ if ( ! class_exists( 'WSAL_WFCMExtension' ) ) {
88
  $body .= '</table></td></tr><!-- Table Border Start --><!-- Desc End --></table></td></tr><!-- Website File Changes End -->';
89
  }
90
 
91
- // No changes to report
92
  if ( empty( $files_added ) && empty( $files_modified ) && empty( $files_deleted ) && class_exists( 'Website_File_Changes_Monitor' ) ) {
93
  $body .= '<!-- Website File Changes Start --><tr><td><table width="100%" cellpadding="0" cellspacing="0" border="0"><!-- Title Start --><tr><td style="font-family: Verdana, sans-serif; font-weight: bold; font-size: 20px; line-height: 28px; color: #404040; text-align: left; padding-bottom: 13px;">Website File Changes</td></tr><!-- Title End --><!-- Desc Start --><!-- Table Border Start --><tr><td style="padding-bottom: 40px;"><table width="100%" cellpadding="0" cellspacing="0" border="0">';
94
 
95
- $body .= '<tr><td style="font-family: Verdana, sans-serif; font-weight: normal; font-size: 16px; line-height: 28px; color: #404040;padding-bottom: 5px;">Everything is looking good. No file changes detected during the last scan that ran on '. date( 'd/m/Y', get_option( 'wfcm_last-scan-timestamp' ) ) .' at '. date( 'H:i:s', get_option( 'wfcm_last-scan-timestamp' ) ) .'.</td></tr>';
96
 
97
  $body .= '</table></td></tr><!-- Table Border Start --><!-- Desc End --></table></td></tr><!-- Website File Changes End -->';
98
  }
@@ -110,6 +148,9 @@ if ( ! class_exists( 'WSAL_WFCMExtension' ) ) {
110
  return $body;
111
  }
112
 
 
 
 
113
  public function get_plugin_filename() {
114
  return 'website-file-changes-monitor/website-file-changes-monitor.php';
115
  }
1
  <?php
2
+ /**
3
+ * WFCM extension class.
4
+ *
5
+ * @package wsal
6
+ * @subpackage add-ons
7
+ */
8
 
9
  if ( ! class_exists( 'WSAL_WFCMExtension' ) ) {
10
 
11
+ /**
12
+ * Class provides basic information about WSAL extension for WFCM.
13
+ *
14
+ * @package wsal
15
+ * @subpackage add-ons
16
+ */
17
  class WSAL_WFCMExtension extends WSAL_AbstractExtension {
18
 
19
+ /**
20
+ * {@inheritDoc}
21
+ */
22
  public function __construct() {
23
+ add_filter( 'append_dailynotification_email_content', array( $this, 'append_dailynotification_email_content' ), 10, 2 );
24
  }
25
 
26
+ /**
27
+ * {@inheritDoc}
28
+ */
29
  public function filter_installable_plugins( $plugins ) {
30
  $new_plugin = array(
31
  array(
37
  'plugin_url' => 'https://downloads.wordpress.org/plugin/website-file-changes-monitor.latest-stable.zip',
38
  'event_tab_id' => '#cat-wfcm',
39
  'plugin_description' => 'To keep a log of file changes please install Website File Changes Monitor, a plugin which is also developed by us.',
40
+ ),
41
  );
42
 
43
  // combine the two arrays.
44
  return array_merge( $plugins, $new_plugin );
45
  }
46
 
47
+ /**
48
+ * {@inheritDoc}
49
+ */
50
  public function add_event_codes( $addon_event_codes ) {
51
  $new_event_codes = array(
52
  'wfcm' => array(
59
  return array_merge( $addon_event_codes, $new_event_codes );
60
  }
61
 
62
+ /**
63
+ * {@inheritDoc}
64
+ */
65
  public function get_plugin_name() {
66
  return 'Website File Changes Monitor';
67
  }
68
 
69
+ /**
70
+ * {@inheritDoc}
71
+ */
72
  public function get_plugin_icon_url() {
73
  return 'https://ps.w.org/website-file-changes-monitor/assets/icon-128x128.png?rev=2393849';
74
  }
75
 
76
+ /**
77
+ * {@inheritDoc}
78
+ */
79
  public function get_color() {
80
  return '#a4286a';
81
  }
82
 
83
+ /**
84
+ * Appends content to the daily notification email content.
85
+ *
86
+ * @param string $body Email body (text).
87
+ * @param array $events Events.
88
+ *
89
+ * @return string
90
+ */
91
  public function append_dailynotification_email_content( $body, $events ) {
92
 
93
  if ( ! empty( $events ) ) {
107
  if ( ! empty( $files_added ) || ! empty( $files_modified ) || ! empty( $files_deleted ) ) {
108
  $body .= '<!-- Website File Changes Start --><tr><td><table width="100%" cellpadding="0" cellspacing="0" border="0"><!-- Title Start --><tr><td style="font-family: Verdana, sans-serif; font-weight: bold; font-size: 20px; line-height: 28px; color: #404040; text-align: left; padding-bottom: 13px;">Website File Changes</td></tr><!-- Title End --><!-- Desc Start --><!-- Table Border Start --><tr><td style="padding-bottom: 40px;"><table width="100%" cellpadding="0" cellspacing="0" border="0">';
109
 
110
+ $body .= '<tr><td style="font-family: Verdana, sans-serif; font-weight: normal; font-size: 16px; line-height: 28px; color: #404040;padding-bottom: 20px;">During the last file integrity scan on ' . date( 'd/m/Y', get_option( 'wfcm_last-scan-timestamp' ) ) . ' at ' . date( 'H:i:s', get_option( 'wfcm_last-scan-timestamp' ) ) . ' we detected the following file changes:</td></tr>'; // phpcs:disable
111
 
112
  if ( ! empty( $files_added ) ) {
113
  $body .= '<tr><td style="font-family: Verdana, sans-serif; font-weight: normal; font-size: 16px; line-height: 28px; color: #404040;padding-bottom: 5px;"><img src="' . $this->media['check'] . '" style="height: 14px; width: 14px; position: relative; top: 1px;" /> New files identified</td></tr>';
126
  $body .= '</table></td></tr><!-- Table Border Start --><!-- Desc End --></table></td></tr><!-- Website File Changes End -->';
127
  }
128
 
129
+ // No changes to report.
130
  if ( empty( $files_added ) && empty( $files_modified ) && empty( $files_deleted ) && class_exists( 'Website_File_Changes_Monitor' ) ) {
131
  $body .= '<!-- Website File Changes Start --><tr><td><table width="100%" cellpadding="0" cellspacing="0" border="0"><!-- Title Start --><tr><td style="font-family: Verdana, sans-serif; font-weight: bold; font-size: 20px; line-height: 28px; color: #404040; text-align: left; padding-bottom: 13px;">Website File Changes</td></tr><!-- Title End --><!-- Desc Start --><!-- Table Border Start --><tr><td style="padding-bottom: 40px;"><table width="100%" cellpadding="0" cellspacing="0" border="0">';
132
 
133
+ $body .= '<tr><td style="font-family: Verdana, sans-serif; font-weight: normal; font-size: 16px; line-height: 28px; color: #404040;padding-bottom: 5px;">Everything is looking good. No file changes detected during the last scan that ran on ' . date( 'd/m/Y', get_option( 'wfcm_last-scan-timestamp' ) ) . ' at ' . date( 'H:i:s', get_option( 'wfcm_last-scan-timestamp' ) ) . '.</td></tr>';
134
 
135
  $body .= '</table></td></tr><!-- Table Border Start --><!-- Desc End --></table></td></tr><!-- Website File Changes End -->';
136
  }
148
  return $body;
149
  }
150
 
151
+ /**
152
+ * {@inheritDoc}
153
+ */
154
  public function get_plugin_filename() {
155
  return 'website-file-changes-monitor/website-file-changes-monitor.php';
156
  }
classes/ThirdPartyExtensions/WPFormsExtension.php CHANGED
@@ -1,9 +1,24 @@
1
  <?php
 
 
 
 
 
 
2
 
3
  if ( ! class_exists( 'WSAL_WPFormsExtension' ) ) {
4
 
 
 
 
 
 
 
5
  class WSAL_WPFormsExtension extends WSAL_AbstractExtension {
6
 
 
 
 
7
  public function filter_installable_plugins( $plugins ) {
8
  $new_plugin = array(
9
  array(
@@ -15,13 +30,16 @@ if ( ! class_exists( 'WSAL_WPFormsExtension' ) ) {
15
  'plugin_url' => 'https://downloads.wordpress.org/plugin/wp-security-audit-log-add-on-for-wpforms.latest-stable.zip',
16
  'event_tab_id' => '#cat-wpforms',
17
  'plugin_description' => 'Keep a record of when someone adds, modifies or deletes forms, entries and more in the WPForms plugin.',
18
- )
19
  );
20
 
21
  // combine the two arrays.
22
  return array_merge( $plugins, $new_plugin );
23
  }
24
 
 
 
 
25
  public function add_event_codes( $addon_event_codes ) {
26
  $new_event_codes = array(
27
  'wpforms' => array(
@@ -34,22 +52,37 @@ if ( ! class_exists( 'WSAL_WPFormsExtension' ) ) {
34
  return array_merge( $addon_event_codes, $new_event_codes );
35
  }
36
 
 
 
 
37
  public function get_custom_post_types() {
38
- return [ 'wpforms' ];
39
  }
40
 
 
 
 
41
  public function get_plugin_name() {
42
  return 'WPForms';
43
  }
44
 
 
 
 
45
  public function get_plugin_icon_url() {
46
  return 'https://ps.w.org/wp-security-audit-log-add-on-for-wpforms/assets/icon-128x128.png?rev=2241926';
47
  }
48
 
 
 
 
49
  public function get_color() {
50
  return '#e27730';
51
  }
52
 
 
 
 
53
  public function get_plugin_filename() {
54
  return 'wp-security-audit-log-add-on-for-wpforms/wsal-wpforms.php';
55
  }
1
  <?php
2
+ /**
3
+ * WP Forms extension class.
4
+ *
5
+ * @package wsal
6
+ * @subpackage add-ons
7
+ */
8
 
9
  if ( ! class_exists( 'WSAL_WPFormsExtension' ) ) {
10
 
11
+ /**
12
+ * Class provides basic information about WSAL extension for WP Forms.
13
+ *
14
+ * @package wsal
15
+ * @subpackage add-ons
16
+ */
17
  class WSAL_WPFormsExtension extends WSAL_AbstractExtension {
18
 
19
+ /**
20
+ * {@inheritDoc}
21
+ */
22
  public function filter_installable_plugins( $plugins ) {
23
  $new_plugin = array(
24
  array(
30
  'plugin_url' => 'https://downloads.wordpress.org/plugin/wp-security-audit-log-add-on-for-wpforms.latest-stable.zip',
31
  'event_tab_id' => '#cat-wpforms',
32
  'plugin_description' => 'Keep a record of when someone adds, modifies or deletes forms, entries and more in the WPForms plugin.',
33
+ ),
34
  );
35
 
36
  // combine the two arrays.
37
  return array_merge( $plugins, $new_plugin );
38
  }
39
 
40
+ /**
41
+ * {@inheritDoc}
42
+ */
43
  public function add_event_codes( $addon_event_codes ) {
44
  $new_event_codes = array(
45
  'wpforms' => array(
52
  return array_merge( $addon_event_codes, $new_event_codes );
53
  }
54
 
55
+ /**
56
+ * {@inheritDoc}
57
+ */
58
  public function get_custom_post_types() {
59
+ return array( 'wpforms' );
60
  }
61
 
62
+ /**
63
+ * {@inheritDoc}
64
+ */
65
  public function get_plugin_name() {
66
  return 'WPForms';
67
  }
68
 
69
+ /**
70
+ * {@inheritDoc}
71
+ */
72
  public function get_plugin_icon_url() {
73
  return 'https://ps.w.org/wp-security-audit-log-add-on-for-wpforms/assets/icon-128x128.png?rev=2241926';
74
  }
75
 
76
+ /**
77
+ * {@inheritDoc}
78
+ */
79
  public function get_color() {
80
  return '#e27730';
81
  }
82
 
83
+ /**
84
+ * {@inheritDoc}
85
+ */
86
  public function get_plugin_filename() {
87
  return 'wp-security-audit-log-add-on-for-wpforms/wsal-wpforms.php';
88
  }
classes/ThirdPartyExtensions/WooCommerceExtension.php CHANGED
@@ -1,14 +1,32 @@
1
  <?php
 
 
 
 
 
 
2
 
3
  if ( ! class_exists( 'WSAL_WooCommerceExtension' ) ) {
4
 
 
 
 
 
 
 
5
  class WSAL_WooCommerceExtension extends WSAL_AbstractExtension {
6
 
7
- public function __construct( ) {
 
 
 
8
  parent::__construct();
9
  add_filter( 'wsal_save_settings_disabled_events', array( $this, 'save_settings_disabled_events' ), 10, 4 );
10
  }
11
 
 
 
 
12
  public function filter_installable_plugins( $plugins ) {
13
  $new_plugin = array(
14
  array(
@@ -27,6 +45,9 @@ if ( ! class_exists( 'WSAL_WooCommerceExtension' ) ) {
27
  return array_merge( $plugins, $new_plugin );
28
  }
29
 
 
 
 
30
  public function add_event_codes( $addon_event_codes ) {
31
  $new_event_codes = array(
32
  'woocommerce' => array(
@@ -66,29 +87,44 @@ if ( ! class_exists( 'WSAL_WooCommerceExtension' ) ) {
66
  return $disabled;
67
  }
68
 
 
 
 
69
  public function get_custom_post_types() {
70
- return [
71
  'product',
72
  'shop_coupon',
73
  'shop_order',
74
  'shop_order_refund',
75
  'product_variation',
76
- 'wc_product_tab'
77
- ];
78
  }
79
 
 
 
 
80
  public function get_plugin_name() {
81
  return 'WooCommerce';
82
  }
83
 
 
 
 
84
  public function get_plugin_icon_url() {
85
  return 'https://ps.w.org/wp-activity-log-for-woocommerce/assets/icon-128x128.png?rev=2357550';
86
  }
87
 
 
 
 
88
  public function get_color() {
89
  return '#7f54b3';
90
  }
91
 
 
 
 
92
  public function get_plugin_filename() {
93
  return 'wp-activity-log-for-woocommerce/wsal-woocommerce.php';
94
  }
1
  <?php
2
+ /**
3
+ * Woocommerce extension class.
4
+ *
5
+ * @package wsal
6
+ * @subpackage add-ons
7
+ */
8
 
9
  if ( ! class_exists( 'WSAL_WooCommerceExtension' ) ) {
10
 
11
+ /**
12
+ * Class provides basic information about WSAL extension for WooCommerce.
13
+ *
14
+ * @package wsal
15
+ * @subpackage add-ons
16
+ */
17
  class WSAL_WooCommerceExtension extends WSAL_AbstractExtension {
18
 
19
+ /**
20
+ * {@inheritDoc}
21
+ */
22
+ public function __construct() {
23
  parent::__construct();
24
  add_filter( 'wsal_save_settings_disabled_events', array( $this, 'save_settings_disabled_events' ), 10, 4 );
25
  }
26
 
27
+ /**
28
+ * {@inheritDoc}
29
+ */
30
  public function filter_installable_plugins( $plugins ) {
31
  $new_plugin = array(
32
  array(
45
  return array_merge( $plugins, $new_plugin );
46
  }
47
 
48
+ /**
49
+ * {@inheritDoc}
50
+ */
51
  public function add_event_codes( $addon_event_codes ) {
52
  $new_event_codes = array(
53
  'woocommerce' => array(
87
  return $disabled;
88
  }
89
 
90
+ /**
91
+ * {@inheritDoc}
92
+ */
93
  public function get_custom_post_types() {
94
+ return array(
95
  'product',
96
  'shop_coupon',
97
  'shop_order',
98
  'shop_order_refund',
99
  'product_variation',
100
+ 'wc_product_tab',
101
+ );
102
  }
103
 
104
+ /**
105
+ * {@inheritDoc}
106
+ */
107
  public function get_plugin_name() {
108
  return 'WooCommerce';
109
  }
110
 
111
+ /**
112
+ * {@inheritDoc}
113
+ */
114
  public function get_plugin_icon_url() {
115
  return 'https://ps.w.org/wp-activity-log-for-woocommerce/assets/icon-128x128.png?rev=2357550';
116
  }
117
 
118
+ /**
119
+ * {@inheritDoc}
120
+ */
121
  public function get_color() {
122
  return '#7f54b3';
123
  }
124
 
125
+ /**
126
+ * {@inheritDoc}
127
+ */
128
  public function get_plugin_filename() {
129
  return 'wp-activity-log-for-woocommerce/wsal-woocommerce.php';
130
  }
classes/ThirdPartyExtensions/YoastSeoExtension.php CHANGED
@@ -1,9 +1,24 @@
1
  <?php
 
 
 
 
 
 
2
 
3
  if ( ! class_exists( 'WSAL_YoastSeoExtension' ) ) {
4
 
 
 
 
 
 
 
5
  class WSAL_YoastSeoExtension extends WSAL_AbstractExtension {
6
 
 
 
 
7
  public function filter_installable_plugins( $plugins ) {
8
  $new_plugin = array(
9
  array(
@@ -15,13 +30,16 @@ if ( ! class_exists( 'WSAL_YoastSeoExtension' ) ) {
15
  'plugin_url' => 'https://downloads.wordpress.org/plugin/activity-log-wp-seo.latest-stable.zip',
16
  'event_tab_id' => '#cat-yoast-seo',
17
  'plugin_description' => 'Keep a log of all the changes that you and your team do in the Yoast SEO metabox, plugin settings & much more.',
18
- )
19
  );
20
 
21
  // combine the two arrays.
22
  return array_merge( $plugins, $new_plugin );
23
  }
24
 
 
 
 
25
  public function add_event_codes( $addon_event_codes ) {
26
  $new_event_codes = array(
27
  'yoast' => array(
@@ -34,6 +52,9 @@ if ( ! class_exists( 'WSAL_YoastSeoExtension' ) ) {
34
  return array_merge( $addon_event_codes, $new_event_codes );
35
  }
36
 
 
 
 
37
  public function modify_predefined_plugin_slug( $plugin ) {
38
  // Correct yoast addon.
39
  if ( 'yoast' === $plugin ) {
@@ -43,18 +64,30 @@ if ( ! class_exists( 'WSAL_YoastSeoExtension' ) ) {
43
  return $plugin;
44
  }
45
 
 
 
 
46
  public function get_plugin_name() {
47
  return 'Yoast SEO';
48
  }
49
 
 
 
 
50
  public function get_plugin_icon_url() {
51
  return 'https://ps.w.org/activity-log-wp-seo/assets/icon-128x128.png?rev=2393849';
52
  }
53
 
 
 
 
54
  public function get_color() {
55
  return '#a4286a';
56
  }
57
 
 
 
 
58
  public function get_plugin_filename() {
59
  return 'activity-log-wp-seo/activity-log-wp-seo.php';
60
  }
1
  <?php
2
+ /**
3
+ * Yoast SEO extension class.
4
+ *
5
+ * @package wsal
6
+ * @subpackage add-ons
7
+ */
8
 
9
  if ( ! class_exists( 'WSAL_YoastSeoExtension' ) ) {
10
 
11
+ /**
12
+ * Class provides basic information about WSAL extension for Yoast SEO.
13
+ *
14
+ * @package wsal
15
+ * @subpackage add-ons
16
+ */
17
  class WSAL_YoastSeoExtension extends WSAL_AbstractExtension {
18
 
19
+ /**
20
+ * {@inheritDoc}
21
+ */
22
  public function filter_installable_plugins( $plugins ) {
23
  $new_plugin = array(
24
  array(
30
  'plugin_url' => 'https://downloads.wordpress.org/plugin/activity-log-wp-seo.latest-stable.zip',
31
  'event_tab_id' => '#cat-yoast-seo',
32
  'plugin_description' => 'Keep a log of all the changes that you and your team do in the Yoast SEO metabox, plugin settings & much more.',
33
+ ),
34
  );
35
 
36
  // combine the two arrays.
37
  return array_merge( $plugins, $new_plugin );
38
  }
39
 
40
+ /**
41
+ * {@inheritDoc}
42
+ */
43
  public function add_event_codes( $addon_event_codes ) {
44
  $new_event_codes = array(
45
  'yoast' => array(
52
  return array_merge( $addon_event_codes, $new_event_codes );
53
  }
54
 
55
+ /**
56
+ * {@inheritDoc}
57
+ */
58
  public function modify_predefined_plugin_slug( $plugin ) {
59
  // Correct yoast addon.
60
  if ( 'yoast' === $plugin ) {
64
  return $plugin;
65
  }
66
 
67
+ /**
68
+ * {@inheritDoc}
69
+ */
70
  public function get_plugin_name() {
71
  return 'Yoast SEO';
72
  }
73
 
74
+ /**
75
+ * {@inheritDoc}
76
+ */
77
  public function get_plugin_icon_url() {
78
  return 'https://ps.w.org/activity-log-wp-seo/assets/icon-128x128.png?rev=2393849';
79
  }
80
 
81
+ /**
82
+ * {@inheritDoc}
83
+ */
84
  public function get_color() {
85
  return '#a4286a';
86
  }
87
 
88
+ /**
89
+ * {@inheritDoc}
90
+ */
91
  public function get_plugin_filename() {
92
  return 'activity-log-wp-seo/activity-log-wp-seo.php';
93
  }
classes/Uninstall.php CHANGED
@@ -47,8 +47,13 @@ class WSAL_Uninstall {
47
  return self::should_data_be_deleted();
48
  }
49
 
 
 
 
 
 
50
  private static function should_data_be_deleted() {
51
- return in_array( get_option( 'wsal_delete-data' ), [ 'yes', 1, '1', 'y', 'true', true ] );
52
  }
53
 
54
  /**
@@ -70,7 +75,7 @@ class WSAL_Uninstall {
70
  private static function drop_table( $name ) {
71
  global $wpdb;
72
  $table_name = self::get_table( $name );
73
- $wpdb->query( 'DROP TABLE IF EXISTS ' . $table_name );
74
  }
75
 
76
  /**
@@ -78,18 +83,18 @@ class WSAL_Uninstall {
78
  */
79
  public static function delete_options_from_wp_options() {
80
  global $wpdb;
81
- $plugin_options = $wpdb->get_results( "SELECT option_name FROM $wpdb->options WHERE option_name LIKE 'wsal_%'" );
82
 
83
  foreach ( $plugin_options as $option ) {
84
  delete_option( $option->option_name );
85
  }
86
 
87
- // Remove wsal specific freemius entry.
88
  delete_option( 'fs_wsalp' );
89
-
90
  // Ensue entry is fully cleared.
91
- delete_network_option( 0 ,'wsal_networkwide_tracker_cpts' );
92
 
93
- // @todo delete also options from site-level tables in multisite context
94
  }
95
  }
47
  return self::should_data_be_deleted();
48
  }
49
 
50
+ /**
51
+ * Checks if data should be deleted.
52
+ *
53
+ * @return bool True if data should be deleted.
54
+ */
55
  private static function should_data_be_deleted() {
56
+ return in_array( get_option( 'wsal_delete-data' ), array( 'yes', 1, '1', 'y', 'true', true ), true );
57
  }
58
 
59
  /**
75
  private static function drop_table( $name ) {
76
  global $wpdb;
77
  $table_name = self::get_table( $name );
78
+ $wpdb->query( 'DROP TABLE IF EXISTS ' . $table_name ); // phpcs:ignore
79
  }
80
 
81
  /**
83
  */
84
  public static function delete_options_from_wp_options() {
85
  global $wpdb;
86
+ $plugin_options = $wpdb->get_results( "SELECT option_name FROM $wpdb->options WHERE option_name LIKE 'wsal_%'" ); // phpcs:ignore
87
 
88
  foreach ( $plugin_options as $option ) {
89
  delete_option( $option->option_name );
90
  }
91
 
92
+ // Remove wsal specific Freemius entry.
93
  delete_option( 'fs_wsalp' );
94
+
95
  // Ensue entry is fully cleared.
96
+ delete_network_option( 0, 'wsal_networkwide_tracker_cpts' );
97
 
98
+ // @todo delete also options from site-level tables in multisite context
99
  }
100
  }
classes/Upgrade/MetadataMigration.php CHANGED
@@ -1,4 +1,11 @@
1
  <?php
 
 
 
 
 
 
 
2
 
3
  // Exit if accessed directly.
4
  if ( ! defined( 'ABSPATH' ) ) {
@@ -12,9 +19,9 @@ if ( ! defined( 'ABSPATH' ) ) {
12
  * It handles metadata migration for 1 connection defined as part of the process information. This can be either "local"
13
  * to work with the local WP database or a name of connection defined by the Integrations extension.
14
  *
15
- * @package wsal
16
  * @subpackage upgrade
17
- * @since 4.4.0
18
  */
19
  class WSAL_Upgrade_MetadataMigration extends WSAL_Vendor\WP_Background_Process {
20
 
@@ -28,7 +35,9 @@ class WSAL_Upgrade_MetadataMigration extends WSAL_Vendor\WP_Background_Process {
28
  const OPTION_NAME_MIGRATION_INFO = 'meta_data_migration_info_440';
29
 
30
  /**
31
- * @inheritDoc
 
 
32
  */
33
  protected $action = 'wsal_meta_data_migration_440';
34
 
@@ -53,8 +62,8 @@ class WSAL_Upgrade_MetadataMigration extends WSAL_Vendor\WP_Background_Process {
53
  return;
54
  }
55
 
56
- $plugin = WpSecurityAuditLog::GetInstance();
57
- $existing_info = $plugin->GetGlobalSetting( self::OPTION_NAME_MIGRATION_INFO, array() );
58
  if ( empty( $existing_info ) ) {
59
  return;
60
  }
@@ -72,17 +81,17 @@ class WSAL_Upgrade_MetadataMigration extends WSAL_Vendor\WP_Background_Process {
72
  }
73
 
74
  /**
75
- * @inheritDoc
76
  *
77
- * @param array{start_time: int, processed_events_count: int, batch_size: int, connection: string} $item
78
  */
79
  protected function task( $item ) {
80
- // migrate metadata for the next batch of events
81
  $items_migrated = $this->process_next_batch( $item['connection'], $item['batch_size'] );
82
  if ( 0 === $items_migrated ) {
83
- // all metadata has been migrated
84
  try {
85
- // delete the migration job info to indicate that the migration is done
86
  self::remove_migration_info( $item['connection'] );
87
 
88
  } catch ( Exception $exception ) {
@@ -92,7 +101,7 @@ class WSAL_Upgrade_MetadataMigration extends WSAL_Vendor\WP_Background_Process {
92
  return false;
93
  }
94
 
95
- // update and save the migration info
96
  $item['processed_events_count'] += $items_migrated;
97
  self::store_migration_info( $item );
98
 
@@ -100,13 +109,15 @@ class WSAL_Upgrade_MetadataMigration extends WSAL_Vendor\WP_Background_Process {
100
  }
101
 
102
  /**
103
- * @param string $connection
104
- * @param int $batch_size
 
 
105
  *
106
  * @return int
107
  */
108
  private function process_next_batch( $connection, $batch_size ) {
109
- $plugin = WpSecurityAuditLog::GetInstance();
110
  if ( 'local' !== $connection && ! is_null( $plugin->external_db_util ) ) {
111
  $connection = $plugin->external_db_util->get_connection( $connection );
112
  if ( false === $connection ) {
@@ -114,37 +125,37 @@ class WSAL_Upgrade_MetadataMigration extends WSAL_Vendor\WP_Background_Process {
114
  }
115
  }
116
 
117
- $connector = $plugin->getConnector( $connection );
118
  /** @var WSAL_Adapters_MySQL_Occurrence $occurrence_adapter */
119
- $occurrence_adapter = $connector->getAdapter( 'Occurrence' );
120
 
121
  $occurrences_to_migrate = $occurrence_adapter->get_all_with_meta_to_migrate( $batch_size );
122
  if ( ! empty( $occurrences_to_migrate ) ) {
123
- $migrated_meta_keys = array_keys( WSAL_Models_Occurrence::$migrated_meta );
124
  $lowercase_migrated_meta_keys = array_map( 'strtolower', $migrated_meta_keys );
125
  foreach ( $occurrences_to_migrate as $occurrence ) {
126
- $all_metadata = $occurrence_adapter->GetMultiMeta( $occurrence );
127
  if ( ! empty( $all_metadata ) ) {
128
  foreach ( $all_metadata as $meta_model ) {
129
- $meta_key = $meta_model->name;
130
- $lowercase_meta_key = strtolower($meta_key);
131
 
132
  // We use lowercase meta keys to make sure we handle even legacy meta keys correctly, for
133
  // example "username" was changed to "Username" at some point.
134
- if ( in_array( $lowercase_meta_key , $lowercase_migrated_meta_keys ) ) {
135
- // this will store the meta in the occ table if it belongs there
136
  $is_empty_string = is_string( $meta_model->value ) && 0 === strlen( $meta_model->value );
137
- if ( ! $is_empty_string && in_array( $meta_key, $migrated_meta_keys )) {
138
  // The meta is set in the occurrence object on if it is an exact match, otherwise we
139
  // would end up writing and deleting the same meta key endlessly.
140
- $occurrence->SetMetaValue( $meta_key, $meta_model->value );
141
  }
142
 
143
- $meta_model->Delete();
144
  }
145
  }
146
 
147
- $occurrence->Save();
148
  }
149
  }
150
  }
@@ -158,38 +169,40 @@ class WSAL_Upgrade_MetadataMigration extends WSAL_Vendor\WP_Background_Process {
158
  * @param string $connection_name Connection name.
159
  */
160
  public static function remove_migration_info( $connection_name ) {
161
- $plugin = WpSecurityAuditLog::GetInstance();
162
- $existing_info = $plugin->GetGlobalSetting( self::OPTION_NAME_MIGRATION_INFO, [] );
163
 
164
  if ( array_key_exists( $connection_name, $existing_info ) ) {
165
  unset( $existing_info[ $connection_name ] );
166
  }
167
 
168
  if ( empty( $existing_info ) ) {
169
- $plugin->DeleteGlobalSetting( self::OPTION_NAME_MIGRATION_INFO );
170
  } else {
171
- $plugin->SetGlobalSetting( self::OPTION_NAME_MIGRATION_INFO, $existing_info );
172
  }
173
  }
174
 
175
  /**
176
- * @param Exception $exception
 
 
177
  */
178
  private function handle_error( $exception ) {
179
- // @todo handle migration error
180
  }
181
 
182
  /**
183
  * Stores or updates migration info for one particular connection.
184
  *
185
- * @param array{start_time: int, processed_events_count: int, batch_size: int, connection: string} $info
186
  */
187
  public static function store_migration_info( $info ) {
188
- $plugin = WpSecurityAuditLog::GetInstance();
189
- $existing_info = $plugin->GetGlobalSetting( self::OPTION_NAME_MIGRATION_INFO, [] );
190
  $connection_name = $info['connection'];
191
 
192
  $existing_info[ $connection_name ] = $info;
193
- $plugin->SetGlobalSetting( self::OPTION_NAME_MIGRATION_INFO, $existing_info );
194
  }
195
- }
1
  <?php
2
+ /**
3
+ * Metadata migration class.
4
+ *
5
+ * @package wsal
6
+ * @subpackage upgrade
7
+ * @since 4.4.0
8
+ */
9
 
10
  // Exit if accessed directly.
11
  if ( ! defined( 'ABSPATH' ) ) {
19
  * It handles metadata migration for 1 connection defined as part of the process information. This can be either "local"
20
  * to work with the local WP database or a name of connection defined by the Integrations extension.
21
  *
22
+ * @package wsal
23
  * @subpackage upgrade
24
+ * @since 4.4.0
25
  */
26
  class WSAL_Upgrade_MetadataMigration extends WSAL_Vendor\WP_Background_Process {
27
 
35
  const OPTION_NAME_MIGRATION_INFO = 'meta_data_migration_info_440';
36
 
37
  /**
38
+ * Action
39
+ *
40
+ * @var string
41
  */
42
  protected $action = 'wsal_meta_data_migration_440';
43
 
62
  return;
63
  }
64
 
65
+ $plugin = WpSecurityAuditLog::get_instance();
66
+ $existing_info = $plugin->get_global_setting( self::OPTION_NAME_MIGRATION_INFO, array() );
67
  if ( empty( $existing_info ) ) {
68
  return;
69
  }
81
  }
82
 
83
  /**
84
+ * {@inheritDoc}
85
  *
86
+ * @param array{start_time: int, processed_events_count: int, batch_size: int, connection: string} $item Migration process item.
87
  */
88
  protected function task( $item ) {
89
+ // Migrate metadata for the next batch of events.
90
  $items_migrated = $this->process_next_batch( $item['connection'], $item['batch_size'] );
91
  if ( 0 === $items_migrated ) {
92
+ // All metadata has been migrated.
93
  try {
94
+ // Delete the migration job info to indicate that the migration is done.
95
  self::remove_migration_info( $item['connection'] );
96
 
97
  } catch ( Exception $exception ) {
101
  return false;
102
  }
103
 
104
+ // Update and save the migration info.
105
  $item['processed_events_count'] += $items_migrated;
106
  self::store_migration_info( $item );
107
 
109
  }
110
 
111
  /**
112
+ * Processes next batch of events that need to be migrated.
113
+ *
114
+ * @param string $connection Connection name.
115
+ * @param int $batch_size Batch size.
116
  *
117
  * @return int
118
  */
119
  private function process_next_batch( $connection, $batch_size ) {
120
+ $plugin = WpSecurityAuditLog::get_instance();
121
  if ( 'local' !== $connection && ! is_null( $plugin->external_db_util ) ) {
122
  $connection = $plugin->external_db_util->get_connection( $connection );
123
  if ( false === $connection ) {
125
  }
126
  }
127
 
128
+ $connector = $plugin->get_connector( $connection );
129
  /** @var WSAL_Adapters_MySQL_Occurrence $occurrence_adapter */
130
+ $occurrence_adapter = $connector->get_adapter( 'Occurrence' );
131
 
132
  $occurrences_to_migrate = $occurrence_adapter->get_all_with_meta_to_migrate( $batch_size );
133
  if ( ! empty( $occurrences_to_migrate ) ) {
134
+ $migrated_meta_keys = array_keys( WSAL_Models_Occurrence::$migrated_meta );
135
  $lowercase_migrated_meta_keys = array_map( 'strtolower', $migrated_meta_keys );
136
  foreach ( $occurrences_to_migrate as $occurrence ) {
137
+ $all_metadata = $occurrence_adapter->get_multi_meta( $occurrence );
138
  if ( ! empty( $all_metadata ) ) {
139
  foreach ( $all_metadata as $meta_model ) {
140
+ $meta_key = $meta_model->name;
141
+ $lowercase_meta_key = strtolower( $meta_key );
142
 
143
  // We use lowercase meta keys to make sure we handle even legacy meta keys correctly, for
144
  // example "username" was changed to "Username" at some point.
145
+ if ( in_array( $lowercase_meta_key, $lowercase_migrated_meta_keys ) ) { // phpcs:ignore
146
+ // This will store the meta in the occ table if it belongs there.
147
  $is_empty_string = is_string( $meta_model->value ) && 0 === strlen( $meta_model->value );
148
+ if ( ! $is_empty_string && in_array( $meta_key, $migrated_meta_keys, true ) ) {
149
  // The meta is set in the occurrence object on if it is an exact match, otherwise we
150
  // would end up writing and deleting the same meta key endlessly.
151
+ $occurrence->set_meta_value( $meta_key, $meta_model->value );
152
  }
153
 
154
+ $meta_model->delete();
155
  }
156
  }
157
 
158
+ $occurrence->save();
159
  }
160
  }
161
  }
169
  * @param string $connection_name Connection name.
170
  */
171
  public static function remove_migration_info( $connection_name ) {
172
+ $plugin = WpSecurityAuditLog::get_instance();
173
+ $existing_info = $plugin->get_global_setting( self::OPTION_NAME_MIGRATION_INFO, array() );
174
 
175
  if ( array_key_exists( $connection_name, $existing_info ) ) {
176
  unset( $existing_info[ $connection_name ] );
177
  }
178
 
179
  if ( empty( $existing_info ) ) {
180
+ $plugin->delete_global_setting( self::OPTION_NAME_MIGRATION_INFO );
181
  } else {
182
+ $plugin->set_global_setting( self::OPTION_NAME_MIGRATION_INFO, $existing_info );
183
  }
184
  }
185
 
186
  /**
187
+ * Handles an error.
188
+ *
189
+ * @param Exception $exception Error to handle.
190
  */
191
  private function handle_error( $exception ) {
192
+ // @todo handle migration error
193
  }
194
 
195
  /**
196
  * Stores or updates migration info for one particular connection.
197
  *
198
+ * @param array{start_time: int, processed_events_count: int, batch_size: int, connection: string} $info Migration info data.
199
  */
200
  public static function store_migration_info( $info ) {
201
+ $plugin = WpSecurityAuditLog::get_instance();
202
+ $existing_info = $plugin->get_global_setting( self::OPTION_NAME_MIGRATION_INFO, array() );
203
  $connection_name = $info['connection'];
204
 
205
  $existing_info[ $connection_name ] = $info;
206
+ $plugin->set_global_setting( self::OPTION_NAME_MIGRATION_INFO, $existing_info );
207
  }
208
+ }
classes/Upgrade/Upgrade_43000_to_44400.php CHANGED
@@ -1,4 +1,17 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  /**
4
  * Class handles upgrade changes from version 43000 to 44400.
@@ -8,7 +21,7 @@
8
  *
9
  * @since 4.4.0
10
  */
11
- class WSAL_Upgrade_43000_to_44400 {
12
 
13
  /**
14
  * Plugin instance.
@@ -31,6 +44,24 @@ class WSAL_Upgrade_43000_to_44400 {
31
  */
32
  public function run() {
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  // Remove some forgotten WFCM settings from the options table.
35
  $this->remove_wfcm_leftover_settings();
36
 
@@ -60,7 +91,7 @@ class WSAL_Upgrade_43000_to_44400 {
60
  'wsal_scanned_dirs',
61
  );
62
  foreach ( $not_found_page_related_settings as $setting_name ) {
63
- $this->plugin->DeleteGlobalSetting( $setting_name );
64
  }
65
  }
66
 
@@ -74,20 +105,20 @@ class WSAL_Upgrade_43000_to_44400 {
74
  * @throws Freemius_Exception Freemius exception.
75
  */
76
  private function upgrade_occurrence_table( $connection ) {
77
- $connector = $this->plugin->getConnector( $connection );
78
  /** @var WSAL_Adapters_MySQL_Occurrence $occurrence_adapter */
79
- $occurrence_adapter = $connector->getAdapter( 'Occurrence' );
80
 
81
  // Skip the upgrade it the table does not exist for some reason.
82
- if ( ! $connector->isInstalled() ) {
83
  return;
84
  }
85
 
86
- $table_name = $occurrence_adapter->GetTable();
87
  $connector->query( $this->get_occurrence_table_upgrade_query( $table_name ) );
88
 
89
  // Check if there are any events to process.
90
- if ( $occurrence_adapter->Count() > 0 ) {
91
  // Create a background job to migrate the metadata.
92
  $job_info = array(
93
  'start_time' => current_time( 'timestamp' ), // phpcs:ignore
@@ -116,20 +147,20 @@ class WSAL_Upgrade_43000_to_44400 {
116
  */
117
  private function get_occurrence_table_upgrade_query( $table_name ) {
118
  return "ALTER TABLE {$table_name}"
119
- . ' DROP COLUMN is_read, '
120
- . ' DROP COLUMN is_migrated, '
121
- . " ADD client_ip VARCHAR(255) NOT NULL DEFAULT '',"
122
- . ' ADD severity BIGINT NOT NULL DEFAULT 0,'
123
- . " ADD object VARCHAR(255) NOT NULL DEFAULT '',"
124
- . " ADD event_type VARCHAR(255) NOT NULL DEFAULT '',"
125
- . " ADD user_agent VARCHAR(255) NOT NULL DEFAULT '',"
126
- . " ADD user_roles VARCHAR(255) NOT NULL DEFAULT '',"
127
- . ' ADD username VARCHAR(255) NULL,'
128
- . ' ADD user_id BIGINT NULL ,'
129
- . " ADD session_id VARCHAR(255) NOT NULL DEFAULT '',"
130
- . " ADD post_status VARCHAR(255) NOT NULL DEFAULT '',"
131
- . " ADD post_type VARCHAR(255) NOT NULL DEFAULT '',"
132
- . ' ADD post_id BIGINT NOT NULL DEFAULT 0;';
133
  }
134
 
135
 
@@ -166,7 +197,7 @@ class WSAL_Upgrade_43000_to_44400 {
166
  foreach ( $plugin_options as $option ) {
167
  if ( ! in_array( $option['option_name'], $settings_to_leave_on_autoload ) ) { // phpcs:ignore
168
  $value = maybe_unserialize( $option['option_value'] );
169
- $this->plugin->SetGlobalSetting( $option['option_name'], $value, false );
170
  }
171
  }
172
  }
1
  <?php
2
+ /**
3
+ * Class WSAL_Upgrade_43000_to_44400.
4
+ *
5
+ * @package wsal
6
+ * @subpackage upgrade
7
+ *
8
+ * @since 4.4.0
9
+ */
10
+
11
+ // Exit if accessed directly.
12
+ if ( ! defined( 'ABSPATH' ) ) {
13
+ exit;
14
+ }
15
 
16
  /**
17
  * Class handles upgrade changes from version 43000 to 44400.
21
  *
22
  * @since 4.4.0
23
  */
24
+ class WSAL_Upgrade_43000_To_44400 {
25
 
26
  /**
27
  * Plugin instance.
44
  */
45
  public function run() {
46
 
47
+ // Delete unwanted usermeta.
48
+ global $wpdb;
49
+ $wpdb->query( // phpcs:ignore
50
+ $wpdb->prepare(
51
+ "DELETE FROM {$wpdb->usermeta} WHERE meta_key = '%s';", // phpcs:ignore
52
+ 'wsal-notice-update-44-notice'
53
+ )
54
+ );
55
+
56
+ if ( class_exists( 'WSAL_Extension_Manager' ) ) {
57
+ WSAL_Extension_Manager::include_extension( 'external-db' );
58
+ }
59
+
60
+ if ( ! did_action( 'wsal_init' ) ) {
61
+ // We need to call wsal init manually because it does not run as before the upgrade procedure is triggered.
62
+ do_action( 'wsal_init', $this->plugin );
63
+ }
64
+
65
  // Remove some forgotten WFCM settings from the options table.
66
  $this->remove_wfcm_leftover_settings();
67
 
91
  'wsal_scanned_dirs',
92
  );
93
  foreach ( $not_found_page_related_settings as $setting_name ) {
94
+ $this->plugin->delete_global_setting( $setting_name );
95
  }
96
  }
97
 
105
  * @throws Freemius_Exception Freemius exception.
106
  */
107
  private function upgrade_occurrence_table( $connection ) {
108
+ $connector = $this->plugin->get_connector( $connection );
109
  /** @var WSAL_Adapters_MySQL_Occurrence $occurrence_adapter */
110
+ $occurrence_adapter = $connector->get_adapter( 'Occurrence' );
111
 
112
  // Skip the upgrade it the table does not exist for some reason.
113
+ if ( ! $connector->is_installed() ) {
114
  return;
115
  }
116
 
117
+ $table_name = $occurrence_adapter->get_table();
118
  $connector->query( $this->get_occurrence_table_upgrade_query( $table_name ) );
119
 
120
  // Check if there are any events to process.
121
+ if ( $occurrence_adapter->count() > 0 ) {
122
  // Create a background job to migrate the metadata.
123
  $job_info = array(
124
  'start_time' => current_time( 'timestamp' ), // phpcs:ignore
147
  */
148
  private function get_occurrence_table_upgrade_query( $table_name ) {
149
  return "ALTER TABLE {$table_name}"
150
+ . ' DROP COLUMN is_read, '
151
+ . ' DROP COLUMN is_migrated, '
152
+ . " ADD client_ip VARCHAR(255) NOT NULL DEFAULT '',"
153
+ . ' ADD severity BIGINT NOT NULL DEFAULT 0,'
154
+ . " ADD object VARCHAR(255) NOT NULL DEFAULT '',"
155
+ . " ADD event_type VARCHAR(255) NOT NULL DEFAULT '',"
156
+ . " ADD user_agent VARCHAR(255) NOT NULL DEFAULT '',"
157
+ . " ADD user_roles VARCHAR(255) NOT NULL DEFAULT '',"
158
+ . ' ADD username VARCHAR(255) NULL,'
159
+ . ' ADD user_id BIGINT NULL ,'
160
+ . " ADD session_id VARCHAR(255) NOT NULL DEFAULT '',"
161
+ . " ADD post_status VARCHAR(255) NOT NULL DEFAULT '',"
162
+ . " ADD post_type VARCHAR(255) NOT NULL DEFAULT '',"
163
+ . ' ADD post_id BIGINT NOT NULL DEFAULT 0;';
164
  }
165
 
166
 
197
  foreach ( $plugin_options as $option ) {
198
  if ( ! in_array( $option['option_name'], $settings_to_leave_on_autoload ) ) { // phpcs:ignore
199
  $value = maybe_unserialize( $option['option_value'] );
200
+ $this->plugin->set_global_setting( $option['option_name'], $value, false );
201
  }
202
  }
203
  }
classes/Utilities/DateTimeFormatter.php CHANGED
@@ -23,7 +23,9 @@ if ( ! defined( 'ABSPATH' ) ) {
23
  class WSAL_Utilities_DateTimeFormatter {
24
 
25
  /**
26
- * @var string Regular expression for matching the milliseconds part of datetime string.
 
 
27
  */
28
  private static $am_pm_lookup_pattern = '/\.\d+((\&nbsp;|\ )([AP]M))?/i';
29
 
@@ -34,14 +36,39 @@ class WSAL_Utilities_DateTimeFormatter {
34
  */
35
  private $gmt_offset_sec = 0;
36
 
 
 
 
 
 
37
  private $date_format;
38
 
 
 
 
 
 
39
  private $time_format;
40
 
 
 
 
 
 
41
  private $datetime_format;
42
 
 
 
 
 
 
43
  private $datetime_format_no_linebreaks;
44
 
 
 
 
 
 
45
  private $show_milliseconds;
46
 
47
  /**
@@ -55,12 +82,12 @@ class WSAL_Utilities_DateTimeFormatter {
55
  */
56
  public static function instance() {
57
  static $instance = false;
58
- if ( $instance === false ) {
59
- // Late static binding (PHP 5.3+)
60
  $instance = new static();
61
 
62
- $plugin = WpSecurityAuditLog::GetInstance();
63
- $timezone = $plugin->settings()->GetTimezone();
64
 
65
  /**
66
  * Transform timezone values.
@@ -74,16 +101,16 @@ class WSAL_Utilities_DateTimeFormatter {
74
  }
75
 
76
  if ( 'utc' === $timezone ) {
77
- $instance->gmt_offset_sec = date( 'Z' );
78
  } else {
79
  $instance->gmt_offset_sec = get_option( 'gmt_offset' ) * HOUR_IN_SECONDS;
80
  }
81
 
82
  $instance->show_milliseconds = $plugin->settings()->get_show_milliseconds();
83
- $instance->date_format = $plugin->settings()->GetDateFormat();
84
- $instance->time_format = $plugin->settings()->GetTimeFormat();
85
- $instance->datetime_format = $plugin->settings()->GetDatetimeFormat();
86
- $instance->datetime_format_no_linebreaks = $plugin->settings()->GetDatetimeFormat( false );
87
 
88
  }
89
 
@@ -93,16 +120,28 @@ class WSAL_Utilities_DateTimeFormatter {
93
  /**
94
  * Remove milliseconds from formatted datetime string.
95
  *
96
- * @param string $formattedDatetime Formatted datetime string
97
  *
98
  * @return string
99
  * @since 4.2.0
100
  */
101
- public static function removeMilliseconds( $formattedDatetime ) {
102
- return preg_replace( self::$am_pm_lookup_pattern, ' $3', $formattedDatetime );
103
  }
104
 
105
- public function getFormattedDateTime( $timestamp, $type = 'datetime', $do_timezone_offset = true, $line_break = false, $use_nb_space_for_am_pm = true, $translated = true ) {
 
 
 
 
 
 
 
 
 
 
 
 
106
  $result = '';
107
  $format = null;
108
  switch ( $type ) {
@@ -126,19 +165,19 @@ class WSAL_Utilities_DateTimeFormatter {
126
  return $result;
127
  }
128
 
129
- // timezone adjustment
130
  $timezone_adjusted_timestamp = $do_timezone_offset ? $timestamp + $this->gmt_offset_sec : $timestamp;
131
 
132
- // milliseconds in format (this is probably not necessary, but we keep it just to be 100% sure)
133
  if ( ! $this->show_milliseconds ) {
134
- // remove the milliseconds placeholder from format string.
135
  $format = str_replace( '.$$$', '', $format );
136
  }
137
 
138
- // date formatting
139
- $result = $translated ? date_i18n( $format, $timezone_adjusted_timestamp ) : date( $format, $timezone_adjusted_timestamp );
140
 
141
- // milliseconds value
142
  if ( $this->show_milliseconds ) {
143
  $result = str_replace(
144
  '$$$',
@@ -148,6 +187,5 @@ class WSAL_Utilities_DateTimeFormatter {
148
  }
149
 
150
  return $result;
151
-
152
  }
153
  }
23
  class WSAL_Utilities_DateTimeFormatter {
24
 
25
  /**
26
+ * Regular expression for matching the milliseconds part of datetime string.
27
+ *
28
+ * @var string
29
  */
30
  private static $am_pm_lookup_pattern = '/\.\d+((\&nbsp;|\ )([AP]M))?/i';
31
 
36
  */
37
  private $gmt_offset_sec = 0;
38
 
39
+ /**
40
+ * Date format.
41
+ *
42
+ * @var string
43
+ */
44
  private $date_format;
45
 
46
+ /**
47
+ * Time format.
48
+ *
49
+ * @var string
50
+ */
51
  private $time_format;
52
 
53
+ /**
54
+ * Datetime format.
55
+ *
56
+ * @var string
57
+ */
58
  private $datetime_format;
59
 
60
+ /**
61
+ * Datetime format without linebreaks.
62
+ *
63
+ * @var string
64
+ */
65
  private $datetime_format_no_linebreaks;
66
 
67
+ /**
68
+ * If true, show milliseconds.
69
+ *
70
+ * @var bool
71
+ */
72
  private $show_milliseconds;
73
 
74
  /**
82
  */
83
  public static function instance() {
84
  static $instance = false;
85
+ if ( false === $instance ) {
86
+ // Late static binding (PHP 5.3+).
87
  $instance = new static();
88
 
89
+ $plugin = WpSecurityAuditLog::get_instance();
90
+ $timezone = $plugin->settings()->get_timezone();
91
 
92
  /**
93
  * Transform timezone values.
101
  }
102
 
103
  if ( 'utc' === $timezone ) {
104
+ $instance->gmt_offset_sec = date( 'Z' ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
105
  } else {
106
  $instance->gmt_offset_sec = get_option( 'gmt_offset' ) * HOUR_IN_SECONDS;
107
  }
108
 
109
  $instance->show_milliseconds = $plugin->settings()->get_show_milliseconds();
110
+ $instance->date_format = $plugin->settings()->get_date_format();
111
+ $instance->time_format = $plugin->settings()->get_time_format();
112
+ $instance->datetime_format = $plugin->settings()->get_datetime_format();
113
+ $instance->datetime_format_no_linebreaks = $plugin->settings()->get_datetime_format( false );
114
 
115
  }
116
 
120
  /**
121
  * Remove milliseconds from formatted datetime string.
122
  *
123
+ * @param string $formatted_datetime Formatted datetime string.
124
  *
125
  * @return string
126
  * @since 4.2.0
127
  */
128
+ public static function remove_milliseconds( $formatted_datetime ) {
129
+ return preg_replace( self::$am_pm_lookup_pattern, ' $3', $formatted_datetime );
130
  }
131
 
132
+ /**
133
+ * Formats date time based on various requirements.
134
+ *
135
+ * @param float $timestamp Timestamp.
136
+ * @param string $type Output type.
137
+ * @param bool $do_timezone_offset If true, timezone offset is applied to the timestamp.
138
+ * @param bool $line_break If true, line-break characters are included.
139
+ * @param bool $use_nb_space_for_am_pm If true, non-breakable space is included before AM/PM part.
140
+ * @param bool $translated If true, the result is translated.
141
+ *
142
+ * @return string
143
+ */
144
+ public function get_formatted_date_time( $timestamp, $type = 'datetime', $do_timezone_offset = true, $line_break = false, $use_nb_space_for_am_pm = true, $translated = true ) {
145
  $result = '';
146
  $format = null;
147
  switch ( $type ) {
165
  return $result;
166
  }
167
 
168
+ // Timezone adjustment.
169
  $timezone_adjusted_timestamp = $do_timezone_offset ? $timestamp + $this->gmt_offset_sec : $timestamp;
170
 
171
+ // Milliseconds in format (this is probably not necessary, but we keep it just to be 100% sure).
172
  if ( ! $this->show_milliseconds ) {
173
+ // Remove the milliseconds placeholder from format string.
174
  $format = str_replace( '.$$$', '', $format );
175
  }
176
 
177
+ // Date formatting.
178
+ $result = $translated ? date_i18n( $format, $timezone_adjusted_timestamp ) : date( $format, $timezone_adjusted_timestamp ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
179
 
180
+ // Milliseconds value.
181
  if ( $this->show_milliseconds ) {
182
  $result = str_replace(
183
  '$$$',
187
  }
188
 
189
  return $result;
 
190
  }
191
  }
classes/Utilities/Emailer.php CHANGED
@@ -25,17 +25,17 @@ class WSAL_Utilities_Emailer {
25
  */
26
  public static function send_deactivation_email() {
27
  // Get the required variables.
28
- $wsal = WpSecurityAuditLog::GetInstance();
29
  $home_url = home_url();
30
  $safe_url = str_replace( array( 'http://', 'https://' ), '', $home_url );
31
  $type_name = $wsal->settings()->get_type_username(); // Get the data to display.
32
  $user = _wp_get_current_user();
33
- $datetime_format = $wsal->settings()->GetDatetimeFormat( false );
34
- $now = current_time( 'timestamp' );
35
  $date_time = str_replace(
36
  '$$$',
37
  substr( number_format( fmod( $now, 1 ), 3 ), 2 ),
38
- date( $datetime_format, $now )
39
  );
40
 
41
  // Checks for display name.
@@ -83,6 +83,9 @@ class WSAL_Utilities_Emailer {
83
  * @param string $email_address - Email Address.
84
  * @param string $subject - Email subject.
85
  * @param string $content - Email content.
 
 
 
86
  * @return bool
87
  */
88
  public static function send_email( $email_address, $subject, $content, $headers = '', $attachments = array() ) {
@@ -151,9 +154,9 @@ class WSAL_Utilities_Emailer {
151
  * @return string
152
  */
153
  public static function custom_wp_mail_from( $original_email_from ) {
154
- $wsal = WpSecurityAuditLog::GetInstance();
155
  $use_email = $wsal->settings()->get_use_email();
156
- $email_from = $wsal->settings()->GetFromEmail();
157
  if ( ! empty( $email_from ) && 'custom_email' === $use_email ) {
158
  return $email_from;
159
  } else {
@@ -168,9 +171,9 @@ class WSAL_Utilities_Emailer {
168
  * @return string
169
  */
170
  public static function custom_wp_mail_from_name( $original_email_from_name ) {
171
- $wsal = WpSecurityAuditLog::GetInstance();
172
  $use_email = $wsal->settings()->get_use_email();
173
- $email_from_name = $wsal->settings()->GetDisplayName();
174
  if ( ! empty( $email_from_name ) && 'custom_email' === $use_email ) {
175
  return $email_from_name;
176
  } else {
25
  */
26
  public static function send_deactivation_email() {
27
  // Get the required variables.
28
+ $wsal = WpSecurityAuditLog::get_instance();
29
  $home_url = home_url();
30
  $safe_url = str_replace( array( 'http://', 'https://' ), '', $home_url );
31
  $type_name = $wsal->settings()->get_type_username(); // Get the data to display.
32
  $user = _wp_get_current_user();
33
+ $datetime_format = $wsal->settings()->get_datetime_format( false );
34
+ $now = current_time( 'timestamp' ); // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested
35
  $date_time = str_replace(
36
  '$$$',
37
  substr( number_format( fmod( $now, 1 ), 3 ), 2 ),
38
+ date( $datetime_format, $now ) // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
39
  );
40
 
41
  // Checks for display name.
83
  * @param string $email_address - Email Address.
84
  * @param string $subject - Email subject.
85
  * @param string $content - Email content.
86
+ * @param string $headers Email headers.
87
+ * @param array $attachments Email attachments.
88
+ *
89
  * @return bool
90
  */
91
  public static function send_email( $email_address, $subject, $content, $headers = '', $attachments = array() ) {
154
  * @return string
155
  */
156
  public static function custom_wp_mail_from( $original_email_from ) {
157
+ $wsal = WpSecurityAuditLog::get_instance();
158
  $use_email = $wsal->settings()->get_use_email();
159
+ $email_from = $wsal->settings()->get_from_email();
160
  if ( ! empty( $email_from ) && 'custom_email' === $use_email ) {
161
  return $email_from;
162
  } else {
171
  * @return string
172
  */
173
  public static function custom_wp_mail_from_name( $original_email_from_name ) {
174
+ $wsal = WpSecurityAuditLog::get_instance();
175
  $use_email = $wsal->settings()->get_use_email();
176
+ $email_from_name = $wsal->settings()->get_display_name();
177
  if ( ! empty( $email_from_name ) && 'custom_email' === $use_email ) {
178
  return $email_from_name;
179
  } else {
classes/Utilities/FileSystemUtils.php CHANGED
@@ -1,4 +1,10 @@
1
  <?php
 
 
 
 
 
 
2
 
3
  /**
4
  * Utility class for handling certain file system related functionality.
@@ -32,7 +38,7 @@ class WSAL_Utilities_FileSystemUtils {
32
  if ( $handle ) {
33
  $ignore_list = array( '.', '..' );
34
  $regexp = '/' . str_replace( array( '.', '*' ), array( '\.', '.*' ), $pattern ) . '/';
35
- while ( false !== ( $file_name = readdir( $handle ) ) ) {
36
  if ( ! in_array( $file_name, $ignore_list, true ) && preg_match( $regexp, $file_name ) ) {
37
  array_push( $result, $folder_slashed . $file_name );
38
  }
@@ -44,4 +50,4 @@ class WSAL_Utilities_FileSystemUtils {
44
 
45
  return $result;
46
  }
47
- }
1
  <?php
2
+ /**
3
+ * File system utility class.
4
+ *
5
+ * @package wsal
6
+ * @since 4.4.0
7
+ */
8
 
9
  /**
10
  * Utility class for handling certain file system related functionality.
38
  if ( $handle ) {
39
  $ignore_list = array( '.', '..' );
40
  $regexp = '/' . str_replace( array( '.', '*' ), array( '\.', '.*' ), $pattern ) . '/';
41
+ while ( false !== ( $file_name = readdir( $handle ) ) ) { // phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition
42
  if ( ! in_array( $file_name, $ignore_list, true ) && preg_match( $regexp, $file_name ) ) {
43
  array_push( $result, $folder_slashed . $file_name );
44
  }
50
 
51
  return $result;
52
  }
53
+ }
classes/Utilities/PluginInstallAndActivate.php CHANGED
@@ -3,7 +3,7 @@
3
  * Handler to install activate plugins.
4
  *
5
  * Provides the allowed plugins data as well as a render method to display the
6
- * items inside of a table with install/actiavte buttons.
7
  *
8
  * @package wsal
9
  * @since 4.0.1
@@ -42,7 +42,7 @@ if ( ! class_exists( 'WSAL_PluginInstallAndActivate' ) ) {
42
  if ( true === $is_allowed_slug ) {
43
  break;
44
  }
45
- $is_allowed_slug = ( isset( $allowed_plugin['plugin_slug'] ) && $allowed_plugin['plugin_slug'] === $plugin_slug ) ? true : false;
46
  }
47
  }
48
 
@@ -99,12 +99,12 @@ if ( ! class_exists( 'WSAL_PluginInstallAndActivate' ) ) {
99
  <div class="addon-wrapper">
100
  <img src="<?php echo esc_url( trailingslashit( WSAL_BASE_URL ) . 'img/addons/' . $details['image_filename'] ); ?>">
101
  <h4><?php esc_html_e( 'Extension for ', 'wp-security-audit-log' ); ?><?php echo esc_html( $details['title'] ); ?></h4>
102
- <p><?php echo sanitize_text_field( $details['plugin_description'] ); ?></p><br>
103
  <p><button class="install-addon button button-primary <?php echo esc_attr( $disable_button ); ?>" data-nonce="<?php echo esc_attr( $nonce ); ?>" data-plugin-slug="<?php echo esc_attr( $details['plugin_slug'] ); ?>" data-plugin-download-url="<?php echo esc_url( $details['plugin_url'] ); ?>" data-plugin-event-tab-id="<?php echo esc_attr( $details['event_tab_id'] ); ?>">
104
  <?php
105
  if ( $this->is_plugin_installed( $details['plugin_slug'] ) && ! WpSecurityAuditLog::is_plugin_active( $details['plugin_slug'] ) ) {
106
  esc_html_e( 'Extension installed, activate now?', 'wp-security-audit-log' );
107
- } elseif ( $this->is_plugin_installed( $details['plugin_slug'] ) && WpSecurityAuditLog::is_plugin_active( $details['plugin_slug'] ) || 'wsal-wpforms.php' === basename( $details['plugin_slug'] ) && function_exists( 'wsal_wpforms_add_custom_event_objects' ) || 'wsal-bbpress.php' === basename( $details['plugin_slug'] ) && function_exists( 'wsal_bbpress_add_custom_event_objects' ) || 'activity-log-yoast-seo.php' === basename( $details['plugin_slug'] ) && function_exists( 'wsal_yoast_seo_extension_add_custom_event_objects' ) ) {
108
  esc_html_e( 'Extension installed', 'wp-security-audit-log' );
109
  } else {
110
  esc_html_e( 'Install Extension', 'wp-security-audit-log' );
@@ -112,7 +112,6 @@ if ( ! class_exists( 'WSAL_PluginInstallAndActivate' ) ) {
112
  ?>
113
  </button><span class="spinner" style="display: none; visibility: visible; float: none; margin: 0 0 0 8px;"></span></p>
114
  </div>
115
-
116
  <?php
117
  }
118
  ?>
3
  * Handler to install activate plugins.
4
  *
5
  * Provides the allowed plugins data as well as a render method to display the
6
+ * items inside of a table with install/activate buttons.
7
  *
8
  * @package wsal
9
  * @since 4.0.1
42
  if ( true === $is_allowed_slug ) {
43
  break;
44
  }
45
+ $is_allowed_slug = isset( $allowed_plugin['plugin_slug'] ) && $allowed_plugin['plugin_slug'] === $plugin_slug;
46
  }
47
  }
48
 
99
  <div class="addon-wrapper">
100
  <img src="<?php echo esc_url( trailingslashit( WSAL_BASE_URL ) . 'img/addons/' . $details['image_filename'] ); ?>">
101
  <h4><?php esc_html_e( 'Extension for ', 'wp-security-audit-log' ); ?><?php echo esc_html( $details['title'] ); ?></h4>
102
+ <p><?php echo sanitize_text_field( $details['plugin_description'] ); // phpcs:ignore ?></p><br>
103
  <p><button class="install-addon button button-primary <?php echo esc_attr( $disable_button ); ?>" data-nonce="<?php echo esc_attr( $nonce ); ?>" data-plugin-slug="<?php echo esc_attr( $details['plugin_slug'] ); ?>" data-plugin-download-url="<?php echo esc_url( $details['plugin_url'] ); ?>" data-plugin-event-tab-id="<?php echo esc_attr( $details['event_tab_id'] ); ?>">
104
  <?php
105
  if ( $this->is_plugin_installed( $details['plugin_slug'] ) && ! WpSecurityAuditLog::is_plugin_active( $details['plugin_slug'] ) ) {
106
  esc_html_e( 'Extension installed, activate now?', 'wp-security-audit-log' );
107
+ } elseif ( $this->is_plugin_installed( $details['plugin_slug'] ) && WpSecurityAuditLog::is_plugin_active( $details['plugin_slug'] ) || 'wsal-wpforms.php' === basename( $details['plugin_slug'] ) && function_exists( 'wsal_wpforms_add_custom_event_objects' ) || 'wsal-bbpress.php' === basename( $details['plugin_slug'] ) && function_exists( 'wsal_bbpress_add_custom_event_objects' ) || 'activity-log-yoast-seo.php' === basename( $details['plugin_slug'] ) && function_exists( 'wsal_yoast_seo_extension_add_custom_event_objects' ) ) {
108
  esc_html_e( 'Extension installed', 'wp-security-audit-log' );
109
  } else {
110
  esc_html_e( 'Install Extension', 'wp-security-audit-log' );
112
  ?>
113
  </button><span class="spinner" style="display: none; visibility: visible; float: none; margin: 0 0 0 8px;"></span></p>
114
  </div>
 
115
  <?php
116
  }
117
  ?>
classes/Utilities/PluginInstallerAction.php CHANGED
@@ -64,7 +64,7 @@ if ( ! class_exists( 'WSAL_PluginInstallerAction' ) ) {
64
  }
65
 
66
  // validate that the plugin is in the allowed list, or it is our helper plugin with external libraries.
67
- $valid = false;
68
  $helper_plugin_installation = 'wsal-external-libraries/wsal-external-libraries.php' === $plugin_slug;
69
  if ( $helper_plugin_installation ) {
70
  $valid = true;
@@ -106,9 +106,9 @@ if ( ! class_exists( 'WSAL_PluginInstallerAction' ) ) {
106
  $result = 'success';
107
  }
108
 
109
- // if we're installing our helper plugin, we also need to delete the nudge to install the helper plugin
110
  if ( $helper_plugin_installation ) {
111
- WpSecurityAuditLog::GetInstance()->DeleteGlobalSetting( 'show-helper-plugin-needed-nudge' );
112
  }
113
 
114
  wp_send_json( $result );
@@ -226,7 +226,6 @@ if ( ! class_exists( 'WSAL_PluginInstallerAction' ) ) {
226
  } else {
227
  return false;
228
  }
229
-
230
  }
231
  }
232
  }
64
  }
65
 
66
  // validate that the plugin is in the allowed list, or it is our helper plugin with external libraries.
67
+ $valid = false;
68
  $helper_plugin_installation = 'wsal-external-libraries/wsal-external-libraries.php' === $plugin_slug;
69
  if ( $helper_plugin_installation ) {
70
  $valid = true;
106
  $result = 'success';
107
  }
108
 
109
+ // If we're installing our helper plugin, we also need to delete the nudge to install the helper plugin.
110
  if ( $helper_plugin_installation ) {
111
+ WpSecurityAuditLog::get_instance()->delete_global_setting( 'show-helper-plugin-needed-nudge' );
112
  }
113
 
114
  wp_send_json( $result );
226
  } else {
227
  return false;
228
  }
 
229
  }
230
  }
231
  }
classes/Utilities/RequestUtils.php CHANGED
@@ -1,4 +1,15 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  /**
4
  * Utility class for handling request inputs.
@@ -7,8 +18,14 @@
7
  * @since 4.1.4
8
  */
9
  class WSAL_Utilities_RequestUtils {
 
 
 
 
 
 
10
  public static function get_filtered_request_data() {
11
- $result = [];
12
 
13
  $get_data = filter_input_array( INPUT_GET );
14
  if ( is_array( $get_data ) ) {
@@ -57,4 +74,4 @@ class WSAL_Utilities_RequestUtils {
57
  public static function is_ip_address( $ip_address ) {
58
  return filter_var( $ip_address, FILTER_VALIDATE_IP ) !== false;
59
  }
60
- }
1
  <?php
2
+ /**
3
+ * Utility class for handling request inputs.
4
+ *
5
+ * @package wsal
6
+ * @since 4.1.4
7
+ */
8
+
9
+ // Exit if accessed directly.
10
+ if ( ! defined( 'ABSPATH' ) ) {
11
+ exit;
12
+ }
13
 
14
  /**
15
  * Utility class for handling request inputs.
18
  * @since 4.1.4
19
  */
20
  class WSAL_Utilities_RequestUtils {
21
+
22
+ /**
23
+ * Filters request data.
24
+ *
25
+ * @return array Filtered request data.
26
+ */
27
  public static function get_filtered_request_data() {
28
+ $result = array();
29
 
30
  $get_data = filter_input_array( INPUT_GET );
31
  if ( is_array( $get_data ) ) {
74
  public static function is_ip_address( $ip_address ) {
75
  return filter_var( $ip_address, FILTER_VALIDATE_IP ) !== false;
76
  }
77
+ }
classes/Utilities/UserUtils.php CHANGED
@@ -1,4 +1,10 @@
1
  <?php
 
 
 
 
 
 
2
 
3
  // Exit if accessed directly.
4
  if ( ! defined( 'ABSPATH' ) ) {
@@ -13,10 +19,15 @@ if ( ! defined( 'ABSPATH' ) ) {
13
  */
14
  class WSAL_Utilities_UsersUtils {
15
 
 
 
 
 
 
16
  private static $cached_users = array();
17
 
18
  /**
19
- * Local static cache for the value of setting determining the prefered user data to display as label.
20
  *
21
  * @var string
22
  */
@@ -64,7 +75,7 @@ class WSAL_Utilities_UsersUtils {
64
  *
65
  * @since 4.3.1 Made the meta attribute mandatory, changed to static and moved from occurrence to alert.
66
  */
67
- public static function GetUsername( $meta = null ) {
68
  if ( ! is_array( $meta ) ) {
69
  return '';
70
  }
@@ -121,7 +132,7 @@ class WSAL_Utilities_UsersUtils {
121
  /**
122
  * Retrieves user ID using either the username of user ID.
123
  *
124
- * @param int|string $user_login
125
  *
126
  * @return int|null
127
  */
@@ -132,7 +143,7 @@ class WSAL_Utilities_UsersUtils {
132
  }
133
 
134
  global $wpdb;
135
- $user_id = $wpdb->get_var(
136
  $wpdb->prepare(
137
  "SELECT ID FROM $wpdb->users WHERE user_login = %s OR ID = %d;",
138
  $user_login,
@@ -163,11 +174,10 @@ class WSAL_Utilities_UsersUtils {
163
  return esc_html( ucwords( implode( ', ', $roles ) ) );
164
  }
165
 
166
- if ( is_string( $roles ) && '' != $roles ) {
167
  return esc_html( ucwords( str_replace( array( '"', '[', ']' ), ' ', $roles ) ) );
168
  }
169
 
170
  return '<i>' . esc_html__( 'Unknown', 'wp-security-audit-log' ) . '</i>';
171
-
172
  }
173
  }
1
  <?php
2
+ /**
3
+ * User utility class.
4
+ *
5
+ * @package wsal
6
+ * @since 4.3.0
7
+ */
8
 
9
  // Exit if accessed directly.
10
  if ( ! defined( 'ABSPATH' ) ) {
19
  */
20
  class WSAL_Utilities_UsersUtils {
21
 
22
+ /**
23
+ * Local user cache. Keys are usernames and values are user IDs.
24
+ *
25
+ * @var array
26
+ */
27
  private static $cached_users = array();
28
 
29
  /**
30
+ * Local static cache for the value of setting determining the preferred user data to display as label.
31
  *
32
  * @var string
33
  */
75
  *
76
  * @since 4.3.1 Made the meta attribute mandatory, changed to static and moved from occurrence to alert.
77
  */
78
+ public static function get_username( $meta = null ) {
79
  if ( ! is_array( $meta ) ) {
80
  return '';
81
  }
132
  /**
133
  * Retrieves user ID using either the username of user ID.
134
  *
135
+ * @param int|string $user_login User login or ID.
136
  *
137
  * @return int|null
138
  */
143
  }
144
 
145
  global $wpdb;
146
+ $user_id = $wpdb->get_var( // phpcs:ignore
147
  $wpdb->prepare(
148
  "SELECT ID FROM $wpdb->users WHERE user_login = %s OR ID = %d;",
149
  $user_login,
174
  return esc_html( ucwords( implode( ', ', $roles ) ) );
175
  }
176
 
177
+ if ( is_string( $roles ) && '' !== $roles ) {
178
  return esc_html( ucwords( str_replace( array( '"', '[', ']' ), ' ', $roles ) ) );
179
  }
180
 
181
  return '<i>' . esc_html__( 'Unknown', 'wp-security-audit-log' ) . '</i>';
 
182
  }
183
  }
classes/ViewManager.php CHANGED
@@ -4,7 +4,7 @@
4
  *
5
  * View manager class file.
6
  *
7
- * @since 1.0.0
8
  * @package wsal
9
  */
10
 
@@ -35,25 +35,24 @@ class WSAL_ViewManager {
35
  *
36
  * @var object
37
  */
38
- protected $_plugin;
39
 
40
  /**
41
  * Active view.
42
  *
43
  * @var WSAL_AbstractView|null
44
  */
45
- protected $_active_view = false;
46
 
47
  /**
48
  * Method: Constructor.
49
  *
50
  * @param WpSecurityAuditLog $plugin - Instance of WpSecurityAuditLog.
51
  *
52
- * @throws Freemius_Exception
53
  * @since 1.0.0
54
  */
55
  public function __construct( WpSecurityAuditLog $plugin ) {
56
- $this->_plugin = $plugin;
57
 
58
  // Skipped views array.
59
  $skip_views = array();
@@ -65,8 +64,8 @@ class WSAL_ViewManager {
65
  *
66
  * @since 3.2.3
67
  */
68
- if ( file_exists( $this->_plugin->GetBaseDir() . 'classes/Views/SetupWizard.php' ) ) {
69
- $skip_views[] = $this->_plugin->GetBaseDir() . 'classes/Views/SetupWizard.php';
70
  }
71
 
72
  /**
@@ -76,7 +75,7 @@ class WSAL_ViewManager {
76
  *
77
  * @since 4.0.4
78
  */
79
- $skip_views[] = $this->_plugin->GetBaseDir() . 'classes/Views/Licensing.php';
80
 
81
  /**
82
  * Skipped Views.
@@ -89,31 +88,37 @@ class WSAL_ViewManager {
89
  $skip_views = apply_filters( 'wsal_skip_views', $skip_views );
90
 
91
  // Load views.
92
- foreach ( WSAL_Utilities_FileSystemUtils::read_files_in_folder( $this->_plugin->GetBaseDir() . 'classes/Views', '*.php' ) as $file ) {
93
- if ( empty( $skip_views ) || ! in_array( $file, $skip_views ) ) {
94
- $this->AddFromFile( $file );
95
  }
96
  }
97
 
98
- // stop Freemius from hiding the menu on sub sites under certain circumstances
99
- add_filter('fs_should_hide_site_admin_settings_on_network_activation_mode_wp-security-audit-log', array( $this, 'bypass_freemius_menu_hiding'));
 
 
 
 
 
 
100
 
101
  // Add menus.
102
- add_action( 'admin_menu', array( $this, 'AddAdminMenus' ) );
103
- add_action( 'network_admin_menu', array( $this, 'AddAdminMenus' ) );
104
 
105
  // Add plugin shortcut links.
106
- add_filter( 'plugin_action_links_' . $plugin->GetBaseName(), array( $this, 'AddPluginShortcuts' ) );
107
 
108
  // Render header.
109
- add_action( 'admin_enqueue_scripts', array( $this, 'RenderViewHeader' ) );
110
 
111
  // Render footer.
112
- add_action( 'admin_footer', array( $this, 'RenderViewFooter' ) );
113
 
114
  // Initialize setup wizard.
115
- if ( ! $this->_plugin->GetGlobalBooleanSetting( 'setup-complete', false )
116
- && $this->_plugin->settings()->CurrentUserCan( 'edit' )
117
  ) {
118
  new WSAL_Views_SetupWizard( $plugin );
119
  }
@@ -135,7 +140,7 @@ class WSAL_ViewManager {
135
  if ( defined( 'WFCM_VERSION' ) ) {
136
  if ( version_compare( WFCM_VERSION, '1.6.0', '<' ) ) {
137
  echo '<div class="notice notice-success">
138
- <p>' . __( 'WP Activity Log requires Website File Changes Monitor 1.6.0. Please upgrade that plugin.', 'wp-security-audit-log' ) . '</p>
139
  </div>';
140
  }
141
  }
@@ -147,9 +152,9 @@ class WSAL_ViewManager {
147
  *
148
  * @param string $file Path to file.
149
  */
150
- public function AddFromFile( $file ) {
151
  $file = basename( $file, '.php' );
152
- $this->AddFromClass( WSAL_CLASS_PREFIX . 'Views_' . $file );
153
  }
154
 
155
  /**
@@ -157,12 +162,12 @@ class WSAL_ViewManager {
157
  *
158
  * @param string $class Class name.
159
  */
160
- public function AddFromClass( $class ) {
161
- $view = new $class( $this->_plugin );
162
- // only load WSAL_AbstractView instances to prevent lingering classes
163
- // that did not impliment this from throwing fatals by being autoloaded.
164
  if ( is_a( $view, '\WSAL_AbstractView' ) ) {
165
- $this->AddInstance( $view );
166
  }
167
  }
168
 
@@ -171,15 +176,15 @@ class WSAL_ViewManager {
171
  *
172
  * @param WSAL_AbstractView $view The new view.
173
  */
174
- public function AddInstance( WSAL_AbstractView $view ) {
175
  $this->views[] = $view;
176
  }
177
 
178
  /**
179
  * Order views by their declared weight.
180
  */
181
- public function ReorderViews() {
182
- usort( $this->views, array( $this, 'OrderByWeight' ) );
183
  }
184
 
185
  /**
@@ -190,9 +195,9 @@ class WSAL_ViewManager {
190
  * @param WSAL_AbstractView $b - Second view.
191
  * @return int
192
  */
193
- public function OrderByWeight( WSAL_AbstractView $a, WSAL_AbstractView $b ) {
194
- $wa = $a->GetWeight();
195
- $wb = $b->GetWeight();
196
  switch ( true ) {
197
  case $wa < $wb:
198
  return -1;
@@ -206,55 +211,55 @@ class WSAL_ViewManager {
206
  /**
207
  * WordPress Action
208
  */
209
- public function AddAdminMenus() {
210
- $this->ReorderViews();
211
 
212
- if ( $this->_plugin->settings()->CurrentUserCan( 'view' ) && count( $this->views ) ) {
213
  // Add main menu.
214
- $main_view_menu_slug = $this->views[0]->GetSafeViewName();
215
  $this->views[0]->hook_suffix = add_menu_page(
216
  'WP Activity Log',
217
  'WP Activity Log',
218
  'read', // No capability requirement.
219
  $main_view_menu_slug,
220
- array( $this, 'RenderViewBody' ),
221
- $this->views[0]->GetIcon(),
222
  '2.5' // Right after dashboard.
223
  );
224
 
225
- // protected views to be displayed only to user with full plugin access
226
  $protected_views = array(
227
- 'wsal-togglealerts',
228
- 'wsal-usersessions-views',
229
- 'wsal-settings',
230
- 'wsal-ext-settings',
231
- 'wsal-rep-views-main',
232
- 'wsal-np-notifications',
233
- 'wsal-setup'
234
- );
235
-
236
- // check edit privileges of the current user
237
- $has_current_user_edit_priv = $this->_plugin->settings()->CurrentUserCan( 'edit' );
238
 
239
  // Add menu items.
240
  foreach ( $this->views as $view ) {
241
- if ( $view->IsAccessible() ) {
242
- $safe_view_name = $view->GetSafeViewName();
243
- if ( $this->GetClassNameByView( $safe_view_name ) ) {
244
  continue;
245
  }
246
 
247
- if ( in_array( $safe_view_name, $protected_views ) && ! $has_current_user_edit_priv ) {
248
  continue;
249
  }
250
 
251
  $view->hook_suffix = add_submenu_page(
252
- $view->IsVisible() ? $main_view_menu_slug : null,
253
- $view->GetTitle(),
254
- $view->GetName(),
255
  'read', // No capability requirement.
256
  $safe_view_name,
257
- array( $this, 'RenderViewBody' )
258
  );
259
  }
260
  }
@@ -266,17 +271,17 @@ class WSAL_ViewManager {
266
  *
267
  * @param array $old_links - Array of old links.
268
  */
269
- public function AddPluginShortcuts( $old_links ) {
270
- $this->ReorderViews();
271
 
272
  $new_links = array();
273
  foreach ( $this->views as $view ) {
274
- if ( $view->HasPluginShortcutLink() ) {
275
- $new_links[] = '<a href="' . add_query_arg( 'page', $view->GetSafeViewName(), admin_url( 'admin.php' ) ) . '">' . $view->GetName() . '</a>';
276
 
277
  if ( 1 === count( $new_links ) && ! wsal_freemius()->is__premium_only() ) {
278
- // Trial link
279
- $trial_link = 'https://wpactivitylog.com/trial-premium-edition-plugin/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL';
280
  $new_links[] = '<a style="font-weight:bold" href="' . $trial_link . '" target="_blank">' . __( 'Free Premium Trial', 'wp-security-audit-log' ) . '</a>';
281
  }
282
  }
@@ -289,13 +294,13 @@ class WSAL_ViewManager {
289
  *
290
  * @return int
291
  */
292
- protected function GetBackendPageIndex() {
293
  // Get current view via $_GET array.
294
  $current_view = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
295
 
296
  if ( isset( $current_view ) ) {
297
  foreach ( $this->views as $i => $view ) {
298
- if ( $current_view === $view->GetSafeViewName() ) {
299
  return $i;
300
  }
301
  }
@@ -308,69 +313,72 @@ class WSAL_ViewManager {
308
  *
309
  * @return WSAL_AbstractView|null
310
  */
311
- public function GetActiveView() {
312
- if ( false === $this->_active_view ) {
313
- $this->_active_view = null;
314
 
315
  // Get current view via $_GET array.
316
  $current_view = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
317
 
318
  if ( isset( $current_view ) ) {
319
  foreach ( $this->views as $view ) {
320
- if ( $current_view === $view->GetSafeViewName() ) {
321
- $this->_active_view = $view;
322
  }
323
  }
324
  }
325
 
326
- if ( $this->_active_view ) {
327
- $this->_active_view->is_active = true;
328
  }
329
  }
330
- return $this->_active_view;
331
  }
332
 
333
  /**
334
  * Render header of the current view.
335
  */
336
- public function RenderViewHeader() {
337
- if ( $view = $this->GetActiveView() ) {
338
- $view->Header();
 
339
  }
340
  }
341
 
342
  /**
343
  * Render footer of the current view.
344
  */
345
- public function RenderViewFooter() {
346
- if ( $view = $this->GetActiveView() ) {
347
- $view->Footer();
 
348
  }
 
349
  global $pagenow;
350
- if ( 'admin.php' === $pagenow && 'wsal-auditlog-pricing' === $_GET['page'] ) {
351
  ?>
352
- <style>
353
- .fs-full-size-wrapper {
354
- margin: 0px 0 -65px -20px !important;
355
- }
356
-
357
- #root .fs-app-header .fs-page-title h2, #fs_pricing_wrapper .fs-app-header .fs-page-title h2 {
358
- font-size: 23px;
359
- font-weight: 400;
360
- margin: 0;
361
- padding: 9px 0 4px 20px;
362
- line-height: 1.3;
363
- }
364
-
365
- @media only screen and (max-width: 768px) {
366
- #root #fs_pricing_wrapper .fs-app-main .fs-section--plans-and-pricing .fs-section--packages .fs-packages-menu, #fs_pricing_wrapper #fs_pricing_wrapper .fs-app-main .fs-section--plans-and-pricing .fs-section--packages .fs-packages-menu {
367
- padding: 5px;
368
- display: flex;
369
- width: 100%;
370
- margin: 0 auto;
371
- }
372
- }
373
- </style>
374
  <?php
375
  }
376
  }
@@ -378,16 +386,15 @@ class WSAL_ViewManager {
378
  /**
379
  * Render content of the current view.
380
  */
381
- public function RenderViewBody() {
382
- $view = $this->GetActiveView();
383
-
384
  if ( $view && $view instanceof WSAL_AbstractView ) :
385
  ?>
386
  <div class="wrap">
387
  <?php
388
- $view->RenderIcon();
389
- $view->RenderTitle();
390
- $view->RenderContent();
391
  ?>
392
  </div>
393
  <?php
@@ -400,7 +407,7 @@ class WSAL_ViewManager {
400
  * @param string $class_name View class name.
401
  * @return WSAL_AbstractView|bool The view or false on failure.
402
  */
403
- public function FindByClassName( $class_name ) {
404
  foreach ( $this->views as $view ) {
405
  if ( $view instanceof $class_name ) {
406
  return $view;
@@ -415,7 +422,7 @@ class WSAL_ViewManager {
415
  * @param string $view_slug - Slug of view.
416
  * @since 1.0.0
417
  */
418
- private function GetClassNameByView( $view_slug ) {
419
  $not_show = false;
420
  switch ( $view_slug ) {
421
  case 'wsal-emailnotifications':
@@ -463,7 +470,7 @@ class WSAL_ViewManager {
463
  }
464
 
465
  // Return if multisite but not on the network admin.
466
- if ( is_multisite() && ! is_network_admin() ) {
467
  return;
468
  }
469
 
@@ -481,27 +488,33 @@ class WSAL_ViewManager {
481
  }
482
 
483
  /**
484
- * @param bool $should_hide
 
 
485
  *
486
  * @return bool
487
  */
488
- public function bypass_freemius_menu_hiding($should_hide) {
489
- return false;
490
  }
491
 
492
  /**
493
- * Builds a relative asset path that takes SCRIPT_DEBUG constant into account.
494
- *
495
- * @param string $path Path relative to the plugin folder.
496
- * @param string $filename Filename base (.min is optionally appended to this).
497
- * @param string $extension File extension
 
498
  *
499
  * @return string
500
  */
501
- public static function get_asset_path($path, $filename, $extension) {
502
- $result = $path . $filename;
503
- $result .= SCRIPT_DEBUG ? '.' : '.min.';
 
 
504
  $result .= $extension;
 
505
  return $result;
506
  }
507
  }
4
  *
5
  * View manager class file.
6
  *
7
+ * @since 1.0.0
8
  * @package wsal
9
  */
10
 
35
  *
36
  * @var object
37
  */
38
+ protected $plugin;
39
 
40
  /**
41
  * Active view.
42
  *
43
  * @var WSAL_AbstractView|null
44
  */
45
+ protected $active_view = false;
46
 
47
  /**
48
  * Method: Constructor.
49
  *
50
  * @param WpSecurityAuditLog $plugin - Instance of WpSecurityAuditLog.
51
  *
 
52
  * @since 1.0.0
53
  */
54
  public function __construct( WpSecurityAuditLog $plugin ) {
55
+ $this->plugin = $plugin;
56
 
57
  // Skipped views array.
58
  $skip_views = array();
64
  *
65
  * @since 3.2.3
66
  */
67
+ if ( file_exists( $this->plugin->get_base_dir() . 'classes/Views/SetupWizard.php' ) ) {
68
+ $skip_views[] = $this->plugin->get_base_dir() . 'classes/Views/SetupWizard.php';
69
  }
70
 
71
  /**
75
  *
76
  * @since 4.0.4
77
  */
78
+ $skip_views[] = $this->plugin->get_base_dir() . 'classes/Views/Licensing.php';
79
 
80
  /**
81
  * Skipped Views.
88
  $skip_views = apply_filters( 'wsal_skip_views', $skip_views );
89
 
90
  // Load views.
91
+ foreach ( WSAL_Utilities_FileSystemUtils::read_files_in_folder( $this->plugin->get_base_dir() . 'classes/Views', '*.php' ) as $file ) {
92
+ if ( empty( $skip_views ) || ! in_array( $file, $skip_views ) ) { // phpcs:ignore
93
+ $this->add_from_file( $file );
94
  }
95
  }
96
 
97
+ // Stop Freemius from hiding the menu on sub sites under certain circumstances.
98
+ add_filter(
99
+ 'fs_should_hide_site_admin_settings_on_network_activation_mode_wp-security-audit-log',
100
+ array(
101
+ $this,
102
+ 'bypass_freemius_menu_hiding',
103
+ )
104
+ );
105
 
106
  // Add menus.
107
+ add_action( 'admin_menu', array( $this, 'add_admin_menus' ) );
108
+ add_action( 'network_admin_menu', array( $this, 'add_admin_menus' ) );
109
 
110
  // Add plugin shortcut links.
111
+ add_filter( 'plugin_action_links_' . $plugin->get_base_name(), array( $this, 'add_plugin_shortcuts' ) );
112
 
113
  // Render header.
114
+ add_action( 'admin_enqueue_scripts', array( $this, 'render_view_header' ) );
115
 
116
  // Render footer.
117
+ add_action( 'admin_footer', array( $this, 'render_view_footer' ) );
118
 
119
  // Initialize setup wizard.
120
+ if ( ! $this->plugin->get_global_boolean_setting( 'setup-complete', false )
121
+ && $this->plugin->settings()->current_user_can( 'edit' )
122
  ) {
123
  new WSAL_Views_SetupWizard( $plugin );
124
  }
140
  if ( defined( 'WFCM_VERSION' ) ) {
141
  if ( version_compare( WFCM_VERSION, '1.6.0', '<' ) ) {
142
  echo '<div class="notice notice-success">
143
+ <p>' . esc_html__( 'WP Activity Log requires Website File Changes Monitor 1.6.0. Please upgrade that plugin.', 'wp-security-audit-log' ) . '</p>
144
  </div>';
145
  }
146
  }
152
  *
153
  * @param string $file Path to file.
154
  */
155
+ public function add_from_file( $file ) {
156
  $file = basename( $file, '.php' );
157
+ $this->add_from_class( WSAL_CLASS_PREFIX . 'Views_' . $file );
158
  }
159
 
160
  /**
162
  *
163
  * @param string $class Class name.
164
  */
165
+ public function add_from_class( $class ) {
166
+ $view = new $class( $this->plugin );
167
+ // Only load WSAL_AbstractView instances to prevent lingering classes
168
+ // that did not implement this from throwing fatals by being autoloaded.
169
  if ( is_a( $view, '\WSAL_AbstractView' ) ) {
170
+ $this->add_instance( $view );
171
  }
172
  }
173
 
176
  *
177
  * @param WSAL_AbstractView $view The new view.
178
  */
179
+ public function add_instance( WSAL_AbstractView $view ) {
180
  $this->views[] = $view;
181
  }
182
 
183
  /**
184
  * Order views by their declared weight.
185
  */
186
+ public function reorder_views() {
187
+ usort( $this->views, array( $this, 'order_by_weight' ) );
188
  }
189
 
190
  /**
195
  * @param WSAL_AbstractView $b - Second view.
196
  * @return int
197
  */
198
+ public function order_by_weight( WSAL_AbstractView $a, WSAL_AbstractView $b ) {
199
+ $wa = $a->get_weight();
200
+ $wb = $b->get_weight();
201
  switch ( true ) {
202
  case $wa < $wb:
203
  return -1;
211
  /**
212
  * WordPress Action
213
  */
214
+ public function add_admin_menus() {
215
+ $this->reorder_views();
216
 
217
+ if ( $this->plugin->settings()->current_user_can( 'view' ) && count( $this->views ) ) {
218
  // Add main menu.
219
+ $main_view_menu_slug = $this->views[0]->get_safe_view_name();
220
  $this->views[0]->hook_suffix = add_menu_page(
221
  'WP Activity Log',
222
  'WP Activity Log',
223
  'read', // No capability requirement.
224
  $main_view_menu_slug,
225
+ array( $this, 'render_view_body' ),
226
+ $this->views[0]->get_icon(),
227
  '2.5' // Right after dashboard.
228
  );
229
 
230
+ // Protected views to be displayed only to user with full plugin access.
231
  $protected_views = array(
232
+ 'wsal-togglealerts',
233
+ 'wsal-usersessions-views',
234
+ 'wsal-settings',
235
+ 'wsal-ext-settings',
236
+ 'wsal-rep-views-main',
237
+ 'wsal-np-notifications',
238
+ 'wsal-setup',
239
+ );
240
+
241
+ // Check edit privileges of the current user.
242
+ $has_current_user_edit_priv = $this->plugin->settings()->current_user_can( 'edit' );
243
 
244
  // Add menu items.
245
  foreach ( $this->views as $view ) {
246
+ if ( $view->is_accessible() ) {
247
+ $safe_view_name = $view->get_safe_view_name();
248
+ if ( $this->get_class_name_by_view( $safe_view_name ) ) {
249
  continue;
250
  }
251
 
252
+ if ( in_array( $safe_view_name, $protected_views ) && ! $has_current_user_edit_priv ) { // phpcs:ignore
253
  continue;
254
  }
255
 
256
  $view->hook_suffix = add_submenu_page(
257
+ $view->is_visible() ? $main_view_menu_slug : null,
258
+ $view->get_title(),
259
+ $view->get_name(),
260
  'read', // No capability requirement.
261
  $safe_view_name,
262
+ array( $this, 'render_view_body' )
263
  );
264
  }
265
  }
271
  *
272
  * @param array $old_links - Array of old links.
273
  */
274
+ public function add_plugin_shortcuts( $old_links ) {
275
+ $this->reorder_views();
276
 
277
  $new_links = array();
278
  foreach ( $this->views as $view ) {
279
+ if ( $view->has_plugin_shortcut_link() ) {
280
+ $new_links[] = '<a href="' . add_query_arg( 'page', $view->get_safe_view_name(), admin_url( 'admin.php' ) ) . '">' . $view->get_name() . '</a>';
281
 
282
  if ( 1 === count( $new_links ) && ! wsal_freemius()->is__premium_only() ) {
283
+ // Trial link.
284
+ $trial_link = 'https://wpactivitylog.com/trial-premium-edition-plugin/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL';
285
  $new_links[] = '<a style="font-weight:bold" href="' . $trial_link . '" target="_blank">' . __( 'Free Premium Trial', 'wp-security-audit-log' ) . '</a>';
286
  }
287
  }
294
  *
295
  * @return int
296
  */
297
+ protected function get_backend_page_index() {
298
  // Get current view via $_GET array.
299
  $current_view = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
300
 
301
  if ( isset( $current_view ) ) {
302
  foreach ( $this->views as $i => $view ) {
303
+ if ( $current_view === $view->get_safe_view_name() ) {
304
  return $i;
305
  }
306
  }
313
  *
314
  * @return WSAL_AbstractView|null
315
  */
316
+ public function get_active_view() {
317
+ if ( false === $this->active_view ) {
318
+ $this->active_view = null;
319
 
320
  // Get current view via $_GET array.
321
  $current_view = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRING );
322
 
323
  if ( isset( $current_view ) ) {
324
  foreach ( $this->views as $view ) {
325
+ if ( $current_view === $view->get_safe_view_name() ) {
326
+ $this->active_view = $view;
327
  }
328
  }
329
  }
330
 
331
+ if ( $this->active_view ) {
332
+ $this->active_view->is_active = true;
333
  }
334
  }
335
+ return $this->active_view;
336
  }
337
 
338
  /**
339
  * Render header of the current view.
340
  */
341
+ public function render_view_header() {
342
+ $view = $this->get_active_view();
343
+ if ( $view ) {
344
+ $view->header();
345
  }
346
  }
347
 
348
  /**
349
  * Render footer of the current view.
350
  */
351
+ public function render_view_footer() {
352
+ $view = $this->get_active_view();
353
+ if ( $view ) {
354
+ $view->footer();
355
  }
356
+
357
  global $pagenow;
358
+ if ( 'admin.php' === $pagenow && 'wsal-auditlog-pricing' === $_GET['page'] ) { // phpcs:ignore
359
  ?>
360
+ <style>
361
+ .fs-full-size-wrapper {
362
+ margin: 0px 0 -65px -20px !important;
363
+ }
364
+
365
+ #root .fs-app-header .fs-page-title h2, #fs_pricing_wrapper .fs-app-header .fs-page-title h2 {
366
+ font-size: 23px;
367
+ font-weight: 400;
368
+ margin: 0;
369
+ padding: 9px 0 4px 20px;
370
+ line-height: 1.3;
371
+ }
372
+
373
+ @media only screen and (max-width: 768px) {
374
+ #root #fs_pricing_wrapper .fs-app-main .fs-section--plans-and-pricing .fs-section--packages .fs-packages-menu, #fs_pricing_wrapper #fs_pricing_wrapper .fs-app-main .fs-section--plans-and-pricing .fs-section--packages .fs-packages-menu {
375
+ padding: 5px;
376
+ display: flex;
377
+ width: 100%;
378
+ margin: 0 auto;
379
+ }
380
+ }
381
+ </style>
382
  <?php
383
  }
384
  }
386
  /**
387
  * Render content of the current view.
388
  */
389
+ public function render_view_body() {
390
+ $view = $this->get_active_view();
 
391
  if ( $view && $view instanceof WSAL_AbstractView ) :
392
  ?>
393
  <div class="wrap">
394
  <?php
395
+ $view->render_icon();
396
+ $view->render_title();
397
+ $view->render_content();
398
  ?>
399
  </div>
400
  <?php
407
  * @param string $class_name View class name.
408
  * @return WSAL_AbstractView|bool The view or false on failure.
409
  */
410
+ public function find_by_class_name( $class_name ) {
411
  foreach ( $this->views as $view ) {
412
  if ( $view instanceof $class_name ) {
413
  return $view;
422
  * @param string $view_slug - Slug of view.
423
  * @since 1.0.0
424
  */
425
+ private function get_class_name_by_view( $view_slug ) {
426
  $not_show = false;
427
  switch ( $view_slug ) {
428
  case 'wsal-emailnotifications':
470
  }
471
 
472
  // Return if multisite but not on the network admin.
473
+ if ( ! is_network_admin() ) {
474
  return;
475
  }
476
 
488
  }
489
 
490
  /**
491
+ * Bypasses Freemius hiding menu items.
492
+ *
493
+ * @param bool $should_hide Should allow Freemium to hide menu items.
494
  *
495
  * @return bool
496
  */
497
+ public function bypass_freemius_menu_hiding( $should_hide ) {
498
+ return false;
499
  }
500
 
501
  /**
502
+ * Builds a relative asset path that takes SCRIPT_DEBUG constant into account.
503
+ *
504
+ * @param string $path Path relative to the plugin folder.
505
+ * @param string $filename Filename base (.min is optionally appended to this).
506
+ * @param string $extension File extension.
507
+ * @param bool $use_minified_version If true, the minified version of the file is used.
508
  *
509
  * @return string
510
  */
511
+ public static function get_asset_path( $path, $filename, $extension, $use_minified_version = true ) {
512
+ $result = $path . $filename . '.';
513
+ if ( $use_minified_version && SCRIPT_DEBUG ) {
514
+ $result .= 'min.';
515
+ }
516
  $result .= $extension;
517
+
518
  return $result;
519
  }
520
  }
classes/Views/AuditLog.php CHANGED
@@ -4,8 +4,9 @@
4
  *
5
  * Class file for Audit Log View.
6
  *
7
- * @since 1.0.0
8
- * @package wsal
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -16,23 +17,24 @@ if ( ! defined( 'ABSPATH' ) ) {
16
  /**
17
  * Audit Log Viewer Page
18
  *
19
- * @package wsal
 
20
  */
21
  class WSAL_Views_AuditLog extends WSAL_AbstractView {
22
 
23
  /**
24
  * Listing view object (Instance of WSAL_AuditLogListView).
25
  *
26
- * @var object
27
  */
28
- protected $_view;
29
 
30
  /**
31
  * Plugin version.
32
  *
33
  * @var string
34
  */
35
- protected $_version;
36
 
37
  /**
38
  * WSAL Adverts.
@@ -62,17 +64,15 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
62
  public $user_last_view = '';
63
 
64
  /**
65
- * Method: Constructor
66
- *
67
- * @param WpSecurityAuditLog $plugin - Instance of WpSecurityAuditLog.
68
  */
69
  public function __construct( WpSecurityAuditLog $plugin ) {
70
  parent::__construct( $plugin );
71
  add_action( 'wp_ajax_AjaxInspector', array( $this, 'AjaxInspector' ) );
72
- add_action( 'wp_ajax_AjaxRefresh', array( $this, 'AjaxRefresh' ) );
73
- add_action( 'wp_ajax_AjaxSetIpp', array( $this, 'AjaxSetIpp' ) );
74
- add_action( 'wp_ajax_AjaxSearchSite', array( $this, 'AjaxSearchSite' ) );
75
- add_action( 'wp_ajax_AjaxSwitchDB', array( $this, 'AjaxSwitchDB' ) );
76
  add_action( 'wp_ajax_wsal_download_failed_login_log', array( $this, 'wsal_download_failed_login_log' ) );
77
  add_action( 'wp_ajax_wsal_freemius_opt_in', array( $this, 'wsal_freemius_opt_in' ) );
78
  add_action( 'wp_ajax_wsal_dismiss_setup_modal', array( $this, 'dismiss_setup_modal' ) );
@@ -81,31 +81,31 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
81
  add_action( 'wp_ajax_wsal_dismiss_missing_aws_sdk_nudge', array( $this, 'dismiss_missing_aws_sdk_nudge' ) );
82
  add_action( 'wp_ajax_wsal_dismiss_helper_plugin_needed_nudge', array( $this, 'dismiss_helper_plugin_needed_nudge' ) );
83
  add_action( 'wp_ajax_wsal_dismiss_wp_pointer', array( $this, 'dismiss_wp_pointer' ) );
84
- add_action( 'all_admin_notices', array( $this, 'AdminNotices' ) );
85
  add_action( 'admin_enqueue_scripts', array( $this, 'load_pointers' ), 1000 );
86
  add_filter( 'wsal_pointers_toplevel_page_wsal-auditlog', array( $this, 'register_privacy_pointer' ), 10, 1 );
87
  add_action( 'admin_init', array( $this, 'handle_form_submission' ) );
88
 
89
- if ( $this->_plugin->settings()->is_infinite_scroll() ) {
90
  add_action( 'wp_ajax_wsal_infinite_scroll_events', array( $this, 'infinite_scroll_events' ) );
91
  }
92
 
93
  // Check plugin version for to dismiss the notice only until upgrade.
94
- $this->_version = WSAL_VERSION;
95
 
96
  // Set adverts array.
97
  $this->adverts = array(
98
  0 => array(
99
- 'head' => __( 'Get email notifications about website changes, view logged-in users, do granular log searches, create detailed reports, and more.', 'wp-security-audit-log' ),
100
- 'desc' => __( 'Upgrade to premium today and get more out of your activity logs!', 'wp-security-audit-log' ),
101
  ),
102
  1 => array(
103
- 'head' => __( 'Instant SMS & email alerts, search & filters, reports, users sessions management and much more!', 'wp-security-audit-log' ),
104
- 'desc' => __( 'Upgrade to premium to get more out of your activity logs!', 'wp-security-audit-log' ),
105
  ),
106
  2 => array(
107
- 'head' => __( 'See who logged in on your site in real-time, generate reports, get SMS & email alerts of critical changes and more!', 'wp-security-audit-log' ),
108
- 'desc' => __( 'Unlock these and other powerful features with WP Activity Log Premium.', 'wp-security-audit-log' ),
109
  ),
110
  );
111
 
@@ -122,21 +122,21 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
122
  * 2. DB disconnection notice.
123
  * 3. Freemius opt-in/out notice.
124
  */
125
- public function AdminNotices() {
126
- $is_current_view = $this->_plugin->views->GetActiveView() == $this;
127
 
128
  // Check if any of the extensions is activated.
129
  if (
130
- ! class_exists( 'WSAL_NP_Plugin' )
131
- && ! class_exists( 'WSAL_Ext_Plugin' )
132
- && ! class_exists( 'WSAL_Rep_Plugin' )
133
- && ! class_exists( 'WSAL_SearchExtension' )
134
- && ! class_exists( 'WSAL_UserSessions_Plugin' )
135
- && 'anonymous' !== $this->_plugin->GetGlobalSetting( 'freemius_state', 'anonymous' ) // Anonymous mode option.
136
  ) {
137
- $get_transient_fn = $this->_plugin->IsMultisite() ? 'get_site_transient' : 'get_transient'; // Check for multisite.
138
  $wsal_is_advert_dismissed = $get_transient_fn( 'wsal-is-advert-dismissed' ); // Check if advert has been dismissed.
139
- $wsal_premium_advert = $this->_plugin->GetGlobalSetting( 'premium-advert', false ); // Get the advert to display.
140
  $wsal_premium_advert = false !== $wsal_premium_advert ? (int) $wsal_premium_advert : 0; // Set the default.
141
 
142
  $more_info = add_query_arg(
@@ -199,13 +199,13 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
199
 
200
 
201
  // Check anonymous mode.
202
- if ( 'anonymous' === $this->_plugin->GetGlobalSetting( 'freemius_state', 'anonymous' ) ) { // If user manually opt-out then don't show the notice.
203
  if (
204
- wsal_freemius()->is_anonymous() // Anonymous mode option.
205
- && wsal_freemius()->is_not_paying() // Not paying customer.
206
- && wsal_freemius()->has_api_connectivity() // Check API connectivity.
207
- && $is_current_view
208
- && $this->_plugin->settings()->CurrentUserCan( 'edit' ) // Have permission to edit plugin settings.
209
  ) {
210
  if ( ! is_multisite() || ( is_multisite() && is_network_admin() ) ) :
211
  ?>
@@ -227,16 +227,16 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
227
  $screen = get_current_screen();
228
 
229
 
230
- if (class_exists('WSAL_Upgrade_MetadataMigration')) {
231
- WSAL_Upgrade_MetadataMigration::maybe_display_progress_admin_notice();
232
- }
233
 
234
- if ( $is_current_view && in_array( $screen->base, array( 'toplevel_page_wsal-auditlog', 'toplevel_page_wsal-auditlog-network' ) ) ) {
235
  // Grab list of installed plugins.
236
  $all_plugins = get_plugins();
237
  $plugin_filenames = array();
238
  foreach ( $all_plugins as $plugin => $info ) {
239
- $plugin_info = pathinfo( $plugin );
240
  $plugin_filenames[] = $plugin_info['filename'];
241
  }
242
 
@@ -244,26 +244,26 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
244
  $predefined_plugins = WSAL_PluginInstallAndActivate::get_installable_plugins();
245
  $predefined_plugins_check = array_column( $predefined_plugins, 'addon_for' );
246
 
247
- // Loop through plugins and create an array of slugs, we will compare these agains the plugins we have addons for.
248
  $we_have_addon = array_intersect( $plugin_filenames, $predefined_plugins_check );
249
 
250
  if ( isset( $we_have_addon ) && is_array( $we_have_addon ) ) {
251
 
252
  foreach ( $we_have_addon as $addon ) {
253
- $addon_slug = array_search( $addon, array_column( $predefined_plugins, 'addon_for', 'plugin_slug' ) );
254
  $is_addon_installed = WpSecurityAuditLog::is_plugin_active( $addon_slug );
255
  if ( $is_addon_installed ) {
256
  continue;
257
  }
258
 
259
- $is_dismissed = $this->_plugin->GetGlobalSetting( $addon . '_addon_available_notice_dismissed' );
260
 
261
  if ( ! $is_dismissed ) {
262
-
263
  $image_filename = array_search( $addon, array_column( $predefined_plugins, 'addon_for', 'image_filename' ) );
264
  $title = array_search( $addon, array_column( $predefined_plugins, 'addon_for', 'title' ) );
265
  $plugin_description = array_search( $addon, array_column( $predefined_plugins, 'addon_for', 'plugin_description' ) );
266
-
267
  ?>
268
  <div class="notice notice-information is-dismissible notice-addon-available" id="wsal-notice-addon-available-<?php echo esc_attr( $addon ); ?>" data-addon="<?php echo esc_attr( $addon ); ?>">
269
  <div class="addon-logo-wrapper">
@@ -278,7 +278,7 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
278
  esc_html__( 'installed.', 'wp-security-audit-log' ),
279
  esc_html( $plugin_description ),
280
  esc_html__( 'Install extension', 'wp-security-audit-log' ),
281
- $this->get_third_party_plugins_tab_url()
282
  );
283
  ?>
284
  <?php wp_nonce_field( 'wsal_dismiss_notice_addon_available_' . $addon, 'wsal-dismiss-notice-addon-available-' . $addon, false, true ); ?>
@@ -303,8 +303,8 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
303
  $post_array = filter_input_array( INPUT_POST, $post_array_args );
304
 
305
  // Verify nonce.
306
- if ( wp_verify_nonce( $post_array['nonce'], 'wsal_dismiss_notice_addon_available_'. $post_array['addon'] ) ) {
307
- $this->_plugin->SetGlobalSetting( $post_array['addon'] . '_addon_available_notice_dismissed', true );
308
  die();
309
  }
310
  die( 'Nonce verification failed!' );
@@ -312,64 +312,62 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
312
 
313
 
314
  /**
315
- * Method: Check if view has shortcut link.
316
  */
317
- public function HasPluginShortcutLink() {
318
  return true;
319
  }
320
 
321
  /**
322
- * Method: Get View Title.
323
  */
324
- public function GetTitle() {
325
- return __( 'Activity Log Viewer', 'wp-security-audit-log' );
326
  }
327
 
328
  /**
329
- * Method: Get View Icon.
330
  */
331
- public function GetIcon() {
332
- return $this->_wpversion < 3.8
333
- ? $this->_plugin->GetBaseUrl() . '/img/logo-main-menu.png'
334
  : $this->get_icon_encoded();
335
  }
336
 
337
  /**
338
- * Returns an encoded SVG strin gfor the menu icon.
339
  *
340
- * @method get_icon_encoded
341
- * @since
342
- * @return [type]
343
  */
344
  private function get_icon_encoded() {
345
  return 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMTEycHgiIGhlaWdodD0iMTEwcHgiIHZpZXdCb3g9IjAgMCAxMTIgMTEwIiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgogICAgPCEtLSBHZW5lcmF0b3I6IHNrZXRjaHRvb2wgNTIuNiAoNjc0OTEpIC0gaHR0cDovL3d3dy5ib2hlbWlhbmNvZGluZy5jb20vc2tldGNoIC0tPgogICAgPHRpdGxlPkE2QUQyNDUyLUZERDItNDIwQS05ODMzLTQ3QkJDOTlBQjEzNzwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggc2tldGNodG9vbC48L2Rlc2M+CiAgICA8ZyBpZD0iV1BTQUwtU2NyZWVucyIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9IkN1c3RvbS1pY29ucyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTEwMjQuMDAwMDAwLCAtNDYxLjAwMDAwMCkiIGZpbGw9IiNGRkZGRkYiIGZpbGwtcnVsZT0ibm9uemVybyI+CiAgICAgICAgICAgIDxnIGlkPSJDdXN0b20tSWNvbnMiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE1MS4wMDAwMDAsIDIyOC4wMDAwMDApIj4KICAgICAgICAgICAgICAgIDxnIGlkPSJMb2dvIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg4MDcuMDAwMDAwLCAyMDQuNjY2NjY3KSI+CiAgICAgICAgICAgICAgICAgICAgPGcgaWQ9IkF0b21zLS8taWNvbnMtLy1jdXN0b20tcmV2ZXJzZWQtYXVkaXQtbG9nIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg1Mi4wMDAwMDAsIDE1LjAwMDAwMCkiPgogICAgICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNzAuMDg0ODc0NSw3OC4zNjU1MDAyIEM3Ny44MDAwOTQyLDc4LjM2NTUwMDIgODQuMDU0OTE2MSw3Mi4xMTA2NzgxIDg0LjA1NDkxNjEsNjQuMzk0NTE5MiBDODQuMDU0OTE2MSw1Ni4xMTk1NTg2IDc2Ljg3Njg5NzUsNDkuNTk2MTM2IDY4LjU1MzEwMDYsNTAuNTExODE5NSBDNjkuMDMxMTM0Myw1MS45MjE1MDIzIDY5LjMwMjU1MjIsNTMuNDI2MDQwNiA2OS4zMDI1NTIyLDU0Ljk5NzI1OTQgQzY5LjMwMjU1MjIsNjIuMTk1MDAwNyA2My44NTcyODgzLDY4LjExNzM1OTMgNTYuODYyNDA2Myw2OC44Nzk5NTkyIEM1OC43MzMyMTc5LDc0LjM5Mjg0MjkgNjMuOTM5OTM0Niw3OC4zNjU1MDAyIDcwLjA4NDg3NDUsNzguMzY1NTAwMiBaIE03MC4wNDA3MzIyLDI1LjU3NzA1NTcgTDEwOC4yNzMwOTUsMjkuNjk5MDM5OCBDMTI0LjgyOTU5LDYzLjc3MDkxNTUgMTA2LjA0NTQwMiwxMDIuODE5NDEzIDY5Ljk4ODEzOTEsMTExLjUyNDUxIEM2OS41NDEwOTc4LDExMS40MTU1NjcgNjkuMTE5NDEzOCwxMTEuMjgzMTQ1IDY4LjY3ODAwNzUsMTExLjE2NzYyOCBMNjguNjc2MTI5Miw5My44NzIwMTIyIEM2OC42NzIzNzI1LDkzLjg3MjAxMjIgNjguNjY5NTU1LDkzLjg3MjAxMjIgNjguNjY1Nzk4NCw5My44NzIwMTIyIEM1My4wNzQ3NjI5LDkzLjEyOTEzNDYgNDAuNjE4NjUxNiw4MC4yMTE4OTM5IDQwLjYxODY1MTYsNjQuNDM4NjYgQzQwLjYxODY1MTYsNTQuOTA4MDM5MSA0Ny41ODI1NDEsMzYuMDA5MjcyNSA2OC42NjU3OTg0LDM1LjAwNjI0NyBDNjguNjY5NTU1LDM1LjAwNjI0NyA2OC42NzIzNzI1LDM1LjAwNTMwNzggNjguNjc2MTI5MiwzNS4wMDUzMDc4IEw2OC42ODE3NjQxLDI1LjcyOTIgQzY5LjczMTc0NzcsMjUuNjEwODY1NSA2OS44NTc1OTU1LDI1LjU5NDg5OTggNzAuMDQwNzMyMiwyNS41NzcwNTU3IFogTTExNC40MjkxMTksODEuNTc0NjE1NCBDMTIyLjYxMjA0MSw2My43NjgwOTU4IDEyMi4wNzAxNDUsNDMuMDc0NTkwOCAxMTIuOTg4NDQ0LDI0LjU2NjUxNjggTDcwLjAwMDE2MTEsMTkuODI2NTY0IEwyNy4wMTA5MzkyLDI0LjU2NjUxNjggQzE3LjkyOTIzODQsNDMuMDczNjUxNiAxNy4zODczNDE2LDYzLjc2NzE1NjYgMjUuNTcxMjAzMiw4MS41NzQ2MTU0IEMzMy43ODIzMDA1LDk5LjQ0MjE4MDcgNDkuOTUwOTIxMiwxMTIuNDc0OTM4IDcwLjAwMDE2MTEsMTE3LjQxNzc1IEM5MC4wNDk0MDEsMTEyLjQ3NDkzOCAxMDYuMjE4MDIyLDk5LjQ0MzExOTggMTE0LjQyOTExOSw4MS41NzQ2MTU0IFogTTExNy40NDEwMTQsMjAuNTMwOTM1NyBDMTI4LjAwNzUzLDQwLjk4MDI1OTIgMTI4LjgyODM1OCw2NC4xMTA4OTE0IDExOS42OTIxODYsODMuOTkyOTYwNyBDMTEwLjYzOTU5OSwxMDMuNjkwMDE1IDkyLjc3MTA5NDIsMTE3Ljk4NTk0NiA3MC42NjY5NjY3LDEyMy4yMTUyMDMgTDcwLjAwMDE2MTQsMTIzLjM3MjA0MyBMNjkuMzMzMzU2LDEyMy4yMTUyMDMgQzQ3LjIyOTIyODUsMTE3Ljk4NTk0NiAyOS4zNTk3ODQ1LDEwMy42OTAwMTUgMjAuMzA4MTM2OCw4My45OTI5NjA3IEMxMS4xNzE5NjQ1LDY0LjExMDg5MTQgMTEuOTkxODUzMyw0MC45NzkzMiAyMi41NTkzMDkyLDIwLjUzMDkzNTcgTDIzLjI3MjEzMzUsMTkuMTUyMjQ1MyBMNzAuMDAwMTYxNCwxNCBMMTE2LjcyODE4OSwxOS4xNTIyNDUzIEwxMTcuNDQxMDE0LDIwLjUzMDkzNTcgWiIgaWQ9ImN1c3RvbS1yZXZlcnNlZC1hdWRpdC1sb2ciPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8L2c+CiAgICAgICAgICAgICAgICA8L2c+CiAgICAgICAgICAgIDwvZz4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg==';
346
  }
347
 
348
  /**
349
- * Method: Get View Name.
350
  */
351
- public function GetName() {
352
- return __( 'Log Viewer', 'wp-security-audit-log' );
353
  }
354
 
355
  /**
356
- * Method: Get View Weight.
357
  */
358
- public function GetWeight() {
359
  return 1;
360
  }
361
 
362
  /**
363
  * Method: Get View.
364
  */
365
- protected function GetView() {
366
  // Set page arguments.
367
  if ( ! $this->page_args ) {
368
  $this->page_args = new stdClass();
369
 
370
  // @codingStandardsIgnoreStart
371
  $this->page_args->page = isset( $_REQUEST['page'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ) : false;
372
- $this->page_args->site_id = $this->_plugin->settings()->get_view_site_id();
373
 
374
  // Order arguments.
375
  $this->page_args->order_by = isset( $_REQUEST['orderby'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['orderby'] ) ) : false;
@@ -382,16 +380,16 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
382
  }
383
 
384
  // Set events listing view class.
385
- if ( is_null( $this->_view ) ) {
386
  // Set the requested view based on POST or GET value. We only care
387
  // if the view is 'grid' specifically.
388
  $requested_view = $this->detect_view_type();
389
 
390
  // If 'grid' is requested use it otherwise use list view by default.
391
  if ( 'grid' !== $requested_view ) {
392
- $this->_view = new WSAL_AuditLogListView( $this->_plugin, $this, $this->page_args );
393
  } else {
394
- $this->_view = new WSAL_AuditLogGridView( $this->_plugin, $this, $this->page_args );
395
  }
396
 
397
  // if the requested view didn't match the view users last viewed
@@ -401,7 +399,7 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
401
  $this->user_last_view = $requested_view;
402
  }
403
  }
404
- return $this->_view;
405
  }
406
 
407
  /**
@@ -424,6 +422,9 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
424
  * @method detect_view_type
425
  * @since 4.0.0
426
  * @return string
 
 
 
427
  */
428
  public function detect_view_type() {
429
  // First check if there is a GET/POST request for a specific view.
@@ -466,12 +467,10 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
466
  check_admin_referer( 'bulk-logs' );
467
  }
468
 
469
- // @codingStandardsIgnoreStart
470
- $wpnonce = isset( $_GET['_wpnonce'] ) ? sanitize_text_field( $_GET['_wpnonce'] ) : false; // View nonce.
471
- $search = isset( $_GET['s'] ) ? sanitize_text_field( $_GET['s'] ) : false; // Search.
472
- $site_id = isset( $_GET['wsal-cbid'] ) ? (int) sanitize_text_field( $_GET['wsal-cbid'] ) : false; // Site id.
473
- $search_save = ( isset( $_REQUEST['wsal-save-search-name'] ) && ! empty( $_REQUEST['wsal-save-search-name'] ) ) ? trim( sanitize_text_field( $_REQUEST['wsal-save-search-name'] ) ) : false;
474
- // @codingStandardsIgnoreEnd
475
 
476
  if ( ! empty( $wpnonce ) ) {
477
  // Remove args array.
@@ -504,8 +503,8 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
504
  *
505
  * @since 1.0.0
506
  */
507
- public function Render() {
508
- if ( ! $this->_plugin->settings()->CurrentUserCan( 'view' ) ) {
509
  wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'wp-security-audit-log' ) );
510
  }
511
 
@@ -514,13 +513,14 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
514
  check_admin_referer( 'bulk-logs' );
515
  }
516
 
517
- $this->GetView()->prepare_items();
 
518
  ?>
519
  <form id="audit-log-viewer" method="get">
520
  <div id="audit-log-viewer-content">
521
  <input type="hidden" name="page" value="<?php echo esc_attr( $this->page_args->page ); ?>" />
522
  <input type="hidden" id="wsal-cbid" name="wsal-cbid" value="<?php echo esc_attr( empty( $this->page_args->site_id ) ? '0' : $this->page_args->site_id ); ?>" />
523
- <input type="hidden" id="view" name="view" value="<?php echo ( isset( $_GET['view'] ) && 'grid' === wp_unslash( $_GET['view'] ) ) ? 'grid' : 'list'; ?>" />
524
  <?php
525
  /**
526
  * Hook: `wsal_auditlog_before_view`
@@ -529,10 +529,10 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
529
  *
530
  * @param WSAL_AuditLogListView $this->_view - Audit log view object.
531
  */
532
- do_action( 'wsal_auditlog_before_view', $this->GetView() );
533
 
534
  // Display the audit log list.
535
- $this->GetView()->display();
536
 
537
  /**
538
  * Hook: `wsal_auditlog_after_view`
@@ -541,16 +541,16 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
541
  *
542
  * @param WSAL_AuditLogListView $this->_view - Audit log view object.
543
  */
544
- do_action( 'wsal_auditlog_after_view', $this->GetView() );
545
  ?>
546
  </div>
547
  </form>
548
 
549
  <?php
550
  if (
551
- $this->_plugin->settings()->CurrentUserCan( 'edit' )
552
- && ! $this->_plugin->GetGlobalBooleanSetting( 'setup-complete', false )
553
- && ! $this->_plugin->GetGlobalBooleanSetting( 'setup-modal-dismissed', false )
554
  ) :
555
  ?>
556
  <div data-remodal-id="wsal-setup-modal">
@@ -572,7 +572,7 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
572
  });
573
 
574
  jQuery(document).on('closed', wsal_setup_modal, function () {
575
- wsal_dismiss_setup_modal();
576
  });
577
  });
578
  </script>
@@ -594,8 +594,8 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
594
  'searchnone' => __( 'No Results', 'wp-security-audit-log' ),
595
  ),
596
  'autorefresh' => array(
597
- 'enabled' => ! $is_search_view ? $this->_plugin->settings()->IsRefreshAlertsEnabled() : false,
598
- 'token' => $this->_plugin->settings()->is_infinite_scroll() ? $this->get_total_events() : $this->GetView()->get_total_items(),
599
  ),
600
  )
601
  );
@@ -610,7 +610,7 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
610
  * Ajax callback to display meta data inspector.
611
  */
612
  public function AjaxInspector() {
613
- if ( ! $this->_plugin->settings()->CurrentUserCan( 'view' ) ) {
614
  die( 'Access Denied.' );
615
  }
616
 
@@ -623,13 +623,13 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
623
 
624
 
625
  $occ = new WSAL_Models_Occurrence();
626
- $occ->Load( 'id = %d', array( (int) $get_array['occurrence'] ) );
627
- $alert_meta = $occ->GetMetaArray();
628
  unset( $alert_meta['ReportText'] );
629
 
630
  // Set WSAL_Ref class scripts and styles.
631
- WSAL_Ref::config( 'stylePath', esc_url( $this->_plugin->GetBaseDir() ) . '/css/wsal-ref.css' );
632
- WSAL_Ref::config( 'scriptPath', esc_url( $this->_plugin->GetBaseDir() ) . '/js/wsal-ref.js' );
633
 
634
  echo '<!DOCTYPE html><html><head>';
635
  echo '<style type="text/css">';
@@ -644,8 +644,8 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
644
  /**
645
  * Ajax callback to refresh the view.
646
  */
647
- public function AjaxRefresh() {
648
- if ( ! $this->_plugin->settings()->CurrentUserCan( 'view' ) ) {
649
  die( 'Access Denied.' );
650
  }
651
 
@@ -663,10 +663,10 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
663
 
664
  // Check for new total number of alerts.
665
  $occ = new WSAL_Models_Occurrence();
666
- $new = (int) $occ->Count();
667
 
668
- // If the count is changed, then return the new count.
669
- echo $old === $new ? 'false' : esc_html( $new );
670
  die;
671
  }
672
 
@@ -674,8 +674,8 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
674
  * Ajax callback to set number of alerts to
675
  * show on a single page.
676
  */
677
- public function AjaxSetIpp() {
678
- if ( ! $this->_plugin->settings()->CurrentUserCan( 'view' ) ) {
679
  die( 'Access Denied.' );
680
  }
681
 
@@ -685,15 +685,15 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
685
  if ( ! isset( $post_array['count'] ) ) {
686
  die( 'Count parameter expected.' );
687
  }
688
- $this->_plugin->settings()->SetViewPerPage( (int) $post_array['count'] );
689
  die;
690
  }
691
 
692
  /**
693
  * Ajax callback to search.
694
  */
695
- public function AjaxSearchSite() {
696
- if ( ! $this->_plugin->settings()->CurrentUserCan( 'view' ) ) {
697
  die( 'Access Denied.' );
698
  }
699
 
@@ -708,14 +708,14 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
708
 
709
  $search = $post_array['search'];
710
 
711
- foreach ( $this->GetView()->get_sites() as $site ) {
712
  if ( stripos( $site->blogname, $search ) !== false ) {
713
  $grp1[] = $site;
714
  } elseif ( stripos( $site->domain, $search ) !== false ) {
715
  $grp2[] = $site;
716
  }
717
  }
718
- die( json_encode( array_slice( $grp1 + $grp2, 0, 7 ) ) );
719
  }
720
 
721
 
@@ -732,32 +732,32 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
732
  die();
733
  }
734
 
735
- // Get alert by id.
736
- $alert_id = filter_input( INPUT_POST, 'alert_id', FILTER_SANITIZE_NUMBER_INT );
737
- $alert = new WSAL_Models_Occurrence();
738
- $alert->id = (int) $alert_id;
739
 
740
- // Get users using alert meta.
741
- $users = $alert->GetMetaValue( 'Users', array() );
742
 
743
- // Check if there are any users.
744
- if ( ! empty( $users ) && is_array( $users ) ) {
745
- // Prepare content.
746
- $content = implode( ',', $users );
747
- echo esc_html( $content );
748
- } else {
749
- echo esc_html__( 'No users found.', 'wp-security-audit-log' );
750
- }
751
 
752
  die();
753
  }
754
 
755
  /**
756
- * Ajax callback to handle freemius opt in/out.
757
  */
758
  public function wsal_freemius_opt_in() {
759
  // Die if not have access.
760
- if ( ! $this->_plugin->settings()->CurrentUserCan( 'edit' ) ) {
761
  die( 'Access Denied.' );
762
  }
763
 
@@ -795,8 +795,8 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
795
  wsal_freemius()->opt_in( false, false, false, false, false, false, false, false, $sites_data );
796
  }
797
 
798
- // Update freemius state.
799
- $this->_plugin->SetGlobalSetting( 'freemius_state', 'in', true );
800
  } elseif ( 'no' === $choice ) {
801
  if ( ! is_multisite() ) {
802
  wsal_freemius()->skip_connection(); // Opt out.
@@ -804,8 +804,8 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
804
  wsal_freemius()->skip_connection( null, true ); // Opt out for all websites.
805
  }
806
 
807
- // Update freemius state.
808
- $this->_plugin->SetGlobalSetting( 'freemius_state', 'skipped', true );
809
  }
810
 
811
  echo wp_json_encode(
@@ -828,48 +828,48 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
828
  /**
829
  * Method: Render header of the view.
830
  */
831
- public function Header() {
832
  add_thickbox();
833
 
834
  // Darktooltip styles.
835
  wp_enqueue_style(
836
  'darktooltip',
837
- $this->_plugin->GetBaseUrl() . '/css/darktooltip.css',
838
  array(),
839
  '0.4.0'
840
  );
841
 
842
  // Remodal styles.
843
- wp_enqueue_style( 'wsal-remodal', $this->_plugin->GetBaseUrl() . '/css/remodal.css', array(), '1.1.1' );
844
- wp_enqueue_style( 'wsal-remodal-theme', $this->_plugin->GetBaseUrl() . '/css/remodal-default-theme.css', array(), '1.1.1.1' );
845
 
846
  // Audit log styles.
847
  wp_enqueue_style(
848
  'auditlog',
849
- $this->_plugin->GetBaseUrl() . '/css/auditlog.css',
850
  array(),
851
- filemtime( $this->_plugin->GetBaseDir() . '/css/auditlog.css' )
852
  );
853
 
854
- // admin notices styles
855
  wp_enqueue_style(
856
  'wsal_admin_notices',
857
- $this->_plugin->GetBaseUrl() . '/css/admin-notices.css',
858
  array(),
859
- filemtime( $this->_plugin->GetBaseDir() . '/css/admin-notices.css' )
860
  );
861
  }
862
 
863
  /**
864
- * Method: Render footer of the view.
865
  */
866
- public function Footer() {
867
  wp_enqueue_script( 'jquery' );
868
 
869
  // Darktooltip js.
870
  wp_enqueue_script(
871
  'darktooltip', // Identifier.
872
- $this->_plugin->GetBaseUrl() . '/js/jquery.darktooltip.js', // Script location.
873
  array( 'jquery' ), // Depends on jQuery.
874
  '0.4.0', // Script version.
875
  true
@@ -878,7 +878,7 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
878
  // Remodal script.
879
  wp_enqueue_script(
880
  'wsal-remodal-js',
881
- $this->_plugin->GetBaseUrl() . '/js/remodal.min.js',
882
  array(),
883
  '1.1.1',
884
  true
@@ -890,11 +890,12 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
890
  // Audit log script.
891
  wp_register_script(
892
  'auditlog',
893
- $this->_plugin->GetBaseUrl() . '/js/auditlog.js',
894
  array(),
895
- filemtime( $this->_plugin->GetBaseDir() . '/js/auditlog.js' ),
896
  true
897
  );
 
898
  $audit_log_data = array(
899
  'page' => isset( $this->page_args->page ) ? $this->page_args->page : false,
900
  'siteId' => isset( $this->page_args->site_id ) ? $this->page_args->site_id : false,
@@ -903,15 +904,15 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
903
  'searchTerm' => isset( $this->page_args->search_term ) ? $this->page_args->search_term : false,
904
  'searchFilters' => isset( $this->page_args->search_filters ) ? $this->page_args->search_filters : false,
905
  'viewerNonce' => wp_create_nonce( 'wsal_auditlog_viewer_nonce' ),
906
- 'infiniteScroll' => $this->_plugin->settings()->is_infinite_scroll(),
907
  'userView' => ( in_array( $this->user_last_view, $this->supported_view_types(), true ) ) ? $this->user_last_view : 'list',
908
  'installAddonStrings' => array(
909
- 'defaultButton' => esc_html( 'Install and activate extension', 'wp-security-audit-log' ),
910
- 'installingText' => esc_html( 'Installing extension', 'wp-security-audit-log' ),
911
- 'otherInstalling' => esc_html( 'Other extension installing', 'wp-security-audit-log' ),
912
- 'addonInstalled' => esc_html( 'Installed', 'wp-security-audit-log' ),
913
- 'installedReload' => esc_html( 'Installed... reloading page', 'wp-security-audit-log' ),
914
- 'buttonError' => esc_html( 'Problem enabling', 'wp-security-audit-log' ),
915
  'msgError' => sprintf(
916
  /* translators: 1 - an opening link tag, 2 - the closing tag. */
917
  __( '<br>An error occurred when trying to install and activate the plugin. Please try install it again from the %1$sevent settings%2$s page.', 'wp-security-audit-log' ),
@@ -938,8 +939,8 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
938
 
939
  // Don't display notice if the wizard notice is showing.
940
  if (
941
- ! $this->_plugin->GetGlobalBooleanSetting( 'setup-complete', false )
942
- && ! $this->_plugin->GetGlobalBooleanSetting( 'setup-modal-dismissed', false )
943
  ) {
944
  return;
945
  }
@@ -956,14 +957,14 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
956
  }
957
 
958
  // Get dismissed pointers.
959
- $dismissed = explode( ',', (string) $this->_plugin->GetGlobalSetting( 'dismissed-privacy-notice', true ) );
960
  $valid_pointers = array();
961
 
962
  // Check pointers and remove dismissed ones.
963
  foreach ( $pointers as $pointer_id => $pointer ) {
964
  // Sanity check.
965
  if (
966
- in_array( $pointer_id, $dismissed )
967
  || empty( $pointer )
968
  || empty( $pointer_id )
969
  || empty( $pointer['target'] )
@@ -988,9 +989,9 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
988
  // Add pointers script to queue. Add custom script.
989
  wp_enqueue_script(
990
  'auditlog-pointer',
991
- $this->_plugin->GetBaseUrl() . '/js/auditlog-pointer.js',
992
  array( 'wp-pointer' ),
993
- filemtime( $this->_plugin->GetBaseDir() . '/js/auditlog-pointer.js' ),
994
  true
995
  );
996
 
@@ -1006,16 +1007,16 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
1006
  * @since 3.2
1007
  */
1008
  public function register_privacy_pointer( $pointer ) {
1009
- $is_current_view = $this->_plugin->views->GetActiveView() == $this;
1010
  if ( current_user_can( 'manage_options' ) && $is_current_view && ! isset( $pointer['wsal_privacy'] ) ) {
1011
  $pointer['wsal_privacy'] = array(
1012
  'target' => '#toplevel_page_wsal-auditlog .wp-first-item',
1013
  'options' => array(
1014
  'content' => sprintf(
1015
  '<h3> %s </h3> <p> %s </p> <p><strong>%s</strong></p>',
1016
- __( 'WordPress Activity Log', 'wp-security-audit-log' ),
1017
- __( 'When a user makes a change on your website the plugin will keep a record of that event here. Right now there is nothing because this is a new install.', 'wp-security-audit-log' ),
1018
- __( 'Thank you for using WP Activity Log', 'wp-security-audit-log' )
1019
  ),
1020
  'position' => array(
1021
  'edge' => 'left',
@@ -1034,7 +1035,7 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
1034
  */
1035
  public function wsal_dismiss_advert() {
1036
  // Die if user does not have permission to dismiss.
1037
- if ( ! $this->_plugin->settings()->CurrentUserCan( 'edit' ) ) {
1038
  echo wp_json_encode(
1039
  array(
1040
  'success' => false,
@@ -1060,8 +1061,8 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
1060
  // @codingStandardsIgnoreEnd
1061
 
1062
  $advert = 2 === $advert ? '0' : $advert + 1;
1063
- $this->_plugin->SetGlobalSetting( 'premium-advert', $advert );
1064
- $set_transient_fn = $this->_plugin->IsMultisite() ? 'set_site_transient' : 'set_transient';
1065
  $set_transient_fn( 'wsal-is-advert-dismissed', true, MONTH_IN_SECONDS );
1066
  echo wp_json_encode(
1067
  array(
@@ -1081,31 +1082,31 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
1081
  $pointer = sanitize_text_field( wp_unslash( $_POST['pointer'] ) );
1082
  // @codingStandardsIgnoreEnd
1083
 
1084
- if ( $pointer != sanitize_key( $pointer ) ) {
1085
  wp_die( 0 );
1086
  }
1087
 
1088
- $dismissed = array_filter( explode( ',', (string) $this->_plugin->GetGlobalSetting( 'dismissed-privacy-notice', true ) ) );
1089
 
1090
- if ( in_array( $pointer, $dismissed ) ) {
1091
  wp_die( 0 );
1092
  }
1093
 
1094
  $dismissed[] = $pointer;
1095
  $dismissed = implode( ',', $dismissed );
1096
 
1097
- $this->_plugin->SetGlobalSetting( 'dismissed-privacy-notice', $dismissed );
1098
  wp_die( 1 );
1099
  }
1100
 
1101
  /**
1102
- * Infinite Scroll Events AJAX Hanlder.
1103
  *
1104
  * @since 3.3.1.1
1105
  */
1106
  public function infinite_scroll_events() {
1107
  // Check user permissions.
1108
- if ( ! $this->_plugin->settings()->CurrentUserCan( 'view' ) ) {
1109
  die( esc_html__( 'Access Denied', 'wp-security-audit-log' ) );
1110
  }
1111
 
@@ -1114,17 +1115,17 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
1114
  die( esc_html__( 'Nonce verification failed.', 'wp-security-audit-log' ) );
1115
  }
1116
 
1117
- // Get $_POST arguments.
1118
- $paged = isset( $_POST['page_number'] ) ? sanitize_text_field( wp_unslash( $_POST['page_number'] ) ) : 0;
1119
-
1120
- // Query events.
1121
- $events_query = $this->GetView()->query_events( $paged );
1122
- if ( ! empty( $events_query['items'] ) ) {
1123
- foreach ( $events_query['items'] as $event ) {
1124
- $this->GetView()->single_row( $event );
1125
- }
1126
- }
1127
- exit();
1128
  }
1129
 
1130
  /**
@@ -1134,7 +1135,7 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
1134
  */
1135
  public function get_total_events() {
1136
  $occ = new WSAL_Models_Occurrence();
1137
- return (int) $occ->Count();
1138
  }
1139
 
1140
  /**
@@ -1144,7 +1145,7 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
1144
  */
1145
  public function dismiss_setup_modal() {
1146
  // Die if user does not have permission to dismiss.
1147
- if ( ! $this->_plugin->settings()->CurrentUserCan( 'edit' ) ) {
1148
  echo wp_json_encode(
1149
  array(
1150
  'success' => false,
@@ -1155,9 +1156,7 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
1155
  }
1156
 
1157
  // Filter $_POST array for security.
1158
- // @codingStandardsIgnoreStart
1159
- $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : false;
1160
- // @codingStandardsIgnoreEnd
1161
 
1162
  if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'wsal_dismiss_setup_modal' ) ) {
1163
  // Nonce verification failed.
@@ -1170,18 +1169,20 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
1170
  die();
1171
  }
1172
 
1173
- $this->_plugin->SetGlobalBooleanSetting( 'setup-modal-dismissed', true, true );
1174
  wp_send_json_success();
1175
  }
1176
 
1177
 
1178
  /**
 
 
1179
  * @return string URL of the 3rd party extensions tab.
1180
- * @since 4.3.2
1181
  */
1182
- public function get_third_party_plugins_tab_url() {
1183
- return esc_url( add_query_arg( 'page', 'wsal-togglealerts#tab-third-party-plugins', network_admin_url( 'admin.php' ) ) );
1184
- }
1185
 
1186
  /**
1187
  * Builds HTML markup to display 3rd party extension teaser if there is a post type in the event meta data and the
@@ -1208,17 +1209,17 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
1208
  return $result;
1209
  }
1210
 
1211
- $result .= '<div class="extension-ad" style="border-color: transparent transparent ' . $extension->get_color() . ' transparent;">';
1212
- $result .= '</div>';
1213
  $plugin_name = $extension->get_plugin_name();
1214
  $link_title = sprintf(
1215
- esc_html__( 'Install the activity log extension for %1$s for more detailed logging of changes done in %2$s.', 'wp-security-audit-log' ),
1216
  $plugin_name,
1217
  $plugin_name
1218
  );
1219
- $result .= '<a class="icon" title="' . $link_title . '" href="' . $this->get_third_party_plugins_tab_url() . '">';
1220
- $result .= '<img src="' . $extension->get_plugin_icon_url() . '" />';
1221
- $result .= '</div>';
1222
 
1223
  return $result;
1224
  }
4
  *
5
  * Class file for Audit Log View.
6
  *
7
+ * @since 1.0.0
8
+ * @package wsal
9
+ * @subpackage views
10
  */
11
 
12
  // Exit if accessed directly.
17
  /**
18
  * Audit Log Viewer Page
19
  *
20
+ * @package wsal
21
+ * @subpackage views
22
  */
23
  class WSAL_Views_AuditLog extends WSAL_AbstractView {
24
 
25
  /**
26
  * Listing view object (Instance of WSAL_AuditLogListView).
27
  *
28
+ * @var WSAL_AuditLogListView
29
  */
30
+ protected $view;
31
 
32
  /**
33
  * Plugin version.
34
  *
35
  * @var string
36
  */
37
+ protected $version;
38
 
39
  /**
40
  * WSAL Adverts.
64
  public $user_last_view = '';
65
 
66
  /**
67
+ * {@inheritDoc}
 
 
68
  */
69
  public function __construct( WpSecurityAuditLog $plugin ) {
70
  parent::__construct( $plugin );
71
  add_action( 'wp_ajax_AjaxInspector', array( $this, 'AjaxInspector' ) );
72
+ add_action( 'wp_ajax_AjaxRefresh', array( $this, 'ajax_refresh' ) );
73
+ add_action( 'wp_ajax_AjaxSetIpp', array( $this, 'ajax_set_items_per_page' ) );
74
+ add_action( 'wp_ajax_AjaxSearchSite', array( $this, 'ajax_search_site' ) );
75
+ add_action( 'wp_ajax_AjaxSwitchDB', array( $this, 'ajax_switch_db' ) );
76
  add_action( 'wp_ajax_wsal_download_failed_login_log', array( $this, 'wsal_download_failed_login_log' ) );
77
  add_action( 'wp_ajax_wsal_freemius_opt_in', array( $this, 'wsal_freemius_opt_in' ) );
78
  add_action( 'wp_ajax_wsal_dismiss_setup_modal', array( $this, 'dismiss_setup_modal' ) );
81
  add_action( 'wp_ajax_wsal_dismiss_missing_aws_sdk_nudge', array( $this, 'dismiss_missing_aws_sdk_nudge' ) );
82
  add_action( 'wp_ajax_wsal_dismiss_helper_plugin_needed_nudge', array( $this, 'dismiss_helper_plugin_needed_nudge' ) );
83
  add_action( 'wp_ajax_wsal_dismiss_wp_pointer', array( $this, 'dismiss_wp_pointer' ) );
84
+ add_action( 'all_admin_notices', array( $this, 'admin_notices' ) );
85
  add_action( 'admin_enqueue_scripts', array( $this, 'load_pointers' ), 1000 );
86
  add_filter( 'wsal_pointers_toplevel_page_wsal-auditlog', array( $this, 'register_privacy_pointer' ), 10, 1 );
87
  add_action( 'admin_init', array( $this, 'handle_form_submission' ) );
88
 
89
+ if ( $this->plugin->settings()->is_infinite_scroll() ) {
90
  add_action( 'wp_ajax_wsal_infinite_scroll_events', array( $this, 'infinite_scroll_events' ) );
91
  }
92
 
93
  // Check plugin version for to dismiss the notice only until upgrade.
94
+ $this->version = WSAL_VERSION;
95
 
96
  // Set adverts array.
97
  $this->adverts = array(
98
  0 => array(
99
+ 'head' => esc_html__( 'Get email notifications about website changes, view logged-in users, do granular log searches, create detailed reports, and more.', 'wp-security-audit-log' ),
100
+ 'desc' => esc_html__( 'Upgrade to premium today and get more out of your activity logs!', 'wp-security-audit-log' ),
101
  ),
102
  1 => array(
103
+ 'head' => esc_html__( 'Instant SMS & email alerts, search & filters, reports, users sessions management and much more!', 'wp-security-audit-log' ),
104
+ 'desc' => esc_html__( 'Upgrade to premium to get more out of your activity logs!', 'wp-security-audit-log' ),
105
  ),
106
  2 => array(
107
+ 'head' => esc_html__( 'See who logged in on your site in real-time, generate reports, get SMS & email alerts of critical changes and more!', 'wp-security-audit-log' ),
108
+ 'desc' => esc_html__( 'Unlock these and other powerful features with WP Activity Log Premium.', 'wp-security-audit-log' ),
109
  ),
110
  );
111
 
122
  * 2. DB disconnection notice.
123
  * 3. Freemius opt-in/out notice.
124
  */
125
+ public function admin_notices() {
126
+ $is_current_view = $this->plugin->views->get_active_view() == $this; // phpcs:ignore
127
 
128
  // Check if any of the extensions is activated.
129
  if (
130
+ ! class_exists( 'WSAL_NP_Plugin' )
131
+ && ! class_exists( 'WSAL_Ext_Plugin' )
132
+ && ! class_exists( 'WSAL_Rep_Plugin' )
133
+ && ! class_exists( 'WSAL_SearchExtension' )
134
+ && ! class_exists( 'WSAL_UserSessions_Plugin' )
135
+ && 'anonymous' !== $this->plugin->get_global_setting( 'freemius_state', 'anonymous' ) // Anonymous mode option.
136
  ) {
137
+ $get_transient_fn = $this->plugin->is_multisite() ? 'get_site_transient' : 'get_transient'; // Check for multisite.
138
  $wsal_is_advert_dismissed = $get_transient_fn( 'wsal-is-advert-dismissed' ); // Check if advert has been dismissed.
139
+ $wsal_premium_advert = $this->plugin->get_global_setting( 'premium-advert', false ); // Get the advert to display.
140
  $wsal_premium_advert = false !== $wsal_premium_advert ? (int) $wsal_premium_advert : 0; // Set the default.
141
 
142
  $more_info = add_query_arg(
199
 
200
 
201
  // Check anonymous mode.
202
+ if ( 'anonymous' === $this->plugin->get_global_setting( 'freemius_state', 'anonymous' ) ) { // If user manually opt-out then don't show the notice.
203
  if (
204
+ wsal_freemius()->is_anonymous() // Anonymous mode option.
205
+ && wsal_freemius()->is_not_paying() // Not paying customer.
206
+ && wsal_freemius()->has_api_connectivity() // Check API connectivity.
207
+ && $is_current_view
208
+ && $this->plugin->settings()->current_user_can( 'edit' ) // Have permission to edit plugin settings.
209
  ) {
210
  if ( ! is_multisite() || ( is_multisite() && is_network_admin() ) ) :
211
  ?>
227
  $screen = get_current_screen();
228
 
229
 
230
+ if ( class_exists( 'WSAL_Upgrade_MetadataMigration' ) ) {
231
+ WSAL_Upgrade_MetadataMigration::maybe_display_progress_admin_notice();
232
+ }
233
 
234
+ if ( $is_current_view && in_array( $screen->base, array( 'toplevel_page_wsal-auditlog', 'toplevel_page_wsal-auditlog-network' ), true ) ) {
235
  // Grab list of installed plugins.
236
  $all_plugins = get_plugins();
237
  $plugin_filenames = array();
238
  foreach ( $all_plugins as $plugin => $info ) {
239
+ $plugin_info = pathinfo( $plugin );
240
  $plugin_filenames[] = $plugin_info['filename'];
241
  }
242
 
244
  $predefined_plugins = WSAL_PluginInstallAndActivate::get_installable_plugins();
245
  $predefined_plugins_check = array_column( $predefined_plugins, 'addon_for' );
246
 
247
+ // Loop through plugins and create an array of slugs, we will compare these against the plugins we have addons for.
248
  $we_have_addon = array_intersect( $plugin_filenames, $predefined_plugins_check );
249
 
250
  if ( isset( $we_have_addon ) && is_array( $we_have_addon ) ) {
251
 
252
  foreach ( $we_have_addon as $addon ) {
253
+ $addon_slug = array_search( $addon, array_column( $predefined_plugins, 'addon_for', 'plugin_slug' ) ); // phpcs:ignore
254
  $is_addon_installed = WpSecurityAuditLog::is_plugin_active( $addon_slug );
255
  if ( $is_addon_installed ) {
256
  continue;
257
  }
258
 
259
+ $is_dismissed = $this->plugin->get_global_setting( $addon . '_addon_available_notice_dismissed' );
260
 
261
  if ( ! $is_dismissed ) {
262
+ // @codingStandardsIgnoreStart
263
  $image_filename = array_search( $addon, array_column( $predefined_plugins, 'addon_for', 'image_filename' ) );
264
  $title = array_search( $addon, array_column( $predefined_plugins, 'addon_for', 'title' ) );
265
  $plugin_description = array_search( $addon, array_column( $predefined_plugins, 'addon_for', 'plugin_description' ) );
266
+ // @codingStandardsIgnoreEnd
267
  ?>
268
  <div class="notice notice-information is-dismissible notice-addon-available" id="wsal-notice-addon-available-<?php echo esc_attr( $addon ); ?>" data-addon="<?php echo esc_attr( $addon ); ?>">
269
  <div class="addon-logo-wrapper">
278
  esc_html__( 'installed.', 'wp-security-audit-log' ),
279
  esc_html( $plugin_description ),
280
  esc_html__( 'Install extension', 'wp-security-audit-log' ),
281
+ $this->get_third_party_plugins_tab_url() // phpcs:ignore
282
  );
283
  ?>
284
  <?php wp_nonce_field( 'wsal_dismiss_notice_addon_available_' . $addon, 'wsal-dismiss-notice-addon-available-' . $addon, false, true ); ?>
303
  $post_array = filter_input_array( INPUT_POST, $post_array_args );
304
 
305
  // Verify nonce.
306
+ if ( wp_verify_nonce( $post_array['nonce'], 'wsal_dismiss_notice_addon_available_' . $post_array['addon'] ) ) {
307
+ $this->plugin->set_global_setting( $post_array['addon'] . '_addon_available_notice_dismissed', true );
308
  die();
309
  }
310
  die( 'Nonce verification failed!' );
312
 
313
 
314
  /**
315
+ * {@inheritDoc}
316
  */
317
+ public function has_plugin_shortcut_link() {
318
  return true;
319
  }
320
 
321
  /**
322
+ * {@inheritDoc}
323
  */
324
+ public function get_title() {
325
+ return esc_html__( 'Activity Log Viewer', 'wp-security-audit-log' );
326
  }
327
 
328
  /**
329
+ * {@inheritDoc}
330
  */
331
+ public function get_icon() {
332
+ return $this->wp_version < 3.8
333
+ ? $this->plugin->get_base_url() . '/img/logo-main-menu.png'
334
  : $this->get_icon_encoded();
335
  }
336
 
337
  /**
338
+ * Returns an encoded SVG string for the menu icon.
339
  *
340
+ * @return string
 
 
341
  */
342
  private function get_icon_encoded() {
343
  return 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iMTEycHgiIGhlaWdodD0iMTEwcHgiIHZpZXdCb3g9IjAgMCAxMTIgMTEwIiB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPgogICAgPCEtLSBHZW5lcmF0b3I6IHNrZXRjaHRvb2wgNTIuNiAoNjc0OTEpIC0gaHR0cDovL3d3dy5ib2hlbWlhbmNvZGluZy5jb20vc2tldGNoIC0tPgogICAgPHRpdGxlPkE2QUQyNDUyLUZERDItNDIwQS05ODMzLTQ3QkJDOTlBQjEzNzwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggc2tldGNodG9vbC48L2Rlc2M+CiAgICA8ZyBpZD0iV1BTQUwtU2NyZWVucyIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+CiAgICAgICAgPGcgaWQ9IkN1c3RvbS1pY29ucyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTEwMjQuMDAwMDAwLCAtNDYxLjAwMDAwMCkiIGZpbGw9IiNGRkZGRkYiIGZpbGwtcnVsZT0ibm9uemVybyI+CiAgICAgICAgICAgIDxnIGlkPSJDdXN0b20tSWNvbnMiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDE1MS4wMDAwMDAsIDIyOC4wMDAwMDApIj4KICAgICAgICAgICAgICAgIDxnIGlkPSJMb2dvIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg4MDcuMDAwMDAwLCAyMDQuNjY2NjY3KSI+CiAgICAgICAgICAgICAgICAgICAgPGcgaWQ9IkF0b21zLS8taWNvbnMtLy1jdXN0b20tcmV2ZXJzZWQtYXVkaXQtbG9nIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSg1Mi4wMDAwMDAsIDE1LjAwMDAwMCkiPgogICAgICAgICAgICAgICAgICAgICAgICA8cGF0aCBkPSJNNzAuMDg0ODc0NSw3OC4zNjU1MDAyIEM3Ny44MDAwOTQyLDc4LjM2NTUwMDIgODQuMDU0OTE2MSw3Mi4xMTA2NzgxIDg0LjA1NDkxNjEsNjQuMzk0NTE5MiBDODQuMDU0OTE2MSw1Ni4xMTk1NTg2IDc2Ljg3Njg5NzUsNDkuNTk2MTM2IDY4LjU1MzEwMDYsNTAuNTExODE5NSBDNjkuMDMxMTM0Myw1MS45MjE1MDIzIDY5LjMwMjU1MjIsNTMuNDI2MDQwNiA2OS4zMDI1NTIyLDU0Ljk5NzI1OTQgQzY5LjMwMjU1MjIsNjIuMTk1MDAwNyA2My44NTcyODgzLDY4LjExNzM1OTMgNTYuODYyNDA2Myw2OC44Nzk5NTkyIEM1OC43MzMyMTc5LDc0LjM5Mjg0MjkgNjMuOTM5OTM0Niw3OC4zNjU1MDAyIDcwLjA4NDg3NDUsNzguMzY1NTAwMiBaIE03MC4wNDA3MzIyLDI1LjU3NzA1NTcgTDEwOC4yNzMwOTUsMjkuNjk5MDM5OCBDMTI0LjgyOTU5LDYzLjc3MDkxNTUgMTA2LjA0NTQwMiwxMDIuODE5NDEzIDY5Ljk4ODEzOTEsMTExLjUyNDUxIEM2OS41NDEwOTc4LDExMS40MTU1NjcgNjkuMTE5NDEzOCwxMTEuMjgzMTQ1IDY4LjY3ODAwNzUsMTExLjE2NzYyOCBMNjguNjc2MTI5Miw5My44NzIwMTIyIEM2OC42NzIzNzI1LDkzLjg3MjAxMjIgNjguNjY5NTU1LDkzLjg3MjAxMjIgNjguNjY1Nzk4NCw5My44NzIwMTIyIEM1My4wNzQ3NjI5LDkzLjEyOTEzNDYgNDAuNjE4NjUxNiw4MC4yMTE4OTM5IDQwLjYxODY1MTYsNjQuNDM4NjYgQzQwLjYxODY1MTYsNTQuOTA4MDM5MSA0Ny41ODI1NDEsMzYuMDA5MjcyNSA2OC42NjU3OTg0LDM1LjAwNjI0NyBDNjguNjY5NTU1LDM1LjAwNjI0NyA2OC42NzIzNzI1LDM1LjAwNTMwNzggNjguNjc2MTI5MiwzNS4wMDUzMDc4IEw2OC42ODE3NjQxLDI1LjcyOTIgQzY5LjczMTc0NzcsMjUuNjEwODY1NSA2OS44NTc1OTU1LDI1LjU5NDg5OTggNzAuMDQwNzMyMiwyNS41NzcwNTU3IFogTTExNC40MjkxMTksODEuNTc0NjE1NCBDMTIyLjYxMjA0MSw2My43NjgwOTU4IDEyMi4wNzAxNDUsNDMuMDc0NTkwOCAxMTIuOTg4NDQ0LDI0LjU2NjUxNjggTDcwLjAwMDE2MTEsMTkuODI2NTY0IEwyNy4wMTA5MzkyLDI0LjU2NjUxNjggQzE3LjkyOTIzODQsNDMuMDczNjUxNiAxNy4zODczNDE2LDYzLjc2NzE1NjYgMjUuNTcxMjAzMiw4MS41NzQ2MTU0IEMzMy43ODIzMDA1LDk5LjQ0MjE4MDcgNDkuOTUwOTIxMiwxMTIuNDc0OTM4IDcwLjAwMDE2MTEsMTE3LjQxNzc1IEM5MC4wNDk0MDEsMTEyLjQ3NDkzOCAxMDYuMjE4MDIyLDk5LjQ0MzExOTggMTE0LjQyOTExOSw4MS41NzQ2MTU0IFogTTExNy40NDEwMTQsMjAuNTMwOTM1NyBDMTI4LjAwNzUzLDQwLjk4MDI1OTIgMTI4LjgyODM1OCw2NC4xMTA4OTE0IDExOS42OTIxODYsODMuOTkyOTYwNyBDMTEwLjYzOTU5OSwxMDMuNjkwMDE1IDkyLjc3MTA5NDIsMTE3Ljk4NTk0NiA3MC42NjY5NjY3LDEyMy4yMTUyMDMgTDcwLjAwMDE2MTQsMTIzLjM3MjA0MyBMNjkuMzMzMzU2LDEyMy4yMTUyMDMgQzQ3LjIyOTIyODUsMTE3Ljk4NTk0NiAyOS4zNTk3ODQ1LDEwMy42OTAwMTUgMjAuMzA4MTM2OCw4My45OTI5NjA3IEMxMS4xNzE5NjQ1LDY0LjExMDg5MTQgMTEuOTkxODUzMyw0MC45NzkzMiAyMi41NTkzMDkyLDIwLjUzMDkzNTcgTDIzLjI3MjEzMzUsMTkuMTUyMjQ1MyBMNzAuMDAwMTYxNCwxNCBMMTE2LjcyODE4OSwxOS4xNTIyNDUzIEwxMTcuNDQxMDE0LDIwLjUzMDkzNTcgWiIgaWQ9ImN1c3RvbS1yZXZlcnNlZC1hdWRpdC1sb2ciPjwvcGF0aD4KICAgICAgICAgICAgICAgICAgICA8L2c+CiAgICAgICAgICAgICAgICA8L2c+CiAgICAgICAgICAgIDwvZz4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg==';
344
  }
345
 
346
  /**
347
+ * {@inheritDoc}
348
  */
349
+ public function get_name() {
350
+ return esc_html__( 'Log Viewer', 'wp-security-audit-log' );
351
  }
352
 
353
  /**
354
+ * {@inheritDoc}
355
  */
356
+ public function get_weight() {
357
  return 1;
358
  }
359
 
360
  /**
361
  * Method: Get View.
362
  */
363
+ protected function get_view() {
364
  // Set page arguments.
365
  if ( ! $this->page_args ) {
366
  $this->page_args = new stdClass();
367
 
368
  // @codingStandardsIgnoreStart
369
  $this->page_args->page = isset( $_REQUEST['page'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ) : false;
370
+ $this->page_args->site_id = $this->plugin->settings()->get_view_site_id();
371
 
372
  // Order arguments.
373
  $this->page_args->order_by = isset( $_REQUEST['orderby'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['orderby'] ) ) : false;
380
  }
381
 
382
  // Set events listing view class.
383
+ if ( is_null( $this->view ) ) {
384
  // Set the requested view based on POST or GET value. We only care
385
  // if the view is 'grid' specifically.
386
  $requested_view = $this->detect_view_type();
387
 
388
  // If 'grid' is requested use it otherwise use list view by default.
389
  if ( 'grid' !== $requested_view ) {
390
+ $this->view = new WSAL_AuditLogListView( $this->plugin, $this, $this->page_args );
391
  } else {
392
+ $this->view = new WSAL_AuditLogGridView( $this->plugin, $this, $this->page_args );
393
  }
394
 
395
  // if the requested view didn't match the view users last viewed
399
  $this->user_last_view = $requested_view;
400
  }
401
  }
402
+ return $this->view;
403
  }
404
 
405
  /**
422
  * @method detect_view_type
423
  * @since 4.0.0
424
  * @return string
425
+ *
426
+ * phpcs:disable WordPress.Security.NonceVerification.Missing
427
+ * phpcs:disable WordPress.Security.NonceVerification.Recommended
428
  */
429
  public function detect_view_type() {
430
  // First check if there is a GET/POST request for a specific view.
467
  check_admin_referer( 'bulk-logs' );
468
  }
469
 
470
+ $wpnonce = isset( $_GET['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ) : false; // View nonce.
471
+ $search = isset( $_GET['s'] ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : false; // Search.
472
+ $site_id = isset( $_GET['wsal-cbid'] ) ? (int) sanitize_text_field( wp_unslash( $_GET['wsal-cbid'] ) ) : false; // Site id.
473
+ $search_save = ( isset( $_REQUEST['wsal-save-search-name'] ) && ! empty( $_REQUEST['wsal-save-search-name'] ) ) ? trim( sanitize_text_field( wp_unslash( $_REQUEST['wsal-save-search-name'] ) ) ) : false;
 
 
474
 
475
  if ( ! empty( $wpnonce ) ) {
476
  // Remove args array.
503
  *
504
  * @since 1.0.0
505
  */
506
+ public function render() {
507
+ if ( ! $this->plugin->settings()->current_user_can( 'view' ) ) {
508
  wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'wp-security-audit-log' ) );
509
  }
510
 
513
  check_admin_referer( 'bulk-logs' );
514
  }
515
 
516
+ $this->get_view()->prepare_items();
517
+ $view_input_value = ( isset( $_GET['view'] ) && 'grid' === wp_unslash( $_GET['view'] ) ) ? 'grid' : 'list'; // phpcs:ignore
518
  ?>
519
  <form id="audit-log-viewer" method="get">
520
  <div id="audit-log-viewer-content">
521
  <input type="hidden" name="page" value="<?php echo esc_attr( $this->page_args->page ); ?>" />
522
  <input type="hidden" id="wsal-cbid" name="wsal-cbid" value="<?php echo esc_attr( empty( $this->page_args->site_id ) ? '0' : $this->page_args->site_id ); ?>" />
523
+ <input type="hidden" id="view" name="view" value="<?php echo esc_attr( $view_input_value ); ?>" />
524
  <?php
525
  /**
526
  * Hook: `wsal_auditlog_before_view`
529
  *
530
  * @param WSAL_AuditLogListView $this->_view - Audit log view object.
531
  */
532
+ do_action( 'wsal_auditlog_before_view', $this->get_view() );
533
 
534
  // Display the audit log list.
535
+ $this->get_view()->display();
536
 
537
  /**
538
  * Hook: `wsal_auditlog_after_view`
541
  *
542
  * @param WSAL_AuditLogListView $this->_view - Audit log view object.
543
  */
544
+ do_action( 'wsal_auditlog_after_view', $this->get_view() );
545
  ?>
546
  </div>
547
  </form>
548
 
549
  <?php
550
  if (
551
+ $this->plugin->settings()->current_user_can( 'edit' )
552
+ && ! $this->plugin->get_global_boolean_setting( 'setup-complete', false )
553
+ && ! $this->plugin->get_global_boolean_setting( 'setup-modal-dismissed', false )
554
  ) :
555
  ?>
556
  <div data-remodal-id="wsal-setup-modal">
572
  });
573
 
574
  jQuery(document).on('closed', wsal_setup_modal, function () {
575
+ wsal_dismiss_setup_modal();
576
  });
577
  });
578
  </script>
594
  'searchnone' => __( 'No Results', 'wp-security-audit-log' ),
595
  ),
596
  'autorefresh' => array(
597
+ 'enabled' => ! $is_search_view && $this->plugin->settings()->is_refresh_alerts_enabled(),
598
+ 'token' => $this->plugin->settings()->is_infinite_scroll() ? $this->get_total_events() : $this->get_view()->get_total_items(),
599
  ),
600
  )
601
  );
610
  * Ajax callback to display meta data inspector.
611
  */
612
  public function AjaxInspector() {
613
+ if ( ! $this->plugin->settings()->current_user_can( 'view' ) ) {
614
  die( 'Access Denied.' );
615
  }
616
 
623
 
624
 
625
  $occ = new WSAL_Models_Occurrence();
626
+ $occ->load( 'id = %d', array( (int) $get_array['occurrence'] ) );
627
+ $alert_meta = $occ->get_meta_array();
628
  unset( $alert_meta['ReportText'] );
629
 
630
  // Set WSAL_Ref class scripts and styles.
631
+ WSAL_Ref::config( 'stylePath', esc_url( $this->plugin->get_base_dir() ) . '/css/wsal-ref.css' );
632
+ WSAL_Ref::config( 'scriptPath', esc_url( $this->plugin->get_base_dir() ) . '/js/wsal-ref.js' );
633
 
634
  echo '<!DOCTYPE html><html><head>';
635
  echo '<style type="text/css">';
644
  /**
645
  * Ajax callback to refresh the view.
646
  */
647
+ public function ajax_refresh() {
648
+ if ( ! $this->plugin->settings()->current_user_can( 'view' ) ) {
649
  die( 'Access Denied.' );
650
  }
651
 
663
 
664
  // Check for new total number of alerts.
665
  $occ = new WSAL_Models_Occurrence();
666
+ $new = (int) $occ->count();
667
 
668
+ // If the count is changed, then return the new count.
669
+ echo $old === $new ? 'false' : esc_html( $new );
670
  die;
671
  }
672
 
674
  * Ajax callback to set number of alerts to
675
  * show on a single page.
676
  */
677
+ public function ajax_set_items_per_page() {
678
+ if ( ! $this->plugin->settings()->current_user_can( 'view' ) ) {
679
  die( 'Access Denied.' );
680
  }
681
 
685
  if ( ! isset( $post_array['count'] ) ) {
686
  die( 'Count parameter expected.' );
687
  }
688
+ $this->plugin->settings()->set_views_per_page( (int) $post_array['count'] );
689
  die;
690
  }
691
 
692
  /**
693
  * Ajax callback to search.
694
  */
695
+ public function ajax_search_site() {
696
+ if ( ! $this->plugin->settings()->current_user_can( 'view' ) ) {
697
  die( 'Access Denied.' );
698
  }
699
 
708
 
709
  $search = $post_array['search'];
710
 
711
+ foreach ( $this->get_view()->get_sites() as $site ) {
712
  if ( stripos( $site->blogname, $search ) !== false ) {
713
  $grp1[] = $site;
714
  } elseif ( stripos( $site->domain, $search ) !== false ) {
715
  $grp2[] = $site;
716
  }
717
  }
718
+ die( json_encode( array_slice( $grp1 + $grp2, 0, 7 ) ) ); // phpcs:ignore
719
  }
720
 
721
 
732
  die();
733
  }
734
 
735
+ // Get alert by id.
736
+ $alert_id = filter_input( INPUT_POST, 'alert_id', FILTER_SANITIZE_NUMBER_INT );
737
+ $alert = new WSAL_Models_Occurrence();
738
+ $alert->id = (int) $alert_id;
739
 
740
+ // Get users using alert meta.
741
+ $users = $alert->get_meta_value( 'Users', array() );
742
 
743
+ // Check if there are any users.
744
+ if ( ! empty( $users ) && is_array( $users ) ) {
745
+ // Prepare content.
746
+ $content = implode( ',', $users );
747
+ echo esc_html( $content );
748
+ } else {
749
+ echo esc_html__( 'No users found.', 'wp-security-audit-log' );
750
+ }
751
 
752
  die();
753
  }
754
 
755
  /**
756
+ * Ajax callback to handle Freemius opt in/out.
757
  */
758
  public function wsal_freemius_opt_in() {
759
  // Die if not have access.
760
+ if ( ! $this->plugin->settings()->current_user_can( 'edit' ) ) {
761
  die( 'Access Denied.' );
762
  }
763
 
795
  wsal_freemius()->opt_in( false, false, false, false, false, false, false, false, $sites_data );
796
  }
797
 
798
+ // Update Freemius state.
799
+ $this->plugin->set_global_setting( 'freemius_state', 'in', true );
800
  } elseif ( 'no' === $choice ) {
801
  if ( ! is_multisite() ) {
802
  wsal_freemius()->skip_connection(); // Opt out.
804
  wsal_freemius()->skip_connection( null, true ); // Opt out for all websites.
805
  }
806
 
807
+ // Update Freemius state.
808
+ $this->plugin->set_global_setting( 'freemius_state', 'skipped', true );
809
  }
810
 
811
  echo wp_json_encode(
828
  /**
829
  * Method: Render header of the view.
830
  */
831
+ public function header() {
832
  add_thickbox();
833
 
834
  // Darktooltip styles.
835
  wp_enqueue_style(
836
  'darktooltip',
837
+ $this->plugin->get_base_url() . '/css/darktooltip.css',
838
  array(),
839
  '0.4.0'
840
  );
841
 
842
  // Remodal styles.
843
+ wp_enqueue_style( 'wsal-remodal', $this->plugin->get_base_url() . '/css/remodal.css', array(), '1.1.1' );
844
+ wp_enqueue_style( 'wsal-remodal-theme', $this->plugin->get_base_url() . '/css/remodal-default-theme.css', array(), '1.1.1.1' );
845
 
846
  // Audit log styles.
847
  wp_enqueue_style(
848
  'auditlog',
849
+ $this->plugin->get_base_url() . '/css/auditlog.css',
850
  array(),
851
+ filemtime( $this->plugin->get_base_dir() . '/css/auditlog.css' )
852
  );
853
 
854
+ // Admin notices styles.
855
  wp_enqueue_style(
856
  'wsal_admin_notices',
857
+ $this->plugin->get_base_url() . '/css/admin-notices.css',
858
  array(),
859
+ filemtime( $this->plugin->get_base_dir() . '/css/admin-notices.css' )
860
  );
861
  }
862
 
863
  /**
864
+ * {@inheritDoc}
865
  */
866
+ public function footer() {
867
  wp_enqueue_script( 'jquery' );
868
 
869
  // Darktooltip js.
870
  wp_enqueue_script(
871
  'darktooltip', // Identifier.
872
+ $this->plugin->get_base_url() . '/js/jquery.darktooltip.js', // Script location.
873
  array( 'jquery' ), // Depends on jQuery.
874
  '0.4.0', // Script version.
875
  true
878
  // Remodal script.
879
  wp_enqueue_script(
880
  'wsal-remodal-js',
881
+ $this->plugin->get_base_url() . '/js/remodal.min.js',
882
  array(),
883
  '1.1.1',
884
  true
890
  // Audit log script.
891
  wp_register_script(
892
  'auditlog',
893
+ $this->plugin->get_base_url() . '/js/auditlog.js',
894
  array(),
895
+ filemtime( $this->plugin->get_base_dir() . '/js/auditlog.js' ),
896
  true
897
  );
898
+
899
  $audit_log_data = array(
900
  'page' => isset( $this->page_args->page ) ? $this->page_args->page : false,
901
  'siteId' => isset( $this->page_args->site_id ) ? $this->page_args->site_id : false,
904
  'searchTerm' => isset( $this->page_args->search_term ) ? $this->page_args->search_term : false,
905
  'searchFilters' => isset( $this->page_args->search_filters ) ? $this->page_args->search_filters : false,
906
  'viewerNonce' => wp_create_nonce( 'wsal_auditlog_viewer_nonce' ),
907
+ 'infiniteScroll' => $this->plugin->settings()->is_infinite_scroll(),
908
  'userView' => ( in_array( $this->user_last_view, $this->supported_view_types(), true ) ) ? $this->user_last_view : 'list',
909
  'installAddonStrings' => array(
910
+ 'defaultButton' => esc_html__( 'Install and activate extension', 'wp-security-audit-log' ),
911
+ 'installingText' => esc_html__( 'Installing extension', 'wp-security-audit-log' ),
912
+ 'otherInstalling' => esc_html__( 'Other extension installing', 'wp-security-audit-log' ),
913
+ 'addonInstalled' => esc_html__( 'Installed', 'wp-security-audit-log' ),
914
+ 'installedReload' => esc_html__( 'Installed... reloading page', 'wp-security-audit-log' ),
915
+ 'buttonError' => esc_html__( 'Problem enabling', 'wp-security-audit-log' ),
916
  'msgError' => sprintf(
917
  /* translators: 1 - an opening link tag, 2 - the closing tag. */
918
  __( '<br>An error occurred when trying to install and activate the plugin. Please try install it again from the %1$sevent settings%2$s page.', 'wp-security-audit-log' ),
939
 
940
  // Don't display notice if the wizard notice is showing.
941
  if (
942
+ ! $this->plugin->get_global_boolean_setting( 'setup-complete', false )
943
+ && ! $this->plugin->get_global_boolean_setting( 'setup-modal-dismissed', false )
944
  ) {
945
  return;
946
  }
957
  }
958
 
959
  // Get dismissed pointers.
960
+ $dismissed = explode( ',', (string) $this->plugin->get_global_setting( 'dismissed-privacy-notice', true ) );
961
  $valid_pointers = array();
962
 
963
  // Check pointers and remove dismissed ones.
964
  foreach ( $pointers as $pointer_id => $pointer ) {
965
  // Sanity check.
966
  if (
967
+ in_array( $pointer_id, $dismissed ) // phpcs:ignore
968
  || empty( $pointer )
969
  || empty( $pointer_id )
970
  || empty( $pointer['target'] )
989
  // Add pointers script to queue. Add custom script.
990
  wp_enqueue_script(
991
  'auditlog-pointer',
992
+ $this->plugin->get_base_url() . '/js/auditlog-pointer.js',
993
  array( 'wp-pointer' ),
994
+ filemtime( $this->plugin->get_base_dir() . '/js/auditlog-pointer.js' ),
995
  true
996
  );
997
 
1007
  * @since 3.2
1008
  */
1009
  public function register_privacy_pointer( $pointer ) {
1010
+ $is_current_view = $this->plugin->views->get_active_view() == $this; // phpcs:ignore
1011
  if ( current_user_can( 'manage_options' ) && $is_current_view && ! isset( $pointer['wsal_privacy'] ) ) {
1012
  $pointer['wsal_privacy'] = array(
1013
  'target' => '#toplevel_page_wsal-auditlog .wp-first-item',
1014
  'options' => array(
1015
  'content' => sprintf(
1016
  '<h3> %s </h3> <p> %s </p> <p><strong>%s</strong></p>',
1017
+ esc_html__( 'WordPress Activity Log', 'wp-security-audit-log' ),
1018
+ esc_html__( 'When a user makes a change on your website the plugin will keep a record of that event here. Right now there is nothing because this is a new install.', 'wp-security-audit-log' ),
1019
+ esc_html__( 'Thank you for using WP Activity Log', 'wp-security-audit-log' )
1020
  ),
1021
  'position' => array(
1022
  'edge' => 'left',
1035
  */
1036
  public function wsal_dismiss_advert() {
1037
  // Die if user does not have permission to dismiss.
1038
+ if ( ! $this->plugin->settings()->current_user_can( 'edit' ) ) {
1039
  echo wp_json_encode(
1040
  array(
1041
  'success' => false,
1061
  // @codingStandardsIgnoreEnd
1062
 
1063
  $advert = 2 === $advert ? '0' : $advert + 1;
1064
+ $this->plugin->set_global_setting( 'premium-advert', $advert );
1065
+ $set_transient_fn = $this->plugin->is_multisite() ? 'set_site_transient' : 'set_transient';
1066
  $set_transient_fn( 'wsal-is-advert-dismissed', true, MONTH_IN_SECONDS );
1067
  echo wp_json_encode(
1068
  array(
1082
  $pointer = sanitize_text_field( wp_unslash( $_POST['pointer'] ) );
1083
  // @codingStandardsIgnoreEnd
1084
 
1085
+ if ( $pointer != sanitize_key( $pointer ) ) { // phpcs:ignore
1086
  wp_die( 0 );
1087
  }
1088
 
1089
+ $dismissed = array_filter( explode( ',', (string) $this->plugin->get_global_setting( 'dismissed-privacy-notice', true ) ) );
1090
 
1091
+ if ( in_array( $pointer, $dismissed ) ) { // phpcs:ignore
1092
  wp_die( 0 );
1093
  }
1094
 
1095
  $dismissed[] = $pointer;
1096
  $dismissed = implode( ',', $dismissed );
1097
 
1098
+ $this->plugin->set_global_setting( 'dismissed-privacy-notice', $dismissed );
1099
  wp_die( 1 );
1100
  }
1101
 
1102
  /**
1103
+ * Infinite Scroll Events AJAX handler.
1104
  *
1105
  * @since 3.3.1.1
1106
  */
1107
  public function infinite_scroll_events() {
1108
  // Check user permissions.
1109
+ if ( ! $this->plugin->settings()->current_user_can( 'view' ) ) {
1110
  die( esc_html__( 'Access Denied', 'wp-security-audit-log' ) );
1111
  }
1112
 
1115
  die( esc_html__( 'Nonce verification failed.', 'wp-security-audit-log' ) );
1116
  }
1117
 
1118
+ // Get $_POST arguments.
1119
+ $paged = isset( $_POST['page_number'] ) ? sanitize_text_field( wp_unslash( $_POST['page_number'] ) ) : 0;
1120
+
1121
+ // Query events.
1122
+ $events_query = $this->get_view()->query_events( $paged );
1123
+ if ( ! empty( $events_query['items'] ) ) {
1124
+ foreach ( $events_query['items'] as $event ) {
1125
+ $this->get_view()->single_row( $event );
1126
+ }
1127
+ }
1128
+ exit();
1129
  }
1130
 
1131
  /**
1135
  */
1136
  public function get_total_events() {
1137
  $occ = new WSAL_Models_Occurrence();
1138
+ return (int) $occ->count();
1139
  }
1140
 
1141
  /**
1145
  */
1146
  public function dismiss_setup_modal() {
1147
  // Die if user does not have permission to dismiss.
1148
+ if ( ! $this->plugin->settings()->current_user_can( 'edit' ) ) {
1149
  echo wp_json_encode(
1150
  array(
1151
  'success' => false,
1156
  }
1157
 
1158
  // Filter $_POST array for security.
1159
+ $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : false; // phpcs:ignore
 
 
1160
 
1161
  if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'wsal_dismiss_setup_modal' ) ) {
1162
  // Nonce verification failed.
1169
  die();
1170
  }
1171
 
1172
+ $this->plugin->set_global_boolean_setting( 'setup-modal-dismissed', true, true );
1173
  wp_send_json_success();
1174
  }
1175
 
1176
 
1177
  /**
1178
+ * Gets a URL to the UI tab listing third party plugins.
1179
+ *
1180
  * @return string URL of the 3rd party extensions tab.
1181
+ * @since 4.3.2
1182
  */
1183
+ public function get_third_party_plugins_tab_url() {
1184
+ return esc_url( add_query_arg( 'page', 'wsal-togglealerts#tab-third-party-plugins', network_admin_url( 'admin.php' ) ) );
1185
+ }
1186
 
1187
  /**
1188
  * Builds HTML markup to display 3rd party extension teaser if there is a post type in the event meta data and the
1209
  return $result;
1210
  }
1211
 
1212
+ $result .= '<div class="extension-ad" style="border-color: transparent transparent ' . $extension->get_color() . ' transparent;">';
1213
+ $result .= '</div>';
1214
  $plugin_name = $extension->get_plugin_name();
1215
  $link_title = sprintf(
1216
+ esc_html__( 'Install the activity log extension for %1$s for more detailed logging of changes done in %2$s.', 'wp-security-audit-log' ), // phpcs:ignore
1217
  $plugin_name,
1218
  $plugin_name
1219
  );
1220
+ $result .= '<a class="icon" title="' . $link_title . '" href="' . $this->get_third_party_plugins_tab_url() . '">';
1221
+ $result .= '<img src="' . $extension->get_plugin_icon_url() . '" />';
1222
+ $result .= '</div>';
1223
 
1224
  return $result;
1225
  }
classes/Views/EmailNotifications.php CHANGED
@@ -4,8 +4,9 @@
4
  *
5
  * WSAL email notifications page.
6
  *
7
- * @since 1.0.0
8
- * @package wsal
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -17,63 +18,64 @@ if ( ! defined( 'ABSPATH' ) ) {
17
  * Email Notifications Add-On promo Page.
18
  * Used only if the plugin is not activated.
19
  *
20
- * @package wsal
 
21
  */
22
  class WSAL_Views_EmailNotifications extends WSAL_ExtensionPlaceholderView {
23
 
24
  /**
25
- * Get View Title.
26
  */
27
- public function GetTitle() {
28
- return __( 'Notifications Extension', 'wp-security-audit-log' );
29
  }
30
 
31
  /**
32
- * Get View Name.
33
  */
34
- public function GetName() {
35
- return __( 'Email Notifications &#8682;', 'wp-security-audit-log' );
36
  }
37
 
38
  /**
39
- * Get View Weight.
40
  */
41
- public function GetWeight() {
42
  return 2;
43
  }
44
 
45
  /**
46
- * Page View.
47
  */
48
- public function Render() {
49
- $title = __( 'Email & SMS Notifications', 'wp-security-audit-log' );
50
- $description = __( 'Get instantly alerted of important changes on your site via email notifications & SMS messages. Upgrade to premium and:', 'wp-security-audit-log' );
51
- $addon_img = trailingslashit( WSAL_BASE_URL ) . 'img/' . $this->GetSafeViewName() . '.jpg';
52
  $premium_list = array(
53
- __( 'Configure any type of email notification', 'wp-security-audit-log' ),
54
- __( 'Configure SMS messages for instant critical alerts', 'wp-security-audit-log' ),
55
- __( 'Receive notifications for when users login, change their password or change content', 'wp-security-audit-log' ),
56
- __( 'Get alerted of site changes like plugin installs, theme changes etc', 'wp-security-audit-log' ),
57
- __( 'Enable built-in security email notifications of suspicious user activity', 'wp-security-audit-log' ),
58
- __( 'Personalize all email and SMS templates', 'wp-security-audit-log' ),
59
- __( 'Use the trigger builder to configure any type of notification criteria!', 'wp-security-audit-log' ),
60
  );
61
- $subtext = __( 'Getting started is really easy. You can use one of the plugin’s built-in notifications or create your own using the easy to use trigger builder.', 'wp-security-audit-log' );
62
  $screenshots = array(
63
  array(
64
- 'desc' => __( 'Email and SMS notifications instantly alert you of important changes on your WordPress site.', 'wp-security-audit-log' ),
65
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/notifications/notifications_1.png',
66
  ),
67
  array(
68
- 'desc' => __( 'Easily enable any of the built-in security and user management notifications.', 'wp-security-audit-log' ),
69
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/notifications/notifications_2.png',
70
  ),
71
  array(
72
- 'desc' => __( 'Use the trigger builder to configure any type of email and SMS notification to get instantly alerted of site changes that are important to you and your business.', 'wp-security-audit-log' ),
73
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/notifications/notifications_3.png',
74
  ),
75
  array(
76
- 'desc' => __( 'All email and SMS templates are configurable, allowing you to personalize them.', 'wp-security-audit-log' ),
77
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/notifications/notifications_4.png',
78
  ),
79
  );
4
  *
5
  * WSAL email notifications page.
6
  *
7
+ * @since 1.0.0
8
+ * @package wsal
9
+ * @subpackage views
10
  */
11
 
12
  // Exit if accessed directly.
18
  * Email Notifications Add-On promo Page.
19
  * Used only if the plugin is not activated.
20
  *
21
+ * @package wsal
22
+ * @subpackage views
23
  */
24
  class WSAL_Views_EmailNotifications extends WSAL_ExtensionPlaceholderView {
25
 
26
  /**
27
+ * {@inheritDoc}
28
  */
29
+ public function get_title() {
30
+ return esc_html__( 'Notifications Extension', 'wp-security-audit-log' );
31
  }
32
 
33
  /**
34
+ * {@inheritDoc}
35
  */
36
+ public function get_name() {
37
+ return esc_html__( 'Email Notifications &#8682;', 'wp-security-audit-log' );
38
  }
39
 
40
  /**
41
+ * {@inheritDoc}
42
  */
43
+ public function get_weight() {
44
  return 2;
45
  }
46
 
47
  /**
48
+ * {@inheritDoc}
49
  */
50
+ public function render() {
51
+ $title = esc_html__( 'Email & SMS Notifications', 'wp-security-audit-log' );
52
+ $description = esc_html__( 'Get instantly alerted of important changes on your site via email notifications & SMS messages. Upgrade to premium and:', 'wp-security-audit-log' );
53
+ $addon_img = trailingslashit( WSAL_BASE_URL ) . 'img/' . $this->get_safe_view_name() . '.jpg';
54
  $premium_list = array(
55
+ esc_html__( 'Configure any type of email notification', 'wp-security-audit-log' ),
56
+ esc_html__( 'Configure SMS messages for instant critical alerts', 'wp-security-audit-log' ),
57
+ esc_html__( 'Receive notifications for when users login, change their password or change content', 'wp-security-audit-log' ),
58
+ esc_html__( 'Get alerted of site changes like plugin installs, theme changes etc', 'wp-security-audit-log' ),
59
+ esc_html__( 'Enable built-in security email notifications of suspicious user activity', 'wp-security-audit-log' ),
60
+ esc_html__( 'Personalize all email and SMS templates', 'wp-security-audit-log' ),
61
+ esc_html__( 'Use the trigger builder to configure any type of notification criteria!', 'wp-security-audit-log' ),
62
  );
63
+ $subtext = esc_html__( 'Getting started is really easy. You can use one of the plugin’s built-in notifications or create your own using the easy to use trigger builder.', 'wp-security-audit-log' );
64
  $screenshots = array(
65
  array(
66
+ 'desc' => esc_html__( 'Email and SMS notifications instantly alert you of important changes on your WordPress site.', 'wp-security-audit-log' ),
67
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/notifications/notifications_1.png',
68
  ),
69
  array(
70
+ 'desc' => esc_html__( 'Easily enable any of the built-in security and user management notifications.', 'wp-security-audit-log' ),
71
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/notifications/notifications_2.png',
72
  ),
73
  array(
74
+ 'desc' => esc_html__( 'Use the trigger builder to configure any type of email and SMS notification to get instantly alerted of site changes that are important to you and your business.', 'wp-security-audit-log' ),
75
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/notifications/notifications_3.png',
76
  ),
77
  array(
78
+ 'desc' => esc_html__( 'All email and SMS templates are configurable, allowing you to personalize them.', 'wp-security-audit-log' ),
79
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/notifications/notifications_4.png',
80
  ),
81
  );
classes/Views/ExternalDB.php CHANGED
@@ -4,8 +4,9 @@
4
  *
5
  * WSAL external db page.
6
  *
7
- * @since 1.0.0
8
- * @package wsal
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -17,56 +18,57 @@ if ( ! defined( 'ABSPATH' ) ) {
17
  * External DB Add-On promo Page.
18
  * Used only if the plugin is not activated.
19
  *
20
- * @package wsal
 
21
  */
22
  class WSAL_Views_ExternalDB extends WSAL_ExtensionPlaceholderView {
23
 
24
  /**
25
- * Method: Get View Title.
26
  */
27
- public function GetTitle() {
28
- return __( 'External DB Extension', 'wp-security-audit-log' );
29
  }
30
 
31
  /**
32
- * Method: Get View Name.
33
  */
34
- public function GetName() {
35
- return __( 'Integrations &#8682;', 'wp-security-audit-log' );
36
  }
37
 
38
  /**
39
- * Method: Get View Weight.
40
  */
41
- public function GetWeight() {
42
  return 10;
43
  }
44
 
45
  /**
46
- * Page View.
47
  */
48
- public function Render() {
49
- $title = __( 'Activity log database & integration tools', 'wp-security-audit-log' );
50
- $description = __( 'There are several benefits to segregating the logs from the main site database, and to be able to mirror the logs to third party and centralized business solutions. Upgrade to premium and:', 'wp-security-audit-log' );
51
- $addon_img = trailingslashit( WSAL_BASE_URL ) . 'img/' . $this->GetSafeViewName() . '.jpg';
52
  $premium_list = array(
53
- __( 'Store the audit logs of your sites on an external database', 'wp-security-audit-log' ),
54
- __( 'Configuring archiving and store older log data in a segregated database', 'wp-security-audit-log' ),
55
- __( 'Mirror the logs to syslog, Slack, Papertrail and central business communication services', 'wp-security-audit-log' ),
56
- __( 'Configure filters to filter what is mirrored and archived in the databases and services', 'wp-security-audit-log' ),
57
  );
58
  $subtext = false;
59
  $screenshots = array(
60
  array(
61
- 'desc' => __( 'Easily configure integration and database connections thanks to a user friendly wizard.', 'wp-security-audit-log' ),
62
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/external-db/db_integrations_1.png',
63
  ),
64
  array(
65
- 'desc' => __( 'Configure activity log filters for third party services connections.', 'wp-security-audit-log' ),
66
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/external-db/db_integrations_2.png',
67
  ),
68
  array(
69
- 'desc' => __( 'Configure an unlimited number of connections to different databases and third party services.', 'wp-security-audit-log' ),
70
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/external-db/db_integrations_3.png',
71
  ),
72
  );
4
  *
5
  * WSAL external db page.
6
  *
7
+ * @since 1.0.0
8
+ * @package wsal
9
+ * @subpackage views
10
  */
11
 
12
  // Exit if accessed directly.
18
  * External DB Add-On promo Page.
19
  * Used only if the plugin is not activated.
20
  *
21
+ * @package wsal
22
+ * @subpackage views
23
  */
24
  class WSAL_Views_ExternalDB extends WSAL_ExtensionPlaceholderView {
25
 
26
  /**
27
+ * {@inheritDoc}
28
  */
29
+ public function get_title() {
30
+ return esc_html__( 'External DB Extension', 'wp-security-audit-log' );
31
  }
32
 
33
  /**
34
+ * {@inheritDoc}
35
  */
36
+ public function get_name() {
37
+ return esc_html__( 'Integrations &#8682;', 'wp-security-audit-log' );
38
  }
39
 
40
  /**
41
+ * {@inheritDoc}
42
  */
43
+ public function get_weight() {
44
  return 10;
45
  }
46
 
47
  /**
48
+ * {@inheritDoc}
49
  */
50
+ public function render() {
51
+ $title = esc_html__( 'Activity log database & integration tools', 'wp-security-audit-log' );
52
+ $description = esc_html__( 'There are several benefits to segregating the logs from the main site database, and to be able to mirror the logs to third party and centralized business solutions. Upgrade to premium and:', 'wp-security-audit-log' );
53
+ $addon_img = trailingslashit( WSAL_BASE_URL ) . 'img/' . $this->get_safe_view_name() . '.jpg';
54
  $premium_list = array(
55
+ esc_html__( 'Store the audit logs of your sites on an external database', 'wp-security-audit-log' ),
56
+ esc_html__( 'Configuring archiving and store older log data in a segregated database', 'wp-security-audit-log' ),
57
+ esc_html__( 'Mirror the logs to syslog, Slack, Papertrail and central business communication services', 'wp-security-audit-log' ),
58
+ esc_html__( 'Configure filters to filter what is mirrored and archived in the databases and services', 'wp-security-audit-log' ),
59
  );
60
  $subtext = false;
61
  $screenshots = array(
62
  array(
63
+ 'desc' => esc_html__( 'Easily configure integration and database connections thanks to a user friendly wizard.', 'wp-security-audit-log' ),
64
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/external-db/db_integrations_1.png',
65
  ),
66
  array(
67
+ 'desc' => esc_html__( 'Configure activity log filters for third party services connections.', 'wp-security-audit-log' ),
68
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/external-db/db_integrations_2.png',
69
  ),
70
  array(
71
+ 'desc' => esc_html__( 'Configure an unlimited number of connections to different databases and third party services.', 'wp-security-audit-log' ),
72
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/external-db/db_integrations_3.png',
73
  ),
74
  );
classes/Views/Help.php CHANGED
@@ -4,8 +4,9 @@
4
  *
5
  * WSAL help page.
6
  *
7
- * @since 1.0.0
8
- * @package wsal
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -19,7 +20,8 @@ if ( ! defined( 'ABSPATH' ) ) {
19
  * - Plugin Support
20
  * - Plugin Documentation
21
  *
22
- * @package wsal
 
23
  */
24
  class WSAL_Views_Help extends WSAL_AbstractView {
25
 
@@ -39,6 +41,8 @@ class WSAL_Views_Help extends WSAL_AbstractView {
39
 
40
  /**
41
  * Constructor.
 
 
42
  */
43
  public function __construct( $plugin ) {
44
  parent::__construct( $plugin );
@@ -52,30 +56,31 @@ class WSAL_Views_Help extends WSAL_AbstractView {
52
  $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : false; // phpcs:ignore
53
 
54
  // Verify that the current page is WSAL settings page.
55
- if ( empty( $page ) || $this->GetSafeViewName() !== $page ) {
56
  return;
57
  }
58
 
59
  // Tab links.
60
  $wsal_help_tabs = array(
61
- 'help' => array(
62
- 'name' => __( 'Help', 'wp-security-audit-log' ),
63
- 'link' => $this->GetUrl(),
64
  'render' => array( $this, 'tab_help' ),
65
  'priority' => 10,
66
  ),
67
  );
68
 
69
- if ( $this->_plugin->settings()->CurrentUserCan( 'edit' ) ) {
70
  $wsal_help_tabs['contact'] = array(
71
- 'name' => __( 'Contact Us', 'wp-security-audit-log' ),
72
- 'link' => add_query_arg( 'tab', 'contact', $this->GetUrl() ),
73
  'render' => array( $this, 'tab_contact_us' ),
74
  'priority' => 15,
75
  );
 
76
  $wsal_help_tabs['system-info'] = array(
77
- 'name' => __( 'System Info', 'wp-security-audit-log' ),
78
- 'link' => add_query_arg( 'tab', 'system-info', $this->GetUrl() ),
79
  'render' => array( $this, 'tab_system_info' ),
80
  'priority' => 20,
81
  );
@@ -107,50 +112,50 @@ class WSAL_Views_Help extends WSAL_AbstractView {
107
  }
108
 
109
  /**
110
- * Method: Get View Title.
111
  */
112
- public function GetTitle() {
113
- return __( 'Help', 'wp-security-audit-log' );
114
  }
115
 
116
  /**
117
- * Method: Get View Icon.
118
  */
119
- public function GetIcon() {
120
  return 'dashicons-sos';
121
  }
122
 
123
  /**
124
- * Method: Get View Name.
125
  */
126
- public function GetName() {
127
- return __( 'Help & Contact Us', 'wp-security-audit-log' );
128
  }
129
 
130
  /**
131
- * Method: Get View Weight.
132
  */
133
- public function GetWeight() {
134
  return 10;
135
  }
136
 
137
  /**
138
- * Method: Get View Header.
139
  */
140
- public function Header() {
141
  wp_enqueue_style(
142
  'extensions',
143
- $this->_plugin->GetBaseUrl() . '/css/extensions.css',
144
  array(),
145
- filemtime( $this->_plugin->GetBaseDir() . '/css/extensions.css' )
146
  );
147
  }
148
 
149
  /**
150
- * Method: Get View.
151
  */
152
- public function Render() {
153
- $can_current_user_edit = $this->_plugin->settings()->CurrentUserCan( 'edit' );
154
  ?>
155
  <nav id="wsal-tabs" class="nav-tab-wrapper">
156
  <?php
@@ -206,9 +211,7 @@ class WSAL_Views_Help extends WSAL_AbstractView {
206
  <?php esc_html_e( 'Refer to the list of WordPress security events for a complete list of Events and IDs that the plugin uses to keep a log of all the changes in the WordPress activity log.', 'wp-security-audit-log' ); ?>
207
  </p><p>
208
  <a class="button" rel="noopener noreferrer" href="https://wpactivitylog.com/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=plugin+website" target="_blank"><?php esc_html_e( 'Plugin Website', 'wp-security-audit-log' ); ?></a>
209
- &nbsp;&nbsp;&nbsp;&nbsp;
210
  <a class="button" rel="noopener noreferrer" href="https://wpactivitylog.com/support/kb/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=knowledge+base" target="_blank"><?php esc_html_e( 'Knowledge Base', 'wp-security-audit-log' ); ?></a>
211
- &nbsp;&nbsp;&nbsp;&nbsp;
212
  <a class="button" rel="noopener noreferrer" href="https://wpactivitylog.com/support/kb/list-wordpress-activity-log-event-ids/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=list+events" target="_blank"><?php esc_html_e( 'List of activity logs event IDs', 'wp-security-audit-log' ); ?></a>
213
  </p>
214
  </div>
@@ -247,13 +250,13 @@ class WSAL_Views_Help extends WSAL_AbstractView {
247
  left: 0 !important;
248
  }
249
  .fs-full-size-wrapper {
250
- margin: 10px 20px 0 2px !important;
251
  }
252
  </style>
253
  <?php
254
  $freemius_id = wsal_freemius()->get_id();
255
- $vars = array( 'id' => $freemius_id );
256
- echo fs_get_template( 'contact.php', $vars );
257
  }
258
 
259
  /**
@@ -279,31 +282,31 @@ class WSAL_Views_Help extends WSAL_AbstractView {
279
  $plugins_data = array(
280
  array(
281
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/help/wp-2fa-img.jpg',
282
- 'desc' => __( 'Add an extra layer of security to your login pages with 2FA & require your users to use it.', 'wp-security-audit-log' ),
283
  'alt' => 'WP 2FA',
284
  'link' => 'https://wp2fa.io/?utm_source=plugin&utm_medium=referral&utm_campaign=WP2FA&utm_content=WSAL+banner',
285
  ),
286
  array(
287
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/help/c4wp.jpg',
288
- 'desc' => __( 'Protect website forms & login pages from spambots & automated attacks.', 'wp-security-audit-log' ),
289
  'alt' => 'Captcha 4WP',
290
  'link' => 'https://www.wpwhitesecurity.com/wordpress-plugins/captcha-plugin-wordpress/?utm_source=plugin&utm_medium=referral&utm_campaign=WP2FA&utm_content=WSAL+banner',
291
  ),
292
  array(
293
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/help/password-policy-manager.jpg',
294
- 'desc' => __( 'Enforce strong password policies on WordPress', 'wp-security-audit-log' ),
295
  'alt' => 'WPassword',
296
  'link' => 'https://www.wpwhitesecurity.com/wordpress-plugins/password-policy-manager-wordpress/?utm_source=plugin&utm_medium=referral&utm_campaign=PPMWP&utm_content=WSAL+banner',
297
  ),
298
  array(
299
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/help/website-file-changes-monitor.jpg',
300
- 'desc' => __( 'Automatically identify unauthorized file changes on WordPress', 'wp-security-audit-log' ),
301
  'alt' => 'Website File Changes Monitor',
302
  'link' => 'https://www.wpwhitesecurity.com/wordpress-plugins/website-file-changes-monitor/?utm_source=plugin&utm_medium=referral&utm_campaign=WFCM&utm_content=WSAL+banner',
303
  ),
304
  array(
305
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/help/activity-log-for-mainwp.jpg',
306
- 'desc' => __( 'See the child sites activity logs from the central MainWP dashboard', 'wp-security-audit-log' ),
307
  'alt' => 'Activity Log for MainWP',
308
  'link' => 'https://wpactivitylog.com/extensions/mainwp-activity-log/?utm_source=plugin&utm_medium=referral&utm_campaign=AL4MWP&utm_content=WSAL+banner',
309
  ),
@@ -334,7 +337,6 @@ class WSAL_Views_Help extends WSAL_AbstractView {
334
  * Method: Get system information.
335
  *
336
  * @return string - System information.
337
- * @throws Freemius_Exception
338
  */
339
  public function get_sysinfo() {
340
  // System info.
@@ -359,11 +361,11 @@ class WSAL_Views_Help extends WSAL_AbstractView {
359
 
360
  // Get theme info.
361
  $theme_data = wp_get_theme();
362
- $theme = $theme_data->Name . ' ' . $theme_data->Version;
363
- $parent_theme = $theme_data->Template;
364
  if ( ! empty( $parent_theme ) ) {
365
  $parent_theme_data = wp_get_theme( $parent_theme );
366
- $parent_theme = $parent_theme_data->Name . ' ' . $parent_theme_data->Version;
367
  }
368
 
369
  // Language information.
@@ -410,18 +412,15 @@ class WSAL_Views_Help extends WSAL_AbstractView {
410
  // WordPress active plugins.
411
  $sysinfo .= "\n" . '-- WordPress Active Plugins --' . "\n\n";
412
 
413
- $plugins = get_plugins();
414
- $active_plugins = get_option( 'active_plugins', array() );
415
-
416
  foreach ( $plugins as $plugin_path => $plugin ) {
417
- if ( ! in_array( $plugin_path, $active_plugins ) ) {
418
  continue;
419
  }
420
 
421
- if (
422
- 'WP Activity Log' === $plugin['Name']
423
- && wsal_freemius()->can_use_premium_code()
424
- ) {
425
  $update = ( array_key_exists( $plugin_path, $updates ) ) ? ' (needs update - ' . $updates[ $plugin_path ]->update->new_version . ')' : '';
426
  $sysinfo .= $plugin['Name'] . ' Premium: ' . $plugin['Version'] . $update . "\n";
427
  } else {
@@ -434,14 +433,11 @@ class WSAL_Views_Help extends WSAL_AbstractView {
434
  $sysinfo .= "\n" . '-- WordPress Inactive Plugins --' . "\n\n";
435
 
436
  foreach ( $plugins as $plugin_path => $plugin ) {
437
- if ( in_array( $plugin_path, $active_plugins ) ) {
438
  continue;
439
  }
440
 
441
- if (
442
- 'WP Activity Log' === $plugin['Name']
443
- && wsal_freemius()->can_use_premium_code()
444
- ) {
445
  $update = ( array_key_exists( $plugin_path, $updates ) ) ? ' (needs update - ' . $updates[ $plugin_path ]->update->new_version . ')' : '';
446
  $sysinfo .= $plugin['Name'] . ' Premium: ' . $plugin['Version'] . $update . "\n";
447
  } else {
@@ -464,10 +460,7 @@ class WSAL_Views_Help extends WSAL_AbstractView {
464
  continue;
465
  }
466
 
467
- if (
468
- 'WP Activity Log' === $plugin['Name']
469
- && wsal_freemius()->can_use_premium_code()
470
- ) {
471
  $update = ( array_key_exists( $plugin_path, $updates ) ) ? ' (needs update - ' . $updates[ $plugin_path ]->update->new_version . ')' : '';
472
  $plugin = get_plugin_data( $plugin_path );
473
  $sysinfo .= $plugin['Name'] . ' Premium: ' . $plugin['Version'] . $update . "\n";
@@ -503,7 +496,7 @@ class WSAL_Views_Help extends WSAL_AbstractView {
503
 
504
  // WSAL options.
505
  $sysinfo .= "\n" . '-- WSAL Options --' . "\n\n";
506
- $options = $this->_plugin->settings()->get_plugin_settings();
507
 
508
  if ( ! empty( $options ) && is_array( $options ) ) {
509
  foreach ( $options as $option ) {
@@ -518,10 +511,10 @@ class WSAL_Views_Help extends WSAL_AbstractView {
518
  }
519
 
520
  /**
521
- * Method: Render footer content.
522
  */
523
- public function Footer() {
524
- if ( 'system-info' === $this->current_tab && $this->_plugin->settings()->CurrentUserCan( 'edit' ) ) :
525
  ?>
526
  <script>
527
  /**
@@ -540,7 +533,7 @@ class WSAL_Views_Help extends WSAL_AbstractView {
540
  element.style.display = 'none';
541
  document.body.appendChild(element);
542
 
543
- // Simlate click on the element.
544
  element.click();
545
 
546
  // Remove temporary element.
4
  *
5
  * WSAL help page.
6
  *
7
+ * @since 1.0.0
8
+ * @package wsal
9
+ * @subpackage views
10
  */
11
 
12
  // Exit if accessed directly.
20
  * - Plugin Support
21
  * - Plugin Documentation
22
  *
23
+ * @package wsal
24
+ * @subpackage views
25
  */
26
  class WSAL_Views_Help extends WSAL_AbstractView {
27
 
41
 
42
  /**
43
  * Constructor.
44
+ *
45
+ * @param WpSecurityAuditLog $plugin Plugin instance.
46
  */
47
  public function __construct( $plugin ) {
48
  parent::__construct( $plugin );
56
  $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : false; // phpcs:ignore
57
 
58
  // Verify that the current page is WSAL settings page.
59
+ if ( empty( $page ) || $this->get_safe_view_name() !== $page ) {
60
  return;
61
  }
62
 
63
  // Tab links.
64
  $wsal_help_tabs = array(
65
+ 'help' => array(
66
+ 'name' => esc_html__( 'Help', 'wp-security-audit-log' ),
67
+ 'link' => $this->get_url(),
68
  'render' => array( $this, 'tab_help' ),
69
  'priority' => 10,
70
  ),
71
  );
72
 
73
+ if ( $this->plugin->settings()->current_user_can( 'edit' ) ) {
74
  $wsal_help_tabs['contact'] = array(
75
+ 'name' => esc_html__( 'Contact Us', 'wp-security-audit-log' ),
76
+ 'link' => add_query_arg( 'tab', 'contact', $this->get_url() ),
77
  'render' => array( $this, 'tab_contact_us' ),
78
  'priority' => 15,
79
  );
80
+
81
  $wsal_help_tabs['system-info'] = array(
82
+ 'name' => esc_html__( 'System Info', 'wp-security-audit-log' ),
83
+ 'link' => add_query_arg( 'tab', 'system-info', $this->get_url() ),
84
  'render' => array( $this, 'tab_system_info' ),
85
  'priority' => 20,
86
  );
112
  }
113
 
114
  /**
115
+ * {@inheritDoc}
116
  */
117
+ public function get_title() {
118
+ return esc_html__( 'Help', 'wp-security-audit-log' );
119
  }
120
 
121
  /**
122
+ * {@inheritDoc}
123
  */
124
+ public function get_icon() {
125
  return 'dashicons-sos';
126
  }
127
 
128
  /**
129
+ * {@inheritDoc}
130
  */
131
+ public function get_name() {
132
+ return esc_html__( 'Help & Contact Us', 'wp-security-audit-log' );
133
  }
134
 
135
  /**
136
+ * {@inheritDoc}
137
  */
138
+ public function get_weight() {
139
  return 10;
140
  }
141
 
142
  /**
143
+ * {@inheritDoc}
144
  */
145
+ public function header() {
146
  wp_enqueue_style(
147
  'extensions',
148
+ $this->plugin->get_base_url() . '/css/extensions.css',
149
  array(),
150
+ filemtime( $this->plugin->get_base_dir() . '/css/extensions.css' )
151
  );
152
  }
153
 
154
  /**
155
+ * {@inheritDoc}
156
  */
157
+ public function render() {
158
+ $can_current_user_edit = $this->plugin->settings()->current_user_can( 'edit' );
159
  ?>
160
  <nav id="wsal-tabs" class="nav-tab-wrapper">
161
  <?php
211
  <?php esc_html_e( 'Refer to the list of WordPress security events for a complete list of Events and IDs that the plugin uses to keep a log of all the changes in the WordPress activity log.', 'wp-security-audit-log' ); ?>
212
  </p><p>
213
  <a class="button" rel="noopener noreferrer" href="https://wpactivitylog.com/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=plugin+website" target="_blank"><?php esc_html_e( 'Plugin Website', 'wp-security-audit-log' ); ?></a>
 
214
  <a class="button" rel="noopener noreferrer" href="https://wpactivitylog.com/support/kb/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=knowledge+base" target="_blank"><?php esc_html_e( 'Knowledge Base', 'wp-security-audit-log' ); ?></a>
 
215
  <a class="button" rel="noopener noreferrer" href="https://wpactivitylog.com/support/kb/list-wordpress-activity-log-event-ids/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=list+events" target="_blank"><?php esc_html_e( 'List of activity logs event IDs', 'wp-security-audit-log' ); ?></a>
216
  </p>
217
  </div>
250
  left: 0 !important;
251
  }
252
  .fs-full-size-wrapper {
253
+ margin: 10px 20px 0 2px !important;
254
  }
255
  </style>
256
  <?php
257
  $freemius_id = wsal_freemius()->get_id();
258
+ $vars = array( 'id' => $freemius_id );
259
+ echo fs_get_template( 'contact.php', $vars ); // phpcs:ignore
260
  }
261
 
262
  /**
282
  $plugins_data = array(
283
  array(
284
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/help/wp-2fa-img.jpg',
285
+ 'desc' => esc_html__( 'Add an extra layer of security to your login pages with 2FA & require your users to use it.', 'wp-security-audit-log' ),
286
  'alt' => 'WP 2FA',
287
  'link' => 'https://wp2fa.io/?utm_source=plugin&utm_medium=referral&utm_campaign=WP2FA&utm_content=WSAL+banner',
288
  ),
289
  array(
290
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/help/c4wp.jpg',
291
+ 'desc' => esc_html__( 'Protect website forms & login pages from spambots & automated attacks.', 'wp-security-audit-log' ),
292
  'alt' => 'Captcha 4WP',
293
  'link' => 'https://www.wpwhitesecurity.com/wordpress-plugins/captcha-plugin-wordpress/?utm_source=plugin&utm_medium=referral&utm_campaign=WP2FA&utm_content=WSAL+banner',
294
  ),
295
  array(
296
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/help/password-policy-manager.jpg',
297
+ 'desc' => esc_html__( 'Enforce strong password policies on WordPress', 'wp-security-audit-log' ),
298
  'alt' => 'WPassword',
299
  'link' => 'https://www.wpwhitesecurity.com/wordpress-plugins/password-policy-manager-wordpress/?utm_source=plugin&utm_medium=referral&utm_campaign=PPMWP&utm_content=WSAL+banner',
300
  ),
301
  array(
302
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/help/website-file-changes-monitor.jpg',
303
+ 'desc' => esc_html__( 'Automatically identify unauthorized file changes on WordPress', 'wp-security-audit-log' ),
304
  'alt' => 'Website File Changes Monitor',
305
  'link' => 'https://www.wpwhitesecurity.com/wordpress-plugins/website-file-changes-monitor/?utm_source=plugin&utm_medium=referral&utm_campaign=WFCM&utm_content=WSAL+banner',
306
  ),
307
  array(
308
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/help/activity-log-for-mainwp.jpg',
309
+ 'desc' => esc_html__( 'See the child sites activity logs from the central MainWP dashboard', 'wp-security-audit-log' ),
310
  'alt' => 'Activity Log for MainWP',
311
  'link' => 'https://wpactivitylog.com/extensions/mainwp-activity-log/?utm_source=plugin&utm_medium=referral&utm_campaign=AL4MWP&utm_content=WSAL+banner',
312
  ),
337
  * Method: Get system information.
338
  *
339
  * @return string - System information.
 
340
  */
341
  public function get_sysinfo() {
342
  // System info.
361
 
362
  // Get theme info.
363
  $theme_data = wp_get_theme();
364
+ $theme = $theme_data->Name . ' ' . $theme_data->Version; // phpcs:ignore
365
+ $parent_theme = $theme_data->Template; // phpcs:ignore
366
  if ( ! empty( $parent_theme ) ) {
367
  $parent_theme_data = wp_get_theme( $parent_theme );
368
+ $parent_theme = $parent_theme_data->Name . ' ' . $parent_theme_data->Version; // phpcs:ignore
369
  }
370
 
371
  // Language information.
412
  // WordPress active plugins.
413
  $sysinfo .= "\n" . '-- WordPress Active Plugins --' . "\n\n";
414
 
415
+ $plugins = get_plugins();
416
+ $active_plugins = get_option( 'active_plugins', array() );
417
+ $can_use_freemius_premium_code = wsal_freemius()->can_use_premium_code();
418
  foreach ( $plugins as $plugin_path => $plugin ) {
419
+ if ( ! in_array( $plugin_path, $active_plugins ) ) { // phpcs:ignore
420
  continue;
421
  }
422
 
423
+ if ( 'WP Activity Log' === $plugin['Name'] && $can_use_freemius_premium_code ) {
 
 
 
424
  $update = ( array_key_exists( $plugin_path, $updates ) ) ? ' (needs update - ' . $updates[ $plugin_path ]->update->new_version . ')' : '';
425
  $sysinfo .= $plugin['Name'] . ' Premium: ' . $plugin['Version'] . $update . "\n";
426
  } else {
433
  $sysinfo .= "\n" . '-- WordPress Inactive Plugins --' . "\n\n";
434
 
435
  foreach ( $plugins as $plugin_path => $plugin ) {
436
+ if ( in_array( $plugin_path, $active_plugins ) ) { // phpcs:ignore
437
  continue;
438
  }
439
 
440
+ if ( 'WP Activity Log' === $plugin['Name'] && $can_use_freemius_premium_code ) {
 
 
 
441
  $update = ( array_key_exists( $plugin_path, $updates ) ) ? ' (needs update - ' . $updates[ $plugin_path ]->update->new_version . ')' : '';
442
  $sysinfo .= $plugin['Name'] . ' Premium: ' . $plugin['Version'] . $update . "\n";
443
  } else {
460
  continue;
461
  }
462
 
463
+ if ( 'WP Activity Log' === $plugin['Name'] && $can_use_freemius_premium_code ) {
 
 
 
464
  $update = ( array_key_exists( $plugin_path, $updates ) ) ? ' (needs update - ' . $updates[ $plugin_path ]->update->new_version . ')' : '';
465
  $plugin = get_plugin_data( $plugin_path );
466
  $sysinfo .= $plugin['Name'] . ' Premium: ' . $plugin['Version'] . $update . "\n";
496
 
497
  // WSAL options.
498
  $sysinfo .= "\n" . '-- WSAL Options --' . "\n\n";
499
+ $options = $this->plugin->settings()->get_plugin_settings();
500
 
501
  if ( ! empty( $options ) && is_array( $options ) ) {
502
  foreach ( $options as $option ) {
511
  }
512
 
513
  /**
514
+ * {@inheritDoc}
515
  */
516
+ public function footer() {
517
+ if ( 'system-info' === $this->current_tab && $this->plugin->settings()->current_user_can( 'edit' ) ) :
518
  ?>
519
  <script>
520
  /**
533
  element.style.display = 'none';
534
  document.body.appendChild(element);
535
 
536
+ // Simulate click on the element.
537
  element.click();
538
 
539
  // Remove temporary element.
classes/Views/LogInUsers.php CHANGED
@@ -4,8 +4,9 @@
4
  *
5
  * WSAL users sessions page.
6
  *
7
- * @since 1.0.0
8
- * @package wsal
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -17,54 +18,55 @@ if ( ! defined( 'ABSPATH' ) ) {
17
  * User Sessions Management Add-On promo Page.
18
  * Used only if the plugin is not activated.
19
  *
20
- * @package wsal
 
21
  */
22
  class WSAL_Views_LogInUsers extends WSAL_ExtensionPlaceholderView {
23
 
24
  /**
25
- * Method: Get View Title.
26
  */
27
- public function GetTitle() {
28
- return __( 'User Sessions Management Extension', 'wp-security-audit-log' );
29
  }
30
 
31
  /**
32
- * Method: Get View Name.
33
  */
34
- public function GetName() {
35
- return __( 'Logged In Users &#8682;', 'wp-security-audit-log' );
36
  }
37
 
38
  /**
39
- * Method: Get View Weight.
40
  */
41
- public function GetWeight() {
42
  return 7;
43
  }
44
 
45
  /**
46
- * Page View.
47
  */
48
- public function Render() {
49
- $title = __( 'Real-Time Users Sessions Management', 'wp-security-audit-log' );
50
- $description = __( 'Better manage your users’ logins and sessions. Upgrade to premium and:', 'wp-security-audit-log' );
51
- $addon_img = trailingslashit( WSAL_BASE_URL ) . 'img/' . $this->GetSafeViewName() . '.png';
52
  $subtext = false;
53
  $premium_list = array(
54
- __( 'See who is logged in to your site', 'wp-security-audit-log' ),
55
- __( 'When they logged in and from where', 'wp-security-audit-log' ),
56
- __( 'The last change they have done in real-time', 'wp-security-audit-log' ),
57
- __( 'Terminate any users’ session with a click of a button', 'wp-security-audit-log' ),
58
- __( 'Limit or block multiple sessions for the same user', 'wp-security-audit-log' ),
59
- __( 'Get alerted of multiple same user sessions', 'wp-security-audit-log' ),
60
  );
61
  $screenshots = array(
62
  array(
63
- 'desc' => __( 'See who is logged in to your WordPress site and multisite network in real-time.', 'wp-security-audit-log' ),
64
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/users-sessions-management/user_sessions_1.png',
65
  ),
66
  array(
67
- 'desc' => __( 'Limit, manage and block multiple same user sessions easily.', 'wp-security-audit-log' ),
68
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/users-sessions-management/user_sessions_2.png',
69
  ),
70
  );
4
  *
5
  * WSAL users sessions page.
6
  *
7
+ * @since 1.0.0
8
+ * @package wsal
9
+ * @subpackage views
10
  */
11
 
12
  // Exit if accessed directly.
18
  * User Sessions Management Add-On promo Page.
19
  * Used only if the plugin is not activated.
20
  *
21
+ * @package wsal
22
+ * @subpackage views
23
  */
24
  class WSAL_Views_LogInUsers extends WSAL_ExtensionPlaceholderView {
25
 
26
  /**
27
+ * {@inheritDoc}
28
  */
29
+ public function get_title() {
30
+ return esc_html__( 'User Sessions Management Extension', 'wp-security-audit-log' );
31
  }
32
 
33
  /**
34
+ * {@inheritDoc}
35
  */
36
+ public function get_name() {
37
+ return esc_html__( 'Logged In Users &#8682;', 'wp-security-audit-log' );
38
  }
39
 
40
  /**
41
+ * {@inheritDoc}
42
  */
43
+ public function get_weight() {
44
  return 7;
45
  }
46
 
47
  /**
48
+ * {@inheritDoc}
49
  */
50
+ public function render() {
51
+ $title = esc_html__( 'Real-Time Users Sessions Management', 'wp-security-audit-log' );
52
+ $description = esc_html__( 'Better manage your users’ logins and sessions. Upgrade to premium and:', 'wp-security-audit-log' );
53
+ $addon_img = trailingslashit( WSAL_BASE_URL ) . 'img/' . $this->get_safe_view_name() . '.png';
54
  $subtext = false;
55
  $premium_list = array(
56
+ esc_html__( 'See who is logged in to your site', 'wp-security-audit-log' ),
57
+ esc_html__( 'When they logged in and from where', 'wp-security-audit-log' ),
58
+ esc_html__( 'The last change they have done in real-time', 'wp-security-audit-log' ),
59
+ esc_html__( 'Terminate any users’ session with a click of a button', 'wp-security-audit-log' ),
60
+ esc_html__( 'Limit or block multiple sessions for the same user', 'wp-security-audit-log' ),
61
+ esc_html__( 'Get alerted of multiple same user sessions', 'wp-security-audit-log' ),
62
  );
63
  $screenshots = array(
64
  array(
65
+ 'desc' => esc_html__( 'See who is logged in to your WordPress site and multisite network in real-time.', 'wp-security-audit-log' ),
66
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/users-sessions-management/user_sessions_1.png',
67
  ),
68
  array(
69
+ 'desc' => esc_html__( 'Limit, manage and block multiple same user sessions easily.', 'wp-security-audit-log' ),
70
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/users-sessions-management/user_sessions_2.png',
71
  ),
72
  );
classes/Views/Reports.php CHANGED
@@ -4,8 +4,9 @@
4
  *
5
  * WSAL reports page.
6
  *
7
- * @since 1.0.0
8
- * @package wsal
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -17,56 +18,57 @@ if ( ! defined( 'ABSPATH' ) ) {
17
  * Reports Add-On promo Page.
18
  * Used only if the plugin is not activated.
19
  *
20
- * @package wsal
 
21
  */
22
  class WSAL_Views_Reports extends WSAL_ExtensionPlaceholderView {
23
 
24
  /**
25
- * Method: Get View Title.
26
  */
27
- public function GetTitle() {
28
- return __( 'Reports Extension', 'wp-security-audit-log' );
29
  }
30
 
31
  /**
32
- * Method: Get View Name.
33
  */
34
- public function GetName() {
35
- return __( 'Create Reports &#8682;', 'wp-security-audit-log' );
36
  }
37
 
38
  /**
39
- * Method: Get View Weight.
40
  */
41
- public function GetWeight() {
42
  return 3;
43
  }
44
 
45
  /**
46
  * Page View.
47
  */
48
- public function Render() {
49
- $title = __( 'Individual, Scheduled & Automated Reports', 'wp-security-audit-log' );
50
- $description = __( 'Many are not fans of reports, however reports are vital in business. With them you can make informed decisions that allow you to improve user productivity and the business. Upgrade to Premium so you can:', 'wp-security-audit-log' );
51
- $addon_img = trailingslashit( WSAL_BASE_URL ) . 'img/' . $this->GetSafeViewName() . '.jpg';
52
  $premium_list = array(
53
- __( 'Generate any type of user and site (in multisite) activity report', 'wp-security-audit-log' ),
54
- __( 'Automate and schedule daily, weekly, monthly and quarterly reports', 'wp-security-audit-log' ),
55
- __( 'Received reports automatically via email', 'wp-security-audit-log' ),
56
- __( 'Create statistics reports about users’ views, logins, activity from IP addresses & more', 'wp-security-audit-log' ),
57
  );
58
- $subtext = __( 'Reports are vital to the success of your business and management of your site.', 'wp-security-audit-log' );
59
  $screenshots = array(
60
  array(
61
- 'desc' => __( 'Generate a HTML or CSV report.', 'wp-security-audit-log' ),
62
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/reports/reports_1.png',
63
  ),
64
  array(
65
- 'desc' => __( 'Easily configure a criteria for your reports.', 'wp-security-audit-log' ),
66
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/reports/reports_2.png',
67
  ),
68
  array(
69
- 'desc' => __( 'Schedule reports that are sent to you by email automatically.', 'wp-security-audit-log' ),
70
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/reports/reports_3.png',
71
  ),
72
  );
4
  *
5
  * WSAL reports page.
6
  *
7
+ * @since 1.0.0
8
+ * @package wsal
9
+ * @subpackage views
10
  */
11
 
12
  // Exit if accessed directly.
18
  * Reports Add-On promo Page.
19
  * Used only if the plugin is not activated.
20
  *
21
+ * @package wsal
22
+ * @subpackage views
23
  */
24
  class WSAL_Views_Reports extends WSAL_ExtensionPlaceholderView {
25
 
26
  /**
27
+ * {@inheritDoc}
28
  */
29
+ public function get_title() {
30
+ return esc_html__( 'Reports Extension', 'wp-security-audit-log' );
31
  }
32
 
33
  /**
34
+ * {@inheritDoc}
35
  */
36
+ public function get_name() {
37
+ return esc_html__( 'Create Reports &#8682;', 'wp-security-audit-log' );
38
  }
39
 
40
  /**
41
+ * {@inheritDoc}
42
  */
43
+ public function get_weight() {
44
  return 3;
45
  }
46
 
47
  /**
48
  * Page View.
49
  */
50
+ public function render() {
51
+ $title = esc_html__( 'Individual, Scheduled & Automated Reports', 'wp-security-audit-log' );
52
+ $description = esc_html__( 'Many are not fans of reports, however reports are vital in business. With them you can make informed decisions that allow you to improve user productivity and the business. Upgrade to Premium so you can:', 'wp-security-audit-log' );
53
+ $addon_img = trailingslashit( WSAL_BASE_URL ) . 'img/' . $this->get_safe_view_name() . '.jpg';
54
  $premium_list = array(
55
+ esc_html__( 'Generate any type of user and site (in multisite) activity report', 'wp-security-audit-log' ),
56
+ esc_html__( 'Automate and schedule daily, weekly, monthly and quarterly reports', 'wp-security-audit-log' ),
57
+ esc_html__( 'Received reports automatically via email', 'wp-security-audit-log' ),
58
+ esc_html__( 'Create statistics reports about users’ views, logins, activity from IP addresses & more', 'wp-security-audit-log' ),
59
  );
60
+ $subtext = esc_html__( 'Reports are vital to the success of your business and management of your site.', 'wp-security-audit-log' );
61
  $screenshots = array(
62
  array(
63
+ 'desc' => esc_html__( 'Generate a HTML or CSV report.', 'wp-security-audit-log' ),
64
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/reports/reports_1.png',
65
  ),
66
  array(
67
+ 'desc' => esc_html__( 'Easily configure a criteria for your reports.', 'wp-security-audit-log' ),
68
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/reports/reports_2.png',
69
  ),
70
  array(
71
+ 'desc' => esc_html__( 'Schedule reports that are sent to you by email automatically.', 'wp-security-audit-log' ),
72
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/reports/reports_3.png',
73
  ),
74
  );
classes/Views/Search.php CHANGED
@@ -1,11 +1,10 @@
1
  <?php
2
  /**
3
- * View: Users Sessions Page
4
  *
5
- * WSAL users sessions page.
6
- *
7
- * @since 1.0.0
8
- * @package wsal
9
  */
10
 
11
  // Exit if accessed directly.
@@ -17,57 +16,58 @@ if ( ! defined( 'ABSPATH' ) ) {
17
  * Search Add-On promo Page.
18
  * Used only if the plugin is not activated.
19
  *
20
- * @package wsal
 
21
  */
22
  class WSAL_Views_Search extends WSAL_ExtensionPlaceholderView {
23
 
24
  /**
25
- * Method: Get View Title.
26
  */
27
- public function GetTitle() {
28
- return __( 'Search Extension', 'wp-security-audit-log' );
29
  }
30
 
31
  /**
32
- * Method: Get View Name.
33
  */
34
- public function GetName() {
35
- return __( 'Log Search &#8682;', 'wp-security-audit-log' );
36
  }
37
 
38
  /**
39
- * Method: Get View Weight.
40
  */
41
- public function GetWeight() {
42
  return 5;
43
  }
44
 
45
  /**
46
- * Page View.
47
  */
48
- public function Render() {
49
- $title = __( 'Search & Filters for the Activity Log', 'wp-security-audit-log' );
50
- $description = __( 'You can find all the information you want in the activity log, if you know what you are looking for and have the right tools. Upgrade to premium so you can:', 'wp-security-audit-log' );
51
- $addon_img = trailingslashit( WSAL_BASE_URL ) . 'img/' . $this->GetSafeViewName() . '.jpg';
52
  $premium_list = array(
53
- __( 'Do text searches and use filters to fine tune the search results', 'wp-security-audit-log' ),
54
- __( 'Easily find when and who did a specific change on your site', 'wp-security-audit-log' ),
55
- __( 'Easily identify and track back suspicious user behaviour', 'wp-security-audit-log' ),
56
- __( 'Search for the cause of a problem and ease troubleshooting', 'wp-security-audit-log' ),
57
- __( 'Save search terms and filters for future use and improved productivity', 'wp-security-audit-log' ),
58
  );
59
  $subtext = false;
60
  $screenshots = array(
61
  array(
62
- 'desc' => __( 'Use the text search to find a specific change.', 'wp-security-audit-log' ),
63
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/search/search_1.png',
64
  ),
65
  array(
66
- 'desc' => __( 'Configure any filter you need to fine tune the search results and find what you are looking for with much less effort.', 'wp-security-audit-log' ),
67
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/search/search_2.png',
68
  ),
69
  array(
70
- 'desc' => __( 'Save search terms and filters to run the searches again in the future with just a single click.', 'wp-security-audit-log' ),
71
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/search/search_3.png',
72
  ),
73
  );
1
  <?php
2
  /**
3
+ * View: Search Add-On promo Page
4
  *
5
+ * @since 1.0.0
6
+ * @package wsal
7
+ * @subpackage views
 
8
  */
9
 
10
  // Exit if accessed directly.
16
  * Search Add-On promo Page.
17
  * Used only if the plugin is not activated.
18
  *
19
+ * @package wsal
20
+ * @subpackage views
21
  */
22
  class WSAL_Views_Search extends WSAL_ExtensionPlaceholderView {
23
 
24
  /**
25
+ * {@inheritDoc}
26
  */
27
+ public function get_title() {
28
+ return esc_html__( 'Search Extension', 'wp-security-audit-log' );
29
  }
30
 
31
  /**
32
+ * {@inheritDoc}
33
  */
34
+ public function get_name() {
35
+ return esc_html__( 'Log Search &#8682;', 'wp-security-audit-log' );
36
  }
37
 
38
  /**
39
+ * {@inheritDoc}
40
  */
41
+ public function get_weight() {
42
  return 5;
43
  }
44
 
45
  /**
46
+ * {@inheritDoc}
47
  */
48
+ public function render() {
49
+ $title = esc_html__( 'Search & Filters for the Activity Log', 'wp-security-audit-log' );
50
+ $description = esc_html__( 'You can find all the information you want in the activity log, if you know what you are looking for and have the right tools. Upgrade to premium so you can:', 'wp-security-audit-log' );
51
+ $addon_img = trailingslashit( WSAL_BASE_URL ) . 'img/' . $this->get_safe_view_name() . '.jpg';
52
  $premium_list = array(
53
+ esc_html__( 'Do text searches and use filters to fine tune the search results', 'wp-security-audit-log' ),
54
+ esc_html__( 'Easily find when and who did a specific change on your site', 'wp-security-audit-log' ),
55
+ esc_html__( 'Easily identify and track back suspicious user behaviour', 'wp-security-audit-log' ),
56
+ esc_html__( 'Search for the cause of a problem and ease troubleshooting', 'wp-security-audit-log' ),
57
+ esc_html__( 'Save search terms and filters for future use and improved productivity', 'wp-security-audit-log' ),
58
  );
59
  $subtext = false;
60
  $screenshots = array(
61
  array(
62
+ 'desc' => esc_html__( 'Use the text search to find a specific change.', 'wp-security-audit-log' ),
63
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/search/search_1.png',
64
  ),
65
  array(
66
+ 'desc' => esc_html__( 'Configure any filter you need to fine tune the search results and find what you are looking for with much less effort.', 'wp-security-audit-log' ),
67
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/search/search_2.png',
68
  ),
69
  array(
70
+ 'desc' => esc_html__( 'Save search terms and filters to run the searches again in the future with just a single click.', 'wp-security-audit-log' ),
71
  'img' => trailingslashit( WSAL_BASE_URL ) . 'img/search/search_3.png',
72
  ),
73
  );
classes/Views/Settings.php CHANGED
@@ -4,8 +4,9 @@
4
  *
5
  * Settings page of the plugin.
6
  *
7
- * @since 1.0.0
8
- * @package wsal
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -18,7 +19,10 @@ if ( ! defined( 'ABSPATH' ) ) {
18
  *
19
  * Settings view class to handle settings page functions.
20
  *
21
- * @since 1.0.0
 
 
 
22
  */
23
  class WSAL_Views_Settings extends WSAL_AbstractView {
24
 
@@ -55,11 +59,11 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
55
  public function __construct( WpSecurityAuditLog $plugin ) {
56
  parent::__construct( $plugin );
57
  add_action( 'admin_init', array( $this, 'setup_settings_tabs' ) );
58
- add_action( 'wp_ajax_AjaxCheckSecurityToken', array( $this, 'AjaxCheckSecurityToken' ) );
59
- add_action( 'wp_ajax_AjaxRunCleanup', array( $this, 'AjaxRunCleanup' ) );
60
- add_action( 'wp_ajax_AjaxGetAllUsers', array( $this, 'AjaxGetAllUsers' ) );
61
- add_action( 'wp_ajax_AjaxGetAllRoles', array( $this, 'AjaxGetAllRoles' ) );
62
- add_action( 'wp_ajax_AjaxGetAllCPT', array( $this, 'AjaxGetAllCPT' ) );
63
  add_action( 'wp_ajax_wsal_reset_settings', array( $this, 'reset_settings' ) );
64
  add_action( 'wp_ajax_wsal_purge_activity', array( $this, 'purge_activity' ) );
65
  add_action( 'wp_ajax_wsal_ajax_get_all_severities', array( $this, 'ajax_get_all_severities' ) );
@@ -74,47 +78,45 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
74
  * @since 3.4
75
  */
76
  public function setup_settings_tabs() {
77
- // @codingStandardsIgnoreStart
78
- $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : false;
79
- // @codingStandardsIgnoreEnd
80
 
81
  // Verify that the current page is WSAL settings page.
82
- if ( empty( $page ) || $this->GetSafeViewName() !== $page ) {
 
83
  return;
84
  }
85
 
86
  // Tab links.
87
  $wsal_setting_tabs = array(
88
  'general' => array(
89
- 'name' => __( 'General', 'wp-security-audit-log' ),
90
- 'link' => add_query_arg( 'tab', 'general', $this->GetUrl() ),
91
  'render' => array( $this, 'tab_general' ),
92
  'save' => array( $this, 'tab_general_save' ),
93
  'priority' => 10,
94
  ),
95
  'audit-log' => array(
96
- 'name' => __( 'Activity log viewer', 'wp-security-audit-log' ),
97
- 'link' => add_query_arg( 'tab', 'audit-log', $this->GetUrl() ),
98
  'render' => array( $this, 'tab_audit_log' ),
99
  'save' => array( $this, 'tab_audit_log_save' ),
100
  'priority' => 20,
101
  ),
102
  'file-changes' => array(
103
- 'name' => __( 'File changes', 'wp-security-audit-log' ),
104
- 'link' => add_query_arg( 'tab', 'file-changes', $this->GetUrl() ),
105
  'render' => array( $this, 'tab_file_changes' ),
106
  'priority' => 30,
107
  ),
108
  'exclude-objects' => array(
109
- 'name' => __( 'Exclude objects', 'wp-security-audit-log' ),
110
- 'link' => add_query_arg( 'tab', 'exclude-objects', $this->GetUrl() ),
111
  'render' => array( $this, 'tab_exclude_objects' ),
112
  'save' => array( $this, 'tab_exclude_objects_save' ),
113
  'priority' => 40,
114
  ),
115
  'advanced-settings' => array(
116
- 'name' => __( 'Advanced settings', 'wp-security-audit-log' ),
117
- 'link' => add_query_arg( 'tab', 'advanced-settings', $this->GetUrl() ),
118
  'render' => array( $this, 'tab_advanced_settings' ),
119
  'save' => array( $this, 'tab_advanced_settings_save' ),
120
  'priority' => 100,
@@ -152,37 +154,37 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
152
  }
153
 
154
  /**
155
- * Method: Plugin Shortcut.
156
  */
157
- public function HasPluginShortcutLink() {
158
  return true;
159
  }
160
 
161
  /**
162
- * Method: Get View Title.
163
  */
164
- public function GetTitle() {
165
- return __( 'Settings', 'wp-security-audit-log' );
166
  }
167
 
168
  /**
169
- * Method: Get View Icon.
170
  */
171
- public function GetIcon() {
172
  return 'dashicons-admin-generic';
173
  }
174
 
175
  /**
176
- * Method: Get View Name.
177
  */
178
- public function GetName() {
179
- return __( 'Settings', 'wp-security-audit-log' );
180
  }
181
 
182
  /**
183
- * Method: Get View Weight.
184
  */
185
- public function GetWeight() {
186
  return 8;
187
  }
188
 
@@ -191,8 +193,8 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
191
  *
192
  * @param string $token - Token type.
193
  */
194
- protected function GetTokenType( $token ) {
195
- return $this->_plugin->settings()->get_token_type( $token );
196
  }
197
 
198
  /**
@@ -200,9 +202,9 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
200
  *
201
  * @throws Exception - Unrecognized settings tab error.
202
  */
203
- protected function Save() {
204
  // Bail early if user does not have sufficient permissions to save.
205
- if ( ! $this->_plugin->settings()->CurrentUserCan( 'edit' ) ) {
206
  throw new Exception( esc_html__( 'Current user is not allowed to save settings.', 'wp-security-audit-log' ) );
207
  }
208
  // Call respective tab save functions if they are set. Nonce is already verified at this point.
@@ -216,8 +218,8 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
216
  /**
217
  * Method: Check security token.
218
  */
219
- public function AjaxCheckSecurityToken() {
220
- if ( ! $this->_plugin->settings()->CurrentUserCan( 'edit' ) ) {
221
  echo wp_json_encode(
222
  array(
223
  'success' => false,
@@ -256,7 +258,7 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
256
  array(
257
  'success' => true,
258
  'token' => $token,
259
- 'tokenType' => esc_html( $this->GetTokenType( $token ) ),
260
  )
261
  );
262
  die();
@@ -265,26 +267,26 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
265
  /**
266
  * Method: Run cleanup.
267
  */
268
- public function AjaxRunCleanup() {
269
- if ( ! $this->_plugin->settings()->CurrentUserCan( 'edit' ) ) {
270
  die( 'Access Denied.' );
271
  }
272
 
273
- $now = current_time( 'timestamp' ); // Current time.
274
- $max_sdate = $this->_plugin->settings()->GetPruningDate(); // Pruning date.
275
 
276
 
277
  // Calculate limit timestamp.
278
  $max_stamp = $now - ( strtotime( $max_sdate ) - $now );
279
 
280
  $query = new WSAL_Models_OccurrenceQuery();
281
- $query->addOrderBy( 'created_on', false ); // Descending order.
282
- $query->addCondition( 'created_on <= %s', intval( $max_stamp ) ); // Add limits of timestamp.
283
- $results = $query->getAdapter()->Execute( $query );
284
  $items = count( $results );
285
 
286
  if ( $items ) {
287
- $this->_plugin->CleanUp();
288
  }
289
 
290
  if ( $archiving ) {
@@ -306,21 +308,21 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
306
  'pruning' => 0,
307
  );
308
  }
309
- wp_safe_redirect( add_query_arg( $redirect_args, $this->GetUrl() ) );
310
  }
311
  exit;
312
  }
313
 
314
  /**
315
- * Method: Get View.
316
  */
317
- public function Render() {
318
  // Verify nonce if a form is submitted.
319
  if ( isset( $_POST['_wpnonce'] ) ) {
320
  check_admin_referer( 'wsal-settings' );
321
  }
322
 
323
- if ( ! $this->_plugin->settings()->CurrentUserCan( 'edit' ) ) {
324
  wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'wp-security-audit-log' ) );
325
  }
326
 
@@ -329,21 +331,23 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
329
 
330
  if ( isset( $_POST['submit'] ) ) {
331
  try {
332
- $this->Save(); // Save settings.
333
  if ( 'sms-provider' === $this->current_tab && $section && 'test' === $section ) :
334
  ?>
335
- <div class="updated">
336
- <p><?php esc_html_e( 'Message sent successfully.', 'wp-security-audit-log' ); ?></p>
337
- </div>
338
  <?php else : ?>
339
- <div class="updated">
340
- <p><?php esc_html_e( 'Settings have been saved.', 'wp-security-audit-log' ); ?></p>
341
- </div>
342
- <?php
343
  endif;
344
  } catch ( Exception $ex ) {
345
  ?>
346
- <div class="error"><p><?php esc_html_e( 'Error: ', 'wp-security-audit-log' ); ?><?php echo esc_html( $ex->getMessage() ); ?></p></div>
 
 
347
  <?php
348
  }
349
  }
@@ -354,34 +358,33 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
354
 
355
  if ( isset( $_GET['pruning'] ) && '1' === $_GET['pruning'] ) {
356
  ?>
357
- <div class="updated">
358
- <p><?php esc_html_e( 'Old data successfully purged.', 'wp-security-audit-log' ); ?></p>
359
- </div>
360
  <?php
361
  } elseif ( isset( $_GET['pruning'] ) && '0' === $_GET['pruning'] ) {
362
  ?>
363
- <div class="error">
364
- <p><?php esc_html_e( 'No data is old enough to be purged.', 'wp-security-audit-log' ); ?></p>
365
- </div>
366
  <?php
367
  }
368
  ?>
369
- <nav id="wsal-tabs" class="nav-tab-wrapper">
370
  <?php foreach ( $this->wsal_setting_tabs as $tab_id => $tab ) : ?>
371
- <a href="<?php echo esc_url( $tab['link'] ); ?>" class="nav-tab <?php echo ( $tab_id === $this->current_tab ) ? 'nav-tab-active' : false; ?>">
372
  <?php echo esc_html( $tab['name'] ); ?>
373
- </a>
374
  <?php endforeach; ?>
375
- </nav>
376
 
377
- <form id="audit-log-settings" method="post">
378
- <input type="hidden" name="page" value="<?php echo isset( $_GET['page'] ) ? esc_attr( sanitize_text_field( wp_unslash( $_GET['page'] ) ) ) : false; ?>" />
379
- <input type="hidden" id="ajaxurl" value="<?php echo esc_attr( admin_url( 'admin-ajax.php' ) ); ?>" />
380
  <?php wp_nonce_field( 'wsal-settings' ); ?>
381
 
382
- <div id="audit-log-adverts">
383
- </div>
384
- <div class="nav-tabs">
385
  <?php
386
  if ( ! empty( $this->current_tab ) && ! empty( $this->wsal_setting_tabs[ $this->current_tab ]['render'] ) ) {
387
  call_user_func( $this->wsal_setting_tabs[ $this->current_tab ]['render'] );
@@ -389,15 +392,16 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
389
  call_user_func( $this->wsal_setting_tabs['general']['render'] );
390
  }
391
  ?>
392
- </div>
393
  <?php
394
  if ( 'sms-provider' === $this->current_tab && $section && 'test' === $section ) {
395
- submit_button( __( 'Send Message', 'wp-security-audit-log' ) );
396
  } else {
397
  submit_button();
398
  }
399
  ?>
400
- </form>
 
401
  <script type="text/javascript">
402
  <!--
403
  function delete_confirm(elementRef) {
@@ -439,19 +443,20 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
439
  } );
440
  // --></script>
441
  <?php
 
442
  }
443
 
444
  /**
445
  * Tab: `General`
446
  */
447
  private function tab_general() {
448
- $settings = $this->_plugin->settings();
449
- $enforced_settings = $settings->get_mainwp_enforced_settings();
450
- $login_page_notification_settings_enforced_by_mainwp = array_key_exists('login_notification_enabled', $enforced_settings);
451
- $incognito_setting_enforced_by_mainwp = array_key_exists('incognito_mode_enabled', $enforced_settings);
452
  ?>
453
- <h3><?php esc_html_e( 'Use infinite scroll or pagination for the event viewer?', 'wp-security-audit-log' ); ?></h3>
454
- <p class="description">
455
  <?php
456
  echo sprintf(
457
  /* translators: Learn more link. */
@@ -459,156 +464,156 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
459
  '<a href="https://wpactivitylog.com/features/search-filters-wordpress-activity-log/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=settings+pages" target="_blank">' . esc_html__( '(Premium feature)', 'wp-security-audit-log' ) . '</a>'
460
  );
461
  ?>
462
- </p>
463
- <table class="form-table wsal-tab">
464
- <tbody>
465
- <tr>
466
- <th><label for="infinite-scroll"><?php esc_html_e( 'Select event viewer view type:', 'wp-security-audit-log' ); ?></label></th>
467
- <td>
468
- <fieldset>
469
- <label for="infinite-scroll">
470
- <input type="radio" name="events-type-nav" value="infinite-scroll" id="infinite-scroll" <?php checked( $this->_plugin->settings()->get_events_type_nav(), 'infinite-scroll' ); ?> />
471
  <?php esc_html_e( 'Infinite Scroll (Recommended)', 'wp-security-audit-log' ); ?>
472
- </label>
473
- <br/>
474
- <label for="pagination">
475
- <input type="radio" name="events-type-nav" value="pagination" id="pagination" <?php checked( $this->_plugin->settings()->get_events_type_nav(), 'pagination' ); ?> />
476
  <?php esc_html_e( 'Pagination', 'wp-security-audit-log' ); ?>
477
- </label>
478
- <br />
479
- </fieldset>
480
- </td>
481
- </tr>
482
- <!-- / Reverse Proxy / Firewall Options -->
483
- </tbody>
484
- </table>
485
- <!-- Events Navigation Type -->
486
-
487
- <h3><?php esc_html_e( 'Do you want the activity log viewer to auto refresh?', 'wp-security-audit-log' ); ?></h3>
488
- <p class="description"><?php esc_html_e( 'The activity log viewer auto refreshes every 30 seconds when opened so you can see the latest events as they happen almost in real time.', 'wp-security-audit-log' ); ?></p>
489
- <table class="form-table wsal-tab">
490
- <tbody>
491
- <tr>
492
- <th><label for="aroption_on"><?php esc_html_e( 'Refresh activity log viewer', 'wp-security-audit-log' ); ?></label></th>
493
- <td>
494
- <fieldset>
495
- <?php $are = $this->_plugin->settings()->IsRefreshAlertsEnabled(); ?>
496
- <label for="aroption_on">
497
- <input type="radio" name="EnableAuditViewRefresh" id="aroption_on" style="margin-top: -2px;" <?php checked( $are ); ?> value="1">
498
- <span><?php esc_html_e( 'Auto refresh', 'wp-security-audit-log' ); ?></span>
499
- </label>
500
- <br/>
501
- <label for="aroption_off">
502
- <input type="radio" name="EnableAuditViewRefresh" id="aroption_off" style="margin-top: -2px;" <?php checked( $are, false ); ?> value="0">
503
- <span><?php esc_html_e( 'Do not auto refresh', 'wp-security-audit-log' ); ?></span>
504
- </label>
505
- </fieldset>
506
- </td>
507
- </tr>
508
- <!-- Refresh activity log viewer -->
509
- </tbody>
510
- </table>
511
- <!-- Refresh activity log -->
512
-
513
- <h3><?php esc_html_e( 'Display latest events widget in Dashboard & Admin bar', 'wp-security-audit-log' ); ?></h3>
514
- <p class="description">
515
  <?php
516
  echo sprintf(
517
  /* translators: Max number of dashboard widget alerts. */
518
  esc_html__( 'The events widget displays the latest %d security events in the dashboard and the admin bar notification displays the latest event.', 'wp-security-audit-log' ),
519
- esc_html( $this->_plugin->settings()->GetDashboardWidgetMaxAlerts() )
520
  );
521
  ?>
522
- </p>
523
- <table class="form-table wsal-tab">
524
- <tbody>
525
- <tr>
526
- <th><label for="dwoption_on"><?php esc_html_e( 'Dashboard Widget', 'wp-security-audit-log' ); ?></label></th>
527
- <td>
528
- <fieldset>
529
- <?php $dwe = $this->_plugin->settings()->IsWidgetsEnabled(); ?>
530
- <label for="dwoption_on">
531
- <input type="radio" name="EnableDashboardWidgets" id="dwoption_on" style="margin-top: -2px;" <?php checked( $dwe ); ?> value="1">
532
- <span><?php esc_html_e( 'Yes', 'wp-security-audit-log' ); ?></span>
533
- </label>
534
- <br/>
535
- <label for="dwoption_off">
536
- <input type="radio" name="EnableDashboardWidgets" id="dwoption_off" style="margin-top: -2px;" <?php checked( $dwe, false ); ?> value="0">
537
- <span><?php esc_html_e( 'No', 'wp-security-audit-log' ); ?></span>
538
- </label>
539
- </fieldset>
540
- </td>
541
- </tr>
542
- <!-- / Events Dashboard Widget -->
543
-
544
- <tr>
545
  <?php
546
  $disabled = '';
547
- $label = __( 'Admin Bar Notification', 'wp-security-audit-log' );
548
  if ( wsal_freemius()->is_free_plan() ) {
549
  $disabled = 'disabled';
550
- $label = __( 'Admin Bar Notification (Premium)', 'wp-security-audit-log' );
551
  }
552
  ?>
553
- <th><label for="admin_bar_notif_on"><?php echo esc_html( $label ); ?></label></th>
554
- <td>
555
- <fieldset <?php echo esc_attr( $disabled ); ?>>
556
- <?php $abn = $this->_plugin->settings()->is_admin_bar_notif(); ?>
557
- <label for="admin_bar_notif_on">
558
- <input type="radio" name="admin_bar_notif" id="admin_bar_notif_on" style="margin-top: -2px;" <?php checked( $abn ); ?> value="1">
559
- <span><?php esc_html_e( 'Yes', 'wp-security-audit-log' ); ?></span>
560
- </label>
561
- <br/>
562
- <label for="admin_bar_notif_off">
563
- <input type="radio" name="admin_bar_notif" id="admin_bar_notif_off" style="margin-top: -2px;" <?php checked( $abn, false ); ?> value="0">
564
- <span><?php esc_html_e( 'No', 'wp-security-audit-log' ); ?></span>
565
- </label>
566
- </fieldset>
567
- </td>
568
- </tr>
569
- <!-- / Admin Bar Notification -->
570
-
571
- <tr>
572
  <?php
573
  $disabled = '';
574
- $label = __( 'Admin Bar Notification Updates', 'wp-security-audit-log' );
575
  if ( wsal_freemius()->is_free_plan() ) {
576
  $disabled = 'disabled';
577
- $label = __( 'Admin Bar Notification Updates (Premium)', 'wp-security-audit-log' );
578
  }
579
  ?>
580
- <th><label for="admin_bar_notif_refresh"><?php echo esc_html( $label ); ?></label></th>
581
- <td>
582
- <fieldset <?php echo esc_attr( $disabled ); ?>>
583
- <?php $abn_updates = $this->_plugin->settings()->get_admin_bar_notif_updates(); ?>
584
- <label for="admin_bar_notif_realtime">
585
- <input type="radio" name="admin_bar_notif_updates" id="admin_bar_notif_realtime" style="margin-top: -2px;" <?php checked( $abn_updates, 'real-time' ); ?> value="real-time">
586
- <span><?php esc_html_e( 'Update in near real time', 'wp-security-audit-log' ); ?></span>
587
- </label>
588
- <br/>
589
- <label for="admin_bar_notif_refresh">
590
- <input type="radio" name="admin_bar_notif_updates" id="admin_bar_notif_refresh" style="margin-top: -2px;" <?php checked( $abn_updates, 'page-refresh' ); ?> value="page-refresh">
591
- <span><?php esc_html_e( 'Update only on page refreshes', 'wp-security-audit-log' ); ?></span>
592
- </label>
593
- </fieldset>
594
- </td>
595
- </tr>
596
- <!-- / Admin Bar Notification Updates -->
597
- </tbody>
598
- </table>
599
- <!-- Dashboard Widget -->
600
-
601
- <h3><?php esc_html_e( 'Add user notification on the WordPress login page', 'wp-security-audit-log' ); ?></h3>
602
- <p class="description"><?php esc_html_e( 'Many compliance regulations (such as the GDPR) require website administrators to tell the users of their website that all the changes they do when logged in are being logged.', 'wp-security-audit-log' ); ?></p>
603
- <table class="form-table wsal-tab">
604
- <tbody>
605
- <tr>
606
- <th><label for="login_page_notification"><?php esc_html_e( 'Login Page Notification', 'wp-security-audit-log' ); ?></label></th>
607
- <td>
608
- <fieldset <?php echo disabled($login_page_notification_settings_enforced_by_mainwp); ?>>
609
  <?php
610
  // Get login page notification checkbox.
611
- $wsal_lpn = $this->_plugin->settings()->is_login_page_notification();
612
  if ( $wsal_lpn && 'true' === $wsal_lpn ) {
613
  // If option exists, value is true then set to true.
614
  $wsal_lpn = true;
@@ -620,16 +625,17 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
620
  $wsal_lpn = false;
621
  }
622
  ?>
623
- <label for="wsal_lpn_yes">
624
- <input type="radio" name="login_page_notification" id="wsal_lpn_yes" <?php checked( $wsal_lpn ); ?> value="true" />
625
  <?php esc_html_e( 'Yes', 'wp-security-audit-log' ); ?>
626
- </label>
627
- <br />
628
  <?php
629
  // Get login page notification text.
630
- $wsal_lpn_text = $this->_plugin->settings()->get_login_page_notification_text();
631
- $wsal_lpn_text_default = __( 'For security and auditing purposes, a record of all of your logged-in actions and changes within the WordPress dashboard will be recorded in an activity log with the <a href="https://wpactivitylog.com/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=settings+pages" target="_blank">WP Activity Log plugin</a>. The audit log also includes the IP address where you accessed this site from.', 'wp-security-audit-log' );
632
-
 
633
  // Allowed HTML tags for this setting.
634
  $allowed_tags = array(
635
  'a' => array(
@@ -638,32 +644,33 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
638
  'target' => array(),
639
  ),
640
  );
 
641
  ?>
642
- <textarea name="login_page_notification_text"
643
- id="login_page_notification_text"
644
- cols="60" rows="6"
645
  <?php echo ( $wsal_lpn ) ? false : 'disabled'; ?>
646
- ><?php echo ( $wsal_lpn_text ) ? wp_kses( $wsal_lpn_text, $allowed_tags ) : wp_kses( $wsal_lpn_text_default, $allowed_tags ); ?></textarea>
647
- <br/>
648
- <p class="description">
649
- <?php echo wp_kses( __( '<strong>Note: </strong>', 'wp-security-audit-log' ), $this->_plugin->allowed_html_tags ) . esc_html__( 'The only HTML code allowed in the login page notification is for links ( < a href >< /a > ).', 'wp-security-audit-log' ); ?>
650
- </p>
651
- <br />
652
-
653
- <label for="wsal_lpn_no">
654
- <input type="radio" name="login_page_notification" id="wsal_lpn_no" <?php checked( $wsal_lpn, false ); ?> value="false" />
655
  <?php esc_html_e( 'No', 'wp-security-audit-log' ); ?>
656
- </label>
657
- </fieldset>
658
- </td>
659
- </tr>
660
- <!-- / Login Page Notification -->
661
- </tbody>
662
- </table>
663
- <!-- Login Page Notification -->
664
-
665
- <h3><?php esc_html_e( 'Is your website running behind a firewall or reverse proxy?', 'wp-security-audit-log' ); ?></h3>
666
- <p class="description">
667
  <?php
668
  echo sprintf(
669
  /* translators: Learn more link. */
@@ -671,38 +678,38 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
671
  '<a href="https://wpactivitylog.com/support/kb/support-reverse-proxies-web-application-firewalls/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=settings+pages" target="_blank">' . esc_html__( 'learn more', 'wp-security-audit-log' ) . '</a>'
672
  );
673
  ?>
674
- </p>
675
- <table class="form-table wsal-tab">
676
- <tbody>
677
- <tr>
678
- <th><label for="pioption_on"><?php esc_html_e( 'Reverse Proxy / Firewall Options', 'wp-security-audit-log' ); ?></label></th>
679
- <td>
680
- <fieldset>
681
- <label for="enable_proxy_ip_capture_yes">
682
- <input type="radio" name="EnableProxyIpCapture" value="1" id="enable_proxy_ip_capture_yes" <?php checked( $this->_plugin->settings()->IsMainIPFromProxy() ); ?> />
683
  <?php esc_html_e( 'Yes', 'wp-security-audit-log' ); ?>
684
- </label>
685
- <br/>
686
- <label for="EnableIpFiltering">
687
- <input type="checkbox" name="EnableIpFiltering" value="1" id="EnableIpFiltering" <?php checked( $this->_plugin->settings()->IsInternalIPsFiltered() ); ?> />
688
  <?php esc_html_e( 'Filter internal IP addresses from the proxy headers. Enable this option only if you are are still seeing the internal IP addresses of the firewall or proxy.', 'wp-security-audit-log' ); ?>
689
- </label>
690
- <br/>
691
- <label for="enable_proxy_ip_capture_no">
692
- <input type="radio" name="EnableProxyIpCapture" value="0" id="enable_proxy_ip_capture_no" <?php checked( $this->_plugin->settings()->IsMainIPFromProxy(), false ); ?> />
693
  <?php esc_html_e( 'No', 'wp-security-audit-log' ); ?>
694
- </label>
695
- <br />
696
- </fieldset>
697
- </td>
698
- </tr>
699
- <!-- / Reverse Proxy / Firewall Options -->
700
- </tbody>
701
- </table>
702
- <!-- Reverse Proxy -->
703
-
704
- <h3><?php esc_html_e( 'Who can change the plugin settings?', 'wp-security-audit-log' ); ?></h3>
705
- <p class="description">
706
  <?php
707
  $allowed_tags = array(
708
  'a' => array(
@@ -712,60 +719,53 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
712
  );
713
  echo wp_kses(
714
  sprintf(
715
- /* translators: Learn more link. */
716
  esc_html__( 'By default only users with administrator role (single site) and super administrator role (multisite) can change the settings of the plugin. Though you can restrict the privileges to just your user - %s.', 'wp-security-audit-log' ),
717
  '<a href="https://wpactivitylog.com/support/kb/managing-wordpress-activity-log-plugin-privileges/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=settings+pages" target="_blank">' . __( 'learn more', 'wp-security-audit-log' ) . '</a>'
718
  ),
719
  $allowed_tags
720
  );
721
- $restrict_settings = $this->_plugin->settings()->get_restrict_plugin_setting();
722
  ?>
723
- </p>
724
- <table class="form-table wsal-tab">
725
- <tbody>
726
- <tr>
727
- <th><label for="RestrictAdmins"><?php esc_html_e( 'Restrict plugin access', 'wp-security-audit-log' ); ?></label></th>
728
- <td>
729
- <fieldset>
730
- <label for="only_me">
731
- <input type="radio" name="restrict-plugin-settings" id="only_me" value="only_me" <?php checked( $restrict_settings, 'only_me' ); ?> />
732
  <?php esc_html_e( 'Only me', 'wp-security-audit-log' ); ?>
733
- </label>
734
- <br/>
735
- <label for="only_admins">
736
- <input type="radio" name="restrict-plugin-settings" id="only_admins" value="only_admins" <?php checked( $restrict_settings, 'only_admins' ); ?> />
737
  <?php
738
- if ( $this->_plugin->IsMultisite() ) {
739
  esc_html_e( 'All superadmins', 'wp-security-audit-log' );
740
  } else {
741
  esc_html_e( 'All administrators', 'wp-security-audit-log' );
742
  }
743
  ?>
744
- </label>
745
- <br/>
746
- </fieldset>
747
- </td>
748
- </tr>
749
- <!-- / Restrict Plugin Access -->
750
- </tbody>
751
- </table>
752
- <!-- Restrict Plugin Access -->
753
-
754
- <h3><?php esc_html_e( 'Allow other users to view the activity log', 'wp-security-audit-log' ); ?></h3>
755
- <p class="description">
756
  <?php
757
- $allowed_tags = array(
758
- 'a' => array(
759
- 'href' => true,
760
- 'target' => true,
761
- ),
762
- );
763
- $is_multisite = $this->_plugin->IsMultisite();
764
- $section_label = '';
765
- if ($is_multisite) {
766
- $section_label = esc_html__('By default only super administrators and the child sites\' administrators can view the WordPress activity log. Though you can change this by using the setting below.', 'wp-security-audit-log');
767
  } else {
768
- $section_label = esc_html__('By default only users with administrator role can view the WordPress activity log. To allow someone who does not have an admin role to view the activity log, specify them in the below setting.', 'wp-security-audit-log');
769
  }
770
 
771
  echo wp_kses(
@@ -773,43 +773,42 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
773
  $allowed_tags
774
  );
775
  ?>
776
- </p>
777
- <?php if ( $is_multisite ): ?>
778
- <table class="form-table wsal-tab">
779
- <tbody>
780
- <tr>
781
- <th><?php esc_html_e( 'Can view events', 'wp-security-audit-log' ); ?></th>
782
- <td>
783
- <fieldset>
784
  <?php
785
- $restrict_settings = $this->_plugin->settings()->get_restrict_log_viewer();
786
  $viewer_restriction_options = array(
787
  'only_me' => __( 'Only me', 'wp-security-audit-log' ),
788
  'only_superadmins' => __( 'Super administators only', 'wp-security-audit-log' ),
789
  'only_admins' => __( 'Super administators and site administrators', 'wp-security-audit-log' ),
790
  );
791
  ?>
792
- <?php foreach ( $viewer_restriction_options as $option => $label ): ?>
793
- <label for="log_viewer_<?php echo $option; ?>">
794
- <?php $disabled = ('only_me' === $option && 'only_superadmins' === $restrict_settings); ?>
795
- <input type="radio" name="restrict-log-viewer" id="log_viewer_<?php echo $option; ?>" value="<?php echo $option; ?>" <?php checked( $restrict_settings, $option ); ?> <?php disabled( $disabled ); ?> />
796
  <?php echo esc_html( $label ); ?>
797
- </label>
798
- <br/>
799
  <?php endforeach; ?>
800
- </fieldset>
801
- </td>
802
- </tr>
803
- </tbody>
804
- </table>
805
- <p class="description"><?php esc_html_e('To allow someone who does not have an admin role to view the activity log, specify them in the below setting.', 'wp-security-audit-log'); ?></p>
806
  <?php endif; ?>
807
- <table class="form-table wsal-tab">
808
- <tbody>
809
-
810
  <tr>
811
- <?php $row_label = $is_multisite ? esc_html__( 'Can also view events', 'wp-security-audit-log' ) : esc_html__( 'Can view events', 'wp-security-audit-log' ); ?>
812
- <th><label for="ViewerQueryBox"><?php echo $row_label; ?></label></th>
813
  <td>
814
  <fieldset>
815
  <label>
@@ -823,12 +822,12 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
823
 
824
  <div id="ViewerList">
825
  <?php
826
- foreach ( $this->_plugin->settings()->GetAllowedPluginViewers() as $item ) :
827
  if ( wp_get_current_user()->user_login === $item ) {
828
  continue;
829
  }
830
  ?>
831
- <span class="sectoken-<?php echo esc_attr( $this->GetTokenType( $item ) ); ?>">
832
  <input type="hidden" name="Viewers[]" value="<?php echo esc_attr( $item ); ?>"/>
833
  <?php echo esc_html( $item ); ?>
834
  <a href="javascript:;" title="<?php esc_attr_e( 'Remove', 'wp-security-audit-log' ); ?>">&times;</a>
@@ -851,7 +850,7 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
851
  <th><label for="FromEmail"><?php esc_html_e( 'From Email & Name', 'wp-security-audit-log' ); ?></label></th>
852
  <td>
853
  <fieldset>
854
- <?php $use_email = $this->_plugin->GetGlobalSetting( 'use-email', 'default_email' ); ?>
855
  <label for="default_email">
856
  <input type="radio" name="use-email" id="default_email" value="default_email" <?php checked( $use_email, 'default_email' ); ?> />
857
  <?php esc_html_e( 'Use the email address from the WordPress general settings', 'wp-security-audit-log' ); ?>
@@ -864,12 +863,12 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
864
  <br>
865
  <label for="FromEmail">
866
  <?php esc_html_e( 'Email Address', 'wp-security-audit-log' ); ?>
867
- <input type="email" id="FromEmail" name="FromEmail" value="<?php echo esc_attr( $this->_plugin->settings()->GetFromEmail() ); ?>" />
868
  </label>
869
  <br>
870
  <label for="DisplayName">
871
  <?php esc_html_e( 'Display Name', 'wp-security-audit-log' ); ?>&nbsp;
872
- <input type="text" id="DisplayName" name="DisplayName" value="<?php echo esc_attr( $this->_plugin->settings()->GetDisplayName() ); ?>" />
873
  </label>
874
  </fieldset>
875
  </td>
@@ -879,6 +878,9 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
879
  </table>
880
  <!-- From Email & Name -->
881
 
 
 
 
882
  <h3><?php esc_html_e( 'Do you want to hide the plugin from the list of installed plugins?', 'wp-security-audit-log' ); ?></h3>
883
  <p class="description"><?php esc_html_e( 'By default all installed plugins are listed in the plugins page. Set this option to Yes remove WP Activity Log from the list of installed plugins for users who are unable to access the WP Activity Log settings.', 'wp-security-audit-log' ); ?></p>
884
  <table class="form-table wsal-tab">
@@ -886,14 +888,14 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
886
  <tr>
887
  <th><label for="incognito_yes"><?php esc_html_e( 'Hide Plugin in Plugins Page', 'wp-security-audit-log' ); ?></label></th>
888
  <td>
889
- <fieldset <?php echo disabled( $incognito_setting_enforced_by_mainwp ); ?>>
890
  <label for="incognito_yes">
891
- <input type="radio" name="Incognito" value="yes" id="incognito_yes" <?php checked( $this->_plugin->settings()->IsIncognito() ); ?> />
892
  <?php esc_html_e( 'Yes, hide the plugin and any WP Activity Log plugin extensions from the list of installed plugins', 'wp-security-audit-log' ); ?>
893
  </label>
894
  <br/>
895
  <label for="incognito_no">
896
- <input type="radio" name="Incognito" value="no" id="incognito_no" <?php checked( $this->_plugin->settings()->IsIncognito(), false ); ?> />
897
  <?php esc_html_e( 'No, do not hide the plugin', 'wp-security-audit-log' ); ?>
898
  </label>
899
  </fieldset>
@@ -913,46 +915,45 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
913
  // Get $_POST global array.
914
  $post_array = filter_input_array( INPUT_POST );
915
 
916
- $this->_plugin->settings()->SetRefreshAlertsEnabled( $post_array['EnableAuditViewRefresh'] );
917
- $this->_plugin->settings()->set_events_type_nav( sanitize_text_field( $post_array['events-type-nav'] ) );
918
- $this->_plugin->settings()->set_use_email( sanitize_text_field( $post_array['use-email'] ) );
919
- $this->_plugin->settings()->SetFromEmail( sanitize_email( $post_array['FromEmail'] ) );
920
- $this->_plugin->settings()->SetDisplayName( sanitize_text_field( $post_array['DisplayName'] ) );
921
-
922
- $this->_plugin->settings()->SetWidgetsEnabled( sanitize_text_field( $post_array['EnableDashboardWidgets'] ) );
923
 
924
  if ( ! wsal_freemius()->is_free_plan() ) {
925
- $this->_plugin->settings()->set_admin_bar_notif( sanitize_text_field( $post_array['admin_bar_notif'] ) );
926
- $this->_plugin->settings()->set_admin_bar_notif_updates( sanitize_text_field( $post_array['admin_bar_notif_updates'] ) );
927
  }
928
 
929
- // handle log viewer settings in multisite context
930
- if ($this->_plugin->IsMultisite()) {
931
  $log_viewer_restrictions = isset( $post_array['restrict-log-viewer'] ) ? sanitize_text_field( $post_array['restrict-log-viewer'] ) : '';
932
- $this->_plugin->settings()->set_restrict_log_viewer($log_viewer_restrictions);
933
  if ( 'only_me' === $log_viewer_restrictions ) {
934
- $this->_plugin->settings()->set_only_me_user_id(get_current_user_id());
935
  }
936
  }
937
 
938
  // Get plugin viewers.
939
  $viewers = isset( $post_array['Viewers'] ) ? array_map( 'sanitize_text_field', $post_array['Viewers'] ) : array();
940
- $this->_plugin->settings()->SetAllowedPluginViewers( $viewers );
941
 
942
- // handle plugin settings permissions
943
  $restrict_settings = isset( $post_array['restrict-plugin-settings'] ) ? sanitize_text_field( $post_array['restrict-plugin-settings'] ) : false;
944
- $this->_plugin->settings()->set_restrict_plugin_setting( $restrict_settings );
945
  if ( 'only_me' === $restrict_settings ) {
946
- $this->_plugin->settings()->set_only_me_user_id(get_current_user_id());
947
  }
948
 
949
- $this->_plugin->settings()->set_login_page_notification( isset( $post_array['login_page_notification'] ) ? sanitize_text_field( $post_array['login_page_notification'] ) : false );
950
- $this->_plugin->settings()->set_login_page_notification_text( isset( $post_array['login_page_notification_text'] ) ? $post_array['login_page_notification_text'] : false );
951
- $this->_plugin->settings()->SetMainIPFromProxy( isset( $post_array['EnableProxyIpCapture'] ) ? sanitize_text_field( $post_array['EnableProxyIpCapture'] ) : false );
952
- $this->_plugin->settings()->SetInternalIPsFiltering( isset( $post_array['EnableIpFiltering'] ) ? sanitize_text_field( $post_array['EnableIpFiltering'] ) : false );
953
 
954
  $is_incognito = isset( $post_array['Incognito'] ) ? \WSAL\Helpers\Options::string_to_bool( sanitize_text_field( $post_array['Incognito'] ) ) : false;
955
- $this->_plugin->settings()->SetIncognito( $is_incognito );
956
  }
957
 
958
  /**
@@ -960,18 +961,18 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
960
  */
961
  private function tab_audit_log() {
962
  ?>
963
- <h3><?php esc_html_e( 'For how long do you want to keep the activity log events (Retention settings) ?', 'wp-security-audit-log' ); ?></h3>
964
- <p class="description">
965
  <?php
966
  esc_html_e( 'The plugin uses an efficient way to store the activity log data in the WordPress database, though the more data you keep the more disk space will be required. ', 'wp-security-audit-log' );
967
  $retention_help_text = __( '<a href="https://wpactivitylog.com/pricing/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=settings+pages" target="_blank">Upgrade to Premium</a> to store the activity log data in an external database.', 'wp-security-audit-log' );
968
 
969
- echo wp_kses( $retention_help_text, $this->_plugin->allowed_html_tags );
970
  ?>
971
- </p>
972
 
973
  <?php
974
- // Ensure it doesnt load a 2nd time for premium users.
975
  if ( ! wsal_freemius()->can_use_premium_code() ) {
976
  $this->render_retention_settings_table();
977
  }
@@ -986,7 +987,7 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
986
  <td>
987
  <fieldset>
988
  <?php
989
- $timezone = $this->_plugin->settings()->GetTimezone();
990
 
991
  /**
992
  * Transform timezone values.
@@ -1018,7 +1019,7 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1018
  <th><?php esc_html_e( 'Show Milliseconds', 'wp-security-audit-log' ); ?></th>
1019
  <td>
1020
  <fieldset>
1021
- <?php $show_milliseconds = $this->_plugin->settings()->get_show_milliseconds(); ?>
1022
  <label for="show_milliseconds">
1023
  <input type="checkbox" name="show_milliseconds" id="show_milliseconds" style="margin-top: -2px;"
1024
  <?php checked( $show_milliseconds ); ?> value="yes">
@@ -1040,7 +1041,7 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1040
  <th><label for="timezone-default"><?php esc_html_e( 'User information in Activity log', 'wp-security-audit-log' ); ?></label></th>
1041
  <td>
1042
  <fieldset>
1043
- <?php $type_username = $this->_plugin->settings()->get_type_username(); ?>
1044
  <label for="column_username">
1045
  <input type="radio" name="type_username" id="column_username" style="margin-top: -2px;" <?php checked( $type_username, 'username' ); ?> value="username">
1046
  <span><?php esc_html_e( 'WordPress username', 'wp-security-audit-log' ); ?></span>
@@ -1071,7 +1072,7 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1071
  <th><label for="columns"><?php esc_html_e( 'Activity log columns selection', 'wp-security-audit-log' ); ?></label></th>
1072
  <td>
1073
  <fieldset>
1074
- <?php $columns = $this->_plugin->settings()->GetColumns(); ?>
1075
  <?php foreach ( $columns as $key => $value ) { ?>
1076
  <label for="columns">
1077
  <input type="checkbox" name="Columns[<?php echo esc_attr( $key ); ?>]" id="<?php echo esc_attr( $key ); ?>" class="sel-columns" style="margin-top: -2px;"
@@ -1102,7 +1103,7 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1102
  </table>
1103
  <!-- Activity log columns -->
1104
 
1105
- <?php $is_wp_backend = $this->_plugin->settings()->IsWPBackend(); ?>
1106
  <h3><?php esc_html_e( 'Do you want to keep a log of WordPress background activity?', 'wp-security-audit-log' ); ?></h3>
1107
  <p class="description">
1108
  <?php esc_html_e( 'WordPress does a lot of things in the background that you do not necessarily need to know about, such as; deletion of post revisions, deletion of auto saved drafts etc. By default the plugin does not report them since there might be a lot and are irrelevant to the user.', 'wp-security-audit-log' ); ?>
@@ -1144,17 +1145,17 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1144
  $pruning_unit = isset( $post_array['pruning-unit'] ) ? sanitize_text_field( $post_array['pruning-unit'] ) : false;
1145
  $pruning_date = ( ! empty( $pruning_date ) && ! empty( $pruning_unit ) ) ? $pruning_date . ' ' . $pruning_unit : false;
1146
 
1147
- $this->_plugin->settings()->SetPruningDateEnabled( isset( $post_array['PruneBy'] ) ? 'date' === $post_array['PruneBy'] : '' );
1148
- $this->_plugin->settings()->SetPruningDate( $pruning_date );
1149
- $this->_plugin->settings()->set_pruning_unit( $pruning_unit );
1150
- $this->_plugin->settings()->SetTimezone( $post_array['Timezone'] );
1151
- $this->_plugin->settings()->set_type_username( $post_array['type_username'] );
1152
- $this->_plugin->settings()->SetWPBackend( isset( $post_array['WPBackend'] ) ? sanitize_text_field( $post_array['WPBackend'] ) : false );
1153
  if ( ! empty( $post_array['Columns'] ) ) {
1154
- $this->_plugin->settings()->SetColumns( $post_array['Columns'] );
1155
  }
1156
- $show_milliseconds = ( isset( $post_array['show_milliseconds'] ) && 'yes' === $post_array['show_milliseconds'] ) ? true : false;
1157
- $this->_plugin->settings()->set_show_milliseconds( $show_milliseconds );
1158
  }
1159
 
1160
  /**
@@ -1168,15 +1169,14 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1168
  <tr>
1169
  <?php if ( ! defined( 'WFCM_PLUGIN_FILE' ) ) : ?>
1170
  <div class="addon-wrapper" style="max-width: 380px; text-align: center; border: 1px solid #ccc; padding: 25px;">
1171
- <img src="<?php echo trailingslashit( WSAL_BASE_URL ) . 'img/help/website-file-changes-monitor.jpg'; ?>">
1172
  <h4><?php echo esc_html__( 'Website File Changes Monitor', 'wp-security-audit-log' ); ?></h4>
1173
  <p><?php echo esc_html__( 'To keep a log of file changes please install Website File Changes Monitor, a plugin which is also developed by us.', 'wp-security-audit-log' ); ?></p><br>
1174
- <p><button class="install-addon button button-primary" data-nonce="<?php echo esc_attr( wp_create_nonce( 'wsal-install-addon' ) ); ?>" data-plugin-slug="website-file-changes-monitor/website-file-changes-monitor.php" data-plugin-download-url="https://downloads.wordpress.org/plugin/website-file-changes-monitor.latest-stable.zip"><?php _e( 'Install plugin now', 'wp-security-audit-log' ); ?></button><span class="spinner" style="display: none; visibility: visible; float: none; margin: 0 0 0 8px;"></span> <a href="https://wpactivitylog.com/support/kb/wordpress-files-changes-warning-activity-logs/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=settings+pages" rel="noopener noreferrer" target="_blank" style="margin-left: 15px;"><?php echo esc_html__( 'Learn More', 'wp-security-audit-log' ); ?></a></p>
1175
  </div>
1176
  <?php else : ?>
1177
  <?php
1178
- $wcfm_settings_page = '';
1179
- $redirect_args = array(
1180
  'page' => 'wfcm-file-changes',
1181
  );
1182
  if ( ! is_multisite() ) {
@@ -1210,8 +1210,8 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1210
  <input type="button" id="ExUserQueryAdd" class="button-primary" value="<?php esc_attr_e( 'Add', 'wp-security-audit-log' ); ?>">
1211
  <br style="clear: both;"/>
1212
  <div id="ExUserList">
1213
- <?php foreach ( $this->_plugin->settings()->GetExcludedMonitoringUsers() as $item ) : ?>
1214
- <span class="sectoken-<?php echo esc_attr( $this->GetTokenType( $item ) ); ?>">
1215
  <input type="hidden" name="ExUsers[]" value="<?php echo esc_attr( $item ); ?>"/>
1216
  <?php echo esc_html( $item ); ?>
1217
  <a href="javascript:;" title="<?php esc_attr_e( 'Remove', 'wp-security-audit-log' ); ?>">&times;</a>
@@ -1231,8 +1231,8 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1231
  <input type="button" id="ExRoleQueryAdd" class="button-primary" value="<?php esc_attr_e( 'Add', 'wp-security-audit-log' ); ?>">
1232
  <br style="clear: both;"/>
1233
  <div id="ExRoleList">
1234
- <?php foreach ( $this->_plugin->settings()->GetExcludedMonitoringRoles() as $item ) : ?>
1235
- <span class="sectoken-<?php echo esc_attr( $this->GetTokenType( $item ) ); ?>">
1236
  <input type="hidden" name="ExRoles[]" value="<?php echo esc_attr( $item ); ?>"/>
1237
  <?php echo esc_html( $item ); ?>
1238
  <a href="javascript:;" title="<?php esc_attr_e( 'Remove', 'wp-security-audit-log' ); ?>">&times;</a>
@@ -1252,89 +1252,100 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1252
  <input type="button" id="IpAddrQueryAdd" class="button-primary" value="<?php esc_attr_e( 'Add', 'wp-security-audit-log' ); ?>">
1253
  <br style="clear: both;"/>
1254
  <div id="IpAddrList">
1255
- <?php foreach ( $this->_plugin->settings()->GetExcludedMonitoringIP() as $item ) : ?>
1256
- <span class="sectoken-<?php echo esc_attr( $this->GetTokenType( $item ) ); ?>">
1257
  <input type="hidden" name="IpAddrs[]" value="<?php echo esc_attr( $item ); ?>"/>
1258
  <?php echo esc_html( $item ); ?>
1259
  <a href="javascript:;" title="<?php esc_attr_e( 'Remove', 'wp-security-audit-log' ); ?>">&times;</a>
1260
  </span>
1261
  <?php endforeach; ?>
1262
- </div>
1263
- </fieldset>
1264
- <p class="description"><?php esc_html_e( 'You can exclude an individual IP address or a range of IP addresses. To exclude a range use the following format: [first IP]-[last octet of the last IP]. Example: 172.16.180.6-127.', 'wp-security-audit-log' ); ?></p>
1265
- </td>
1266
- </tr>
1267
- <!-- Exclude IP Addresses -->
1268
-
1269
- <tr>
1270
- <th><label for="ExCPTsQueryBox"><?php esc_html_e( 'Exclude Post Type:', 'wp-security-audit-log' ); ?></label></th>
1271
- <td>
1272
- <fieldset>
1273
- <input type="text" id="ExCPTsQueryBox" style="width: 250px;">
1274
- <input type="button" id="ExCPTsQueryAdd" class="button-primary" value="<?php esc_attr_e( 'Add', 'wp-security-audit-log' ); ?>">
1275
- <br style="clear: both;"/>
1276
- <div id="ExCPTsList">
1277
- <?php foreach ( $this->_plugin->settings()->get_excluded_post_types() as $item ) : ?>
1278
- <span class="sectoken-<?php echo esc_attr( $this->GetTokenType( $item ) ); ?>">
1279
  <input type="hidden" name="ExCPTss[]" value="<?php echo esc_attr( $item ); ?>"/>
1280
  <?php echo esc_html( $item ); ?>
1281
  <a href="javascript:;" title="<?php esc_attr_e( 'Remove', 'wp-security-audit-log' ); ?>">&times;</a>
1282
  </span>
1283
  <?php endforeach; ?>
1284
- </div>
1285
- </fieldset>
1286
- <p class="description"><?php esc_html_e( 'WordPress has the post and page post types by default though your website might use more post types (custom post types). You can exclude all post types, including the default WordPress ones.', 'wp-security-audit-log' ); ?></p>
1287
- </td>
1288
- </tr>
1289
- <!-- Exclude Custom Post Types -->
1290
-
1291
- <?php
1292
- $this->renderMetaExclusionSection(
1293
- esc_html__( 'Exclude custom post fields:', 'wp-security-audit-log' ),
1294
- $this->_plugin->settings()->GetExcludedPostMetaFields(),
1295
- 'PostMeta'
1296
- );
1297
- ?><!-- Exclude Custom Post Fields -->
 
1298
 
1299
  <?php
1300
  $this->renderMetaExclusionSection(
1301
  esc_html__( 'Exclude custom user fields:', 'wp-security-audit-log' ),
1302
- $this->_plugin->settings()->GetExcludedUserMetaFields(),
1303
  'UserMeta'
1304
  );
1305
- ?><!-- Exclude Custom User Fields -->
 
1306
 
1307
- </tbody>
1308
- </table>
1309
- <!-- / Exclude Objects Tab -->
1310
  <?php
1311
  }
1312
 
 
 
 
 
 
 
 
1313
  private function renderMetaExclusionSection( $title, $values, $type ) {
 
1314
  ?>
1315
- <tr>
1316
- <th><label for="Custom<?php echo $type; ?>QueryBox"><?php echo $title; ?></label></th>
1317
- <td>
1318
- <fieldset data-type="<?php echo $type; ?>">
1319
- <input type="text" id="<?php echo $type; ?>QueryBox" class="js-query-box" style="width: 250px;">
1320
- <input type="button" id="<?php echo $type; ?>QueryAdd" class="js-query-add button-primary"
1321
- value="<?php esc_attr_e( 'Add', 'wp-security-audit-log' ); ?>">
1322
- <br style="clear: both;"/>
1323
- <div id="<?php echo $type; ?>List" class="js-list">
1324
  <?php foreach ( $values as $item ) : ?>
1325
- <span class="sectoken-<?php echo esc_attr( $this->GetTokenType( $item ) ); ?>">
1326
  <input type="hidden" name="<?php echo $type; ?>s[]"
1327
- value="<?php echo esc_attr( $item ); ?>"/>
1328
  <?php echo esc_html( $item ); ?>
1329
  <a href="javascript:;" title="<?php esc_attr_e( 'Remove', 'wp-security-audit-log' ); ?>">&times;</a>
1330
  </span>
1331
  <?php endforeach; ?>
1332
- </div>
1333
- </fieldset>
1334
- <p class="description"><?php esc_html_e( 'You can use the * wildcard to exclude multiple matching custom fields. For example to exclude all custom fields starting with wp123 enter wp123*', 'wp-security-audit-log' ); ?></p>
1335
- </td>
1336
- </tr>
1337
  <?php
 
1338
  }
1339
 
1340
  /**
@@ -1344,12 +1355,12 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1344
  // Get $_POST global array.
1345
  $post_array = filter_input_array( INPUT_POST );
1346
 
1347
- $this->_plugin->settings()->SetExcludedMonitoringUsers( isset( $post_array['ExUsers'] ) ? $post_array['ExUsers'] : array() );
1348
- $this->_plugin->settings()->SetExcludedMonitoringRoles( isset( $post_array['ExRoles'] ) ? $post_array['ExRoles'] : array() );
1349
- $this->_plugin->settings()->SetExcludedPostMetaFields( isset( $post_array['PostMetas'] ) ? $post_array['PostMetas'] : array() );
1350
- $this->_plugin->settings()->SetExcludedUserMetaFields( isset( $post_array['UserMetas'] ) ? $post_array['UserMetas'] : array() );
1351
- $this->_plugin->settings()->SetExcludedMonitoringIP( isset( $post_array['IpAddrs'] ) ? $post_array['IpAddrs'] : array() );
1352
- $this->_plugin->settings()->set_excluded_post_types( isset( $post_array['ExCPTss'] ) ? $post_array['ExCPTss'] : array() );
1353
  }
1354
 
1355
  /**
@@ -1357,23 +1368,23 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1357
  */
1358
  private function tab_advanced_settings() {
1359
  ?>
1360
- <p class="description">
1361
  <?php esc_html_e( 'These settings are for advanced users.', 'wp-security-audit-log' ); ?>
1362
- <?php echo sprintf( __( 'If you have any questions <a href="https://wpactivitylog.com/contact/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=settings+pages" target="_blank">contact us</a>.', 'wp-security-audit-log' ), $this->_plugin->allowed_html_tags ); ?>
1363
  </p>
1364
 
1365
- <h3><?php esc_html_e( 'Reset plugin settings to default', 'wp-security-audit-log' ); ?></h3>
1366
- <p class="description"><?php _e( 'Use this button to <em>factory reset</em> the plugin. This means that all the configured settings will be reset to default and all email notifications, scheduled reports, external database / third party services connections, archiving and mirroring rule will be deleted. NOTE: the activity log data will not be purged. Use the setting below to purge the activity log.', 'wp-security-audit-log' ); ?></p>
1367
- <table class="form-table wsal-tab">
1368
- <tbody>
1369
- <tr>
1370
- <th><?php esc_html_e( 'Reset Settings', 'wp-security-audit-log' ); ?></th>
1371
- <td>
1372
- <a href="#wsal_reset_settings" class="button-primary js-settings-reset"><?php esc_html_e( 'RESET', 'wp-security-audit-log' ); ?></a>
1373
- </td>
1374
- </tr>
1375
- </tbody>
1376
- </table>
1377
 
1378
  <h3><?php esc_html_e( 'Purge the WordPress activity log', 'wp-security-audit-log' ); ?></h3>
1379
  <p class="description"><?php esc_html_e( 'Click the Purge button below to delete all the data from the WordPress activity log and start afresh.', 'wp-security-audit-log' ); ?></p>
@@ -1388,7 +1399,7 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1388
  </tbody>
1389
  </table>
1390
 
1391
- <?php $stealth_mode = $this->_plugin->settings()->is_stealth_mode(); ?>
1392
  <h3><?php esc_html_e( 'MainWP Child Site Stealth Mode', 'wp-security-audit-log' ); ?></h3>
1393
  <p class="description"><?php esc_html_e( 'This option is enabled automatically when the plugin detects the MainWP Child plugin on the site. When this setting is enabled plugin access is restricted to the administrator who installs the plugin, the plugin is not shown in the list of installed plugins and no admin notifications are shown. Disable this option to change the plugin to the default setup.', 'wp-security-audit-log' ); ?></p>
1394
  <table class="form-table wsal-tab">
@@ -1412,7 +1423,7 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1412
  </td>
1413
  </tr>
1414
  <!-- / MainWP Child Site Stealth Mode -->
1415
- <?php $admin_blocking_plugins_support = $this->_plugin->settings()->get_admin_blocking_plugin_support(); ?>
1416
  <tr>
1417
  <th>
1418
  <label for="mwp_admin_blocking_support"><?php esc_html_e( 'Admin blocking plugins support', 'wp-security-audit-log' ); ?></label>
@@ -1431,6 +1442,9 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1431
  </tbody>
1432
  </table>
1433
 
 
 
 
1434
  <h3><?php esc_html_e( 'Do you want to delete the plugin data from the database upon uninstall?', 'wp-security-audit-log' ); ?></h3>
1435
  <p class="description"><?php esc_html_e( 'The plugin saves the activity log data and settings in the WordPress database. By default upon uninstalling the plugin the data is kept in the database so if it is installed again, you can still access the data. If the data is deleted it is not possible to recover it so you won\'t be able to access it again even when you reinstall the plugin.', 'wp-security-audit-log' ); ?></p>
1436
  <table class="form-table wsal-tab">
@@ -1441,14 +1455,14 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1441
  <fieldset>
1442
  <label for="delete_data_yes">
1443
  <input type="radio" name="DeleteData" value="1" id="delete_data_yes" onclick="return delete_confirm(this);"
1444
- <?php checked( $this->_plugin->settings()->IsDeleteData() ); ?>
1445
  />
1446
  <?php esc_html_e( 'Yes', 'wp-security-audit-log' ); ?>
1447
  </label>
1448
  <br>
1449
  <label for="delete_data_no">
1450
  <input type="radio" name="DeleteData" value="0" id="delete_data_no"
1451
- <?php checked( $this->_plugin->settings()->IsDeleteData(), false ); ?>
1452
  />
1453
  <?php esc_html_e( 'No', 'wp-security-audit-log' ); ?>
1454
  </label>
@@ -1459,15 +1473,15 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1459
  </tbody>
1460
  </table>
1461
 
1462
- <div class="remodal" data-remodal-id="wsal_reset_settings">
1463
- <button data-remodal-action="close" class="remodal-close"></button>
1464
- <h3><?php esc_html_e( 'Are you sure you want to reset all the plugin settings to default? This action cannot be undone.', 'wp-security-audit-log' ); ?></h3>
1465
- <br>
1466
- <input type="hidden" id="wsal-reset-settings-nonce" value="<?php echo esc_attr( wp_create_nonce( 'wsal-reset-settings' ) ); ?>">
1467
- <button data-remodal-action="confirm" class="remodal-confirm"><?php esc_html_e( 'Yes' ); ?></button>
1468
- <button data-remodal-action="cancel" class="remodal-cancel"><?php esc_html_e( 'No' ); ?></button>
1469
- </div>
1470
- <!-- Reset Settings Modal -->
1471
 
1472
  <div class="remodal" data-remodal-id="wsal_purge_activity">
1473
  <button data-remodal-action="close" class="remodal-close"></button>
@@ -1490,33 +1504,33 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1490
  // Get $_POST global array.
1491
  $post_array = filter_input_array( INPUT_POST );
1492
 
1493
- $this->_plugin->settings()->SetDeleteData( isset( $post_array['DeleteData'] ) ? sanitize_text_field( $post_array['DeleteData'] ) : false );
1494
 
1495
  $stealth_mode = isset( $post_array['mwp_stealth_mode'] ) ? $post_array['mwp_stealth_mode'] : false;
1496
  if ( 'yes' === $stealth_mode ) {
1497
  if ( ! WpSecurityAuditLog::is_mainwp_active() ) {
1498
  throw new Exception( __( 'MainWP Child plugin is not active on this website.', 'wp-security-audit-log' ) );
1499
  }
1500
- $this->_plugin->settings()->set_mainwp_child_stealth_mode();
1501
 
1502
  $admin_blocking_plugins_support = isset( $post_array['mwp_admin_blocking_support'] ) ? $post_array['mwp_admin_blocking_support'] : false;
1503
  if ( 'yes' === $admin_blocking_plugins_support ) {
1504
- $this->_plugin->settings()->set_admin_blocking_plugin_support( true );
1505
  }
1506
  } else {
1507
- $this->_plugin->settings()->deactivate_mainwp_child_stealth_mode();
1508
  }
1509
  }
1510
 
1511
  /**
1512
- * Method: Get View Header.
1513
  */
1514
- public function Header() {
1515
  wp_enqueue_style(
1516
  'settings',
1517
- $this->_plugin->GetBaseUrl() . '/css/settings.css',
1518
  array(),
1519
- filemtime( $this->_plugin->GetBaseDir() . '/css/settings.css' )
1520
  );
1521
 
1522
  // Check current tab.
@@ -1526,24 +1540,24 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1526
  wp_enqueue_style( 'wsal-remodal-theme', WSAL_BASE_URL . 'css/remodal-default-theme.css', array(), '1.1.1' );
1527
  }
1528
  ?>
1529
- <style type="text/css">
1530
- .wsal-tab {
1531
- /* display: none; */
1532
- }
1533
- .wsal-tab tr.alert-incomplete td {
1534
- color: #9BE;
1535
- }
1536
- .wsal-tab tr.alert-unavailable td {
1537
- color: #CCC;
1538
- }
1539
- </style>
1540
  <?php
1541
  }
1542
 
1543
  /**
1544
- * Method: Get View Footer.
1545
  */
1546
- public function Footer() {
1547
  // Enqueue jQuery UI from core.
1548
  wp_enqueue_script(
1549
  'wsal-jquery-ui',
@@ -1568,9 +1582,9 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1568
  // Register settings script.
1569
  wp_register_script(
1570
  'settings',
1571
- $this->_plugin->GetBaseUrl() . '/js/settings.js',
1572
  array(),
1573
- filemtime( $this->_plugin->GetBaseDir() . '/js/settings.js' ),
1574
  true
1575
  );
1576
  // Passing nonce for security to JS file.
@@ -1589,25 +1603,25 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1589
  wp_localize_script( 'settings', 'wsal_data', $wsal_data );
1590
  wp_enqueue_script( 'settings' );
1591
  ?>
1592
- <script type="text/javascript">
1593
- jQuery( document ).ready( function() {
1594
- jQuery( '.sel-columns' ).change( function() {
1595
- var notChecked = 1;
1596
- jQuery( '.sel-columns' ).each( function() {
1597
- if ( this.checked ) notChecked = 0;
1598
- })
1599
- if ( notChecked == 1 ) {
1600
- alert( esc_html__( 'You have to select at least one column!', 'wp-security-audit-log' ) );
1601
- }
1602
- });
1603
- });</script>
1604
  <?php
1605
  }
1606
 
1607
  /**
1608
  * Method: Ajax Request handler for AjaxGetAllUsers.
1609
  */
1610
- public function AjaxGetAllUsers() {
1611
  // Filter $_GET array for security.
1612
  $get_array = filter_input_array( INPUT_GET );
1613
  $this->check_ajax_request_is_valid( $get_array );
@@ -1626,7 +1640,7 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1626
  /**
1627
  * Method: Ajax Request handler for AjaxGetAllRoles.
1628
  */
1629
- public function AjaxGetAllRoles() {
1630
  // Filter $_GET array for security.
1631
  $get_array = filter_input_array( INPUT_GET );
1632
  $this->check_ajax_request_is_valid( $get_array );
@@ -1653,22 +1667,29 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1653
  $get_array = filter_input_array( INPUT_GET );
1654
  $this->check_ajax_request_is_valid( $get_array );
1655
 
1656
- echo $this->filter_values_for_searched_term( array_values( WSAL_ConstantManager::getSeverities() ), $get_array['term'] );
 
 
 
1657
  exit;
1658
  }
1659
 
1660
  /**
1661
  * Filters values to return ones matching the desired term.
1662
  *
1663
- * @param array $items_to_filter
1664
- * @param string $term
1665
- * @return string
 
1666
  */
1667
  public function filter_values_for_searched_term( $items_to_filter, $term ) {
1668
 
1669
- $result = array_filter( $items_to_filter, function( $value ) use ( $term ) {
1670
- return strpos( strtolower( $value ), strtolower( $term ) ) !== false;
1671
- });
 
 
 
1672
 
1673
  return wp_json_encode( $result );
1674
  }
@@ -1684,9 +1705,9 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1684
  $get_array = filter_input_array( INPUT_GET );
1685
  $this->check_ajax_request_is_valid( $get_array );
1686
 
1687
- $event_types = $this->_plugin->alerts->get_event_type_data();
1688
 
1689
- echo $this->filter_values_for_searched_term( array_values( $event_types ), $get_array['term'] );
1690
  exit;
1691
  }
1692
 
@@ -1701,9 +1722,9 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1701
  $get_array = filter_input_array( INPUT_GET );
1702
  $this->check_ajax_request_is_valid( $get_array );
1703
 
1704
- $event_objects = $this->_plugin->alerts->get_event_objects_data();
1705
 
1706
- echo $this->filter_values_for_searched_term( array_values( $event_objects ), $get_array['term'] );
1707
  exit;
1708
  }
1709
 
@@ -1718,14 +1739,14 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1718
  $get_array = filter_input_array( INPUT_GET );
1719
  $this->check_ajax_request_is_valid( $get_array );
1720
 
1721
- $registered_alerts = $this->_plugin->alerts->GetAlerts();
1722
 
1723
- $alerts = [];
1724
  foreach ( $registered_alerts as $alert => $details ) {
1725
  $alerts[] = (string) $details->code;
1726
  }
1727
 
1728
- echo $this->filter_values_for_searched_term( array_values( $alerts ), $get_array['term'] );
1729
  exit;
1730
  }
1731
 
@@ -1734,16 +1755,19 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1734
  *
1735
  * @since 2.6.7
1736
  */
1737
- public function AjaxGetAllCPT() {
1738
  // Filter $_GET array for security.
1739
  $get_array = filter_input_array( INPUT_GET );
1740
  $this->check_ajax_request_is_valid( $get_array );
1741
 
1742
  // Get custom post types.
1743
  $custom_post_types = array();
1744
- $post_types = get_post_types( array(
1745
- 'public' => false
1746
- ), 'names' );
 
 
 
1747
  // if we are running multisite and have networkwide cpt tracker get the
1748
  // list from and merge to the post_types array.
1749
  if ( is_multisite() && class_exists( '\WSAL\Multisite\NetworkWide\CPTsTracker' ) ) {
@@ -1752,6 +1776,7 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1752
  $post_types[ $cpt ] = $cpt;
1753
  }
1754
  }
 
1755
  $post_types = array_diff( $post_types, array( 'attachment', 'revision', 'nav_menu_item', 'customize_changeset', 'custom_css' ) );
1756
  foreach ( $post_types as $post_type ) {
1757
  if ( strpos( $post_type, $get_array['term'] ) !== false ) {
@@ -1765,14 +1790,14 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1765
  /**
1766
  * Checks if provided GET array is valid and bails if not.
1767
  *
1768
- * @param array $get_array
1769
- * @return void
1770
  */
1771
  public function check_ajax_request_is_valid( $get_array ) {
1772
  // Die if user does not have permission to edit.
1773
- if ( ! $this->_plugin->settings()->CurrentUserCan( 'edit' ) ) {
1774
  die( 'Access Denied.' );
1775
  }
 
1776
  // Die if nonce verification failed.
1777
  if ( ! wp_verify_nonce( $get_array['wsal_nonce'], 'wsal-exclude-nonce' ) ) {
1778
  die( esc_html__( 'Nonce verification failed.', 'wp-security-audit-log' ) );
@@ -1784,7 +1809,7 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1784
  */
1785
  public function reset_settings() {
1786
  // Die if user does not have permission to change settings.
1787
- if ( ! $this->_plugin->settings()->CurrentUserCan( 'edit' ) ) {
1788
  wp_send_json_error( esc_html__( 'Access Denied.', 'wp-security-audit-log' ) );
1789
  }
1790
 
@@ -1794,20 +1819,20 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1794
  wp_send_json_error( esc_html__( 'Nonce Verification Failed.', 'wp-security-audit-log' ) );
1795
  }
1796
 
1797
- // delete all settings
1798
- WSAL_Uninstall::delete_options_from_wp_options();
1799
 
1800
- // Log settings reset event.
1801
- $this->_plugin->alerts->Trigger( 6006 );
1802
- wp_send_json_success( esc_html__( 'Plugin settings have been reset.', 'wp-security-audit-log' ) );
1803
  }
1804
 
1805
  /**
1806
  * Method: Purge plugin occurrence & meta tables.
1807
  */
1808
- public function purge_activity() {
1809
  // Die if user does not have permission to change settings.
1810
- if ( ! $this->_plugin->settings()->CurrentUserCan( 'edit' ) ) {
1811
  wp_send_json_error( esc_html__( 'Access Denied.', 'wp-security-audit-log' ) );
1812
  }
1813
 
@@ -1817,103 +1842,110 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1817
  wp_send_json_error( esc_html__( 'Nonce Verification Failed.', 'wp-security-audit-log' ) );
1818
  }
1819
 
1820
- $connector = WpSecurityAuditLog::getConnector();
1821
- $result = $connector->purge_activity();
1822
 
1823
- if ( $result ) {
1824
- // Log purge activity event.
1825
- $this->_plugin->alerts->Trigger( 6034 );
1826
- wp_send_json_success( esc_html__( 'Tables has been reset.', 'wp-security-audit-log' ) );
1827
- } else {
1828
- wp_send_json_error( esc_html__( 'Reset query failed.', 'wp-security-audit-log' ) );
1829
- }
1830
  }
1831
 
1832
- public function render_retention_settings_table( ) {
1833
- // check if the retention settings are enforced from the MainWP master site
1834
- $settings = $this->_plugin->settings();
1835
- $enforced_settings = $settings->get_mainwp_enforced_settings();
1836
- $retention_settings_enforced_by_mainwp = array_key_exists( 'pruning_enabled', $enforced_settings );
1837
- ?>
1838
- <table class="form-table wsal-tab">
1839
- <tbody>
1840
- <tr>
1841
- <th><label for="delete1"><?php esc_html_e( 'Activity log retention', 'wp-security-audit-log' ); ?></label></th>
1842
- <td>
1843
- <fieldset>
1844
- <?php $nbld = ! $this->_plugin->settings()->IsPruningDateEnabled(); ?>
1845
- <label for="delete0">
1846
- <input type="radio" id="delete0" name="PruneBy" value="" <?php checked( $nbld ); ?><?php if ( $retention_settings_enforced_by_mainwp ): ?> disabled="disabled"<?php endif; ?> />
1847
- <?php echo esc_html__( 'Keep all data', 'wp-security-audit-log' ); ?>
1848
- </label>
1849
- </fieldset>
1850
-
1851
- <fieldset>
1852
- <?php
1853
- // Check pruning date option.
1854
- $nbld = $this->_plugin->settings()->IsPruningDateEnabled();
1855
-
1856
- // Find and replace ` months` in the string.
1857
- $pruning_date = $this->_plugin->settings()->GetPruningDate();
1858
- $pruning_date = preg_replace( "/[^0-9]/", "", $pruning_date );
1859
-
1860
- $pruning_unit = $this->_plugin->settings()->get_pruning_unit();
1861
-
1862
- $pruning_unit_options = [
 
 
 
 
1863
  'days' => esc_html__( 'Days', 'wp-security-audit-log' ),
1864
  'months' => esc_html__( 'Months', 'wp-security-audit-log' ),
1865
  'years' => esc_html__( 'Years', 'wp-security-audit-log' ),
1866
- ];
1867
-
1868
- // Check if pruning limit was enabled for backwards compatibility.
1869
- if ( $this->_plugin->settings()->IsPruningLimitEnabled() ) {
1870
- $nbld = true;
1871
- $pruning_date = '6';
1872
- $pruning_unit = 'months';
1873
- $this->_plugin->settings()->SetPruningDate( $pruning_date . ' ' . $pruning_unit );
1874
- $this->_plugin->settings()->SetPruningDateEnabled( true );
1875
- $this->_plugin->settings()->SetPruningLimitEnabled( false );
1876
- }
1877
- ?>
1878
- <label for="delete1">
1879
- <input type="radio" id="delete1" name="PruneBy" value="date" <?php checked( $nbld ); ?><?php if ( $retention_settings_enforced_by_mainwp ): ?> disabled="disabled"<?php endif; ?> />
1880
- <?php esc_html_e( 'Delete events older than', 'wp-security-audit-log' ); ?>
1881
- </label>
1882
- <input type="text" id="PruningDate" name="PruningDate"
1883
- value="<?php echo esc_attr( $pruning_date ); ?>"
1884
- onfocus="jQuery('#delete1').attr('checked', true);"
1885
- <?php if ( $retention_settings_enforced_by_mainwp ): ?> disabled="disabled"<?php endif; ?>
1886
- />
1887
- <select name="pruning-unit" id="pruning-unit"<?php if ( $retention_settings_enforced_by_mainwp ): ?> disabled="disabled"<?php endif; ?> >
1888
- <?php foreach ( $pruning_unit_options as $option => $label ) {
1889
- echo '<option value="' . $option . '" ' . selected( $pruning_unit, $option, true ) . '>' . ucwords( $label ) . '</option>';
1890
- } ?>
1891
- </select>
1892
- </fieldset>
1893
-
1894
- <?php if ( $this->_plugin->settings()->IsPruningDateEnabled() ) : ?>
1895
- <p class="description">
1896
- <?php
1897
- $next = wp_next_scheduled( 'wsal_cleanup' );
1898
- echo esc_html__( 'The next scheduled purging of activity log data that is older than ', 'wp-security-audit-log' );
1899
- echo esc_html( $pruning_date . ' ' . $pruning_unit );
1900
- echo sprintf(
1901
- ' is in %s.',
1902
- esc_html( human_time_diff( current_time( 'timestamp' ), $next ) )
1903
- );
1904
- echo '<!-- ' . esc_html( date( 'dMy H:i:s', $next ) ) . ' --> ';
1905
- echo esc_html__( 'You can run the purging process now by clicking the button below.', 'wp-security-audit-log' );
1906
- ?>
1907
- </p>
1908
- <p>
1909
- <a class="button-primary" href="<?php echo esc_url( add_query_arg( 'action', 'AjaxRunCleanup', admin_url( 'admin-ajax.php' ) ) ); ?>"><?php esc_html_e( 'Purge Old Data', 'wp-security-audit-log' ); ?></a>
1910
- </p>
1911
- <?php endif; ?>
1912
- </td>
1913
- </tr>
1914
- <!-- Activity log retention -->
1915
- </tbody>
1916
- </table>
1917
- <?php
1918
- }
 
 
 
1919
  }
4
  *
5
  * Settings page of the plugin.
6
  *
7
+ * @since 1.0.0
8
+ * @package wsal
9
+ * @subpackage views
10
  */
11
 
12
  // Exit if accessed directly.
19
  *
20
  * Settings view class to handle settings page functions.
21
  *
22
+ * @since 1.0.0
23
+ *
24
+ * @package wsal
25
+ * @subpackage views
26
  */
27
  class WSAL_Views_Settings extends WSAL_AbstractView {
28
 
59
  public function __construct( WpSecurityAuditLog $plugin ) {
60
  parent::__construct( $plugin );
61
  add_action( 'admin_init', array( $this, 'setup_settings_tabs' ) );
62
+ add_action( 'wp_ajax_AjaxCheckSecurityToken', array( $this, 'ajax_check_security_token' ) );
63
+ add_action( 'wp_ajax_AjaxRunCleanup', array( $this, 'ajax_run_cleanup' ) );
64
+ add_action( 'wp_ajax_AjaxGetAllUsers', array( $this, 'ajax_get_all_users' ) );
65
+ add_action( 'wp_ajax_AjaxGetAllRoles', array( $this, 'ajax_get_all_roles' ) );
66
+ add_action( 'wp_ajax_AjaxGetAllCPT', array( $this, 'ajax_get_all_cpts' ) );
67
  add_action( 'wp_ajax_wsal_reset_settings', array( $this, 'reset_settings' ) );
68
  add_action( 'wp_ajax_wsal_purge_activity', array( $this, 'purge_activity' ) );
69
  add_action( 'wp_ajax_wsal_ajax_get_all_severities', array( $this, 'ajax_get_all_severities' ) );
78
  * @since 3.4
79
  */
80
  public function setup_settings_tabs() {
 
 
 
81
 
82
  // Verify that the current page is WSAL settings page.
83
+ $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : false; // phpcs:ignore
84
+ if ( empty( $page ) || $this->get_safe_view_name() !== $page ) {
85
  return;
86
  }
87
 
88
  // Tab links.
89
  $wsal_setting_tabs = array(
90
  'general' => array(
91
+ 'name' => esc_html__( 'General', 'wp-security-audit-log' ),
92
+ 'link' => add_query_arg( 'tab', 'general', $this->get_url() ),
93
  'render' => array( $this, 'tab_general' ),
94
  'save' => array( $this, 'tab_general_save' ),
95
  'priority' => 10,
96
  ),
97
  'audit-log' => array(
98
+ 'name' => esc_html__( 'Activity log viewer', 'wp-security-audit-log' ),
99
+ 'link' => add_query_arg( 'tab', 'audit-log', $this->get_url() ),
100
  'render' => array( $this, 'tab_audit_log' ),
101
  'save' => array( $this, 'tab_audit_log_save' ),
102
  'priority' => 20,
103
  ),
104
  'file-changes' => array(
105
+ 'name' => esc_html__( 'File changes', 'wp-security-audit-log' ),
106
+ 'link' => add_query_arg( 'tab', 'file-changes', $this->get_url() ),
107
  'render' => array( $this, 'tab_file_changes' ),
108
  'priority' => 30,
109
  ),
110
  'exclude-objects' => array(
111
+ 'name' => esc_html__( 'Exclude objects', 'wp-security-audit-log' ),
112
+ 'link' => add_query_arg( 'tab', 'exclude-objects', $this->get_url() ),
113
  'render' => array( $this, 'tab_exclude_objects' ),
114
  'save' => array( $this, 'tab_exclude_objects_save' ),
115
  'priority' => 40,
116
  ),
117
  'advanced-settings' => array(
118
+ 'name' => esc_html__( 'Advanced settings', 'wp-security-audit-log' ),
119
+ 'link' => add_query_arg( 'tab', 'advanced-settings', $this->get_url() ),
120
  'render' => array( $this, 'tab_advanced_settings' ),
121
  'save' => array( $this, 'tab_advanced_settings_save' ),
122
  'priority' => 100,
154
  }
155
 
156
  /**
157
+ * {@inheritDoc}
158
  */
159
+ public function has_plugin_shortcut_link() {
160
  return true;
161
  }
162
 
163
  /**
164
+ * {@inheritDoc}
165
  */
166
+ public function get_title() {
167
+ return esc_html__( 'Settings', 'wp-security-audit-log' );
168
  }
169
 
170
  /**
171
+ * {@inheritDoc}
172
  */
173
+ public function get_icon() {
174
  return 'dashicons-admin-generic';
175
  }
176
 
177
  /**
178
+ * {@inheritDoc}
179
  */
180
+ public function get_name() {
181
+ return esc_html__( 'Settings', 'wp-security-audit-log' );
182
  }
183
 
184
  /**
185
+ * {@inheritDoc}
186
  */
187
+ public function get_weight() {
188
  return 8;
189
  }
190
 
193
  *
194
  * @param string $token - Token type.
195
  */
196
+ protected function get_token_type( $token ) {
197
+ return $this->plugin->settings()->get_token_type( $token );
198
  }
199
 
200
  /**
202
  *
203
  * @throws Exception - Unrecognized settings tab error.
204
  */
205
+ protected function save() {
206
  // Bail early if user does not have sufficient permissions to save.
207
+ if ( ! $this->plugin->settings()->current_user_can( 'edit' ) ) {
208
  throw new Exception( esc_html__( 'Current user is not allowed to save settings.', 'wp-security-audit-log' ) );
209
  }
210
  // Call respective tab save functions if they are set. Nonce is already verified at this point.
218
  /**
219
  * Method: Check security token.
220
  */
221
+ public function ajax_check_security_token() {
222
+ if ( ! $this->plugin->settings()->current_user_can( 'edit' ) ) {
223
  echo wp_json_encode(
224
  array(
225
  'success' => false,
258
  array(
259
  'success' => true,
260
  'token' => $token,
261
+ 'tokenType' => esc_html( $this->get_token_type( $token ) ),
262
  )
263
  );
264
  die();
267
  /**
268
  * Method: Run cleanup.
269
  */
270
+ public function ajax_run_cleanup() {
271
+ if ( ! $this->plugin->settings()->current_user_can( 'edit' ) ) {
272
  die( 'Access Denied.' );
273
  }
274
 
275
+ $now = current_time( 'timestamp' ); // phpcs:ignore
276
+ $max_sdate = $this->plugin->settings()->get_pruning_date(); // Pruning date.
277
 
278
 
279
  // Calculate limit timestamp.
280
  $max_stamp = $now - ( strtotime( $max_sdate ) - $now );
281
 
282
  $query = new WSAL_Models_OccurrenceQuery();
283
+ $query->add_order_by( 'created_on', false ); // Descending order.
284
+ $query->add_condition( 'created_on <= %s', intval( $max_stamp ) ); // Add limits of timestamp.
285
+ $results = $query->get_adapter()->execute_query( $query );
286
  $items = count( $results );
287
 
288
  if ( $items ) {
289
+ $this->plugin->clean_up();
290
  }
291
 
292
  if ( $archiving ) {
308
  'pruning' => 0,
309
  );
310
  }
311
+ wp_safe_redirect( add_query_arg( $redirect_args, $this->get_url() ) );
312
  }
313
  exit;
314
  }
315
 
316
  /**
317
+ * {@inheritDoc}
318
  */
319
+ public function render() {
320
  // Verify nonce if a form is submitted.
321
  if ( isset( $_POST['_wpnonce'] ) ) {
322
  check_admin_referer( 'wsal-settings' );
323
  }
324
 
325
+ if ( ! $this->plugin->settings()->current_user_can( 'edit' ) ) {
326
  wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'wp-security-audit-log' ) );
327
  }
328
 
331
 
332
  if ( isset( $_POST['submit'] ) ) {
333
  try {
334
+ $this->save(); // Save settings.
335
  if ( 'sms-provider' === $this->current_tab && $section && 'test' === $section ) :
336
  ?>
337
+ <div class="updated">
338
+ <p><?php esc_html_e( 'Message sent successfully.', 'wp-security-audit-log' ); ?></p>
339
+ </div>
340
  <?php else : ?>
341
+ <div class="updated">
342
+ <p><?php esc_html_e( 'Settings have been saved.', 'wp-security-audit-log' ); ?></p>
343
+ </div>
344
+ <?php
345
  endif;
346
  } catch ( Exception $ex ) {
347
  ?>
348
+ <div class="error">
349
+ <p><?php esc_html_e( 'Error: ', 'wp-security-audit-log' ); ?><?php echo esc_html( $ex->getMessage() ); ?></p>
350
+ </div>
351
  <?php
352
  }
353
  }
358
 
359
  if ( isset( $_GET['pruning'] ) && '1' === $_GET['pruning'] ) {
360
  ?>
361
+ <div class="updated">
362
+ <p><?php esc_html_e( 'Old data successfully purged.', 'wp-security-audit-log' ); ?></p>
363
+ </div>
364
  <?php
365
  } elseif ( isset( $_GET['pruning'] ) && '0' === $_GET['pruning'] ) {
366
  ?>
367
+ <div class="error">
368
+ <p><?php esc_html_e( 'No data is old enough to be purged.', 'wp-security-audit-log' ); ?></p>
369
+ </div>
370
  <?php
371
  }
372
  ?>
373
+ <nav id="wsal-tabs" class="nav-tab-wrapper">
374
  <?php foreach ( $this->wsal_setting_tabs as $tab_id => $tab ) : ?>
375
+ <a href="<?php echo esc_url( $tab['link'] ); ?>" class="nav-tab <?php echo ( $tab_id === $this->current_tab ) ? 'nav-tab-active' : false; ?>">
376
  <?php echo esc_html( $tab['name'] ); ?>
377
+ </a>
378
  <?php endforeach; ?>
379
+ </nav>
380
 
381
+ <form id="audit-log-settings" method="post">
382
+ <input type="hidden" name="page" value="<?php echo isset( $_GET['page'] ) ? esc_attr( sanitize_text_field( wp_unslash( $_GET['page'] ) ) ) : false; ?>" />
383
+ <input type="hidden" id="ajaxurl" value="<?php echo esc_attr( admin_url( 'admin-ajax.php' ) ); ?>" />
384
  <?php wp_nonce_field( 'wsal-settings' ); ?>
385
 
386
+ <div id="audit-log-adverts"></div>
387
+ <div class="nav-tabs">
 
388
  <?php
389
  if ( ! empty( $this->current_tab ) && ! empty( $this->wsal_setting_tabs[ $this->current_tab ]['render'] ) ) {
390
  call_user_func( $this->wsal_setting_tabs[ $this->current_tab ]['render'] );
392
  call_user_func( $this->wsal_setting_tabs['general']['render'] );
393
  }
394
  ?>
395
+ </div>
396
  <?php
397
  if ( 'sms-provider' === $this->current_tab && $section && 'test' === $section ) {
398
+ submit_button( esc_html__( 'Send Message', 'wp-security-audit-log' ) );
399
  } else {
400
  submit_button();
401
  }
402
  ?>
403
+ </form>
404
+ <?php // @codingStandardsIgnoreStart ?>
405
  <script type="text/javascript">
406
  <!--
407
  function delete_confirm(elementRef) {
443
  } );
444
  // --></script>
445
  <?php
446
+ // @codingStandardsIgnoreEnd
447
  }
448
 
449
  /**
450
  * Tab: `General`
451
  */
452
  private function tab_general() {
453
+ $settings = $this->plugin->settings();
454
+ $enforced_settings = $settings->get_mainwp_enforced_settings();
455
+ $login_page_notification_settings_enforced_by_mainwp = array_key_exists( 'login_notification_enabled', $enforced_settings );
456
+ $incognito_setting_enforced_by_mainwp = array_key_exists( 'incognito_mode_enabled', $enforced_settings );
457
  ?>
458
+ <h3><?php esc_html_e( 'Use infinite scroll or pagination for the event viewer?', 'wp-security-audit-log' ); ?></h3>
459
+ <p class="description">
460
  <?php
461
  echo sprintf(
462
  /* translators: Learn more link. */
464
  '<a href="https://wpactivitylog.com/features/search-filters-wordpress-activity-log/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=settings+pages" target="_blank">' . esc_html__( '(Premium feature)', 'wp-security-audit-log' ) . '</a>'
465
  );
466
  ?>
467
+ </p>
468
+ <table class="form-table wsal-tab">
469
+ <tbody>
470
+ <tr>
471
+ <th><label for="infinite-scroll"><?php esc_html_e( 'Select event viewer view type:', 'wp-security-audit-log' ); ?></label></th>
472
+ <td>
473
+ <fieldset>
474
+ <label for="infinite-scroll">
475
+ <input type="radio" name="events-type-nav" value="infinite-scroll" id="infinite-scroll" <?php checked( $this->plugin->settings()->get_events_type_nav(), 'infinite-scroll' ); ?> />
476
  <?php esc_html_e( 'Infinite Scroll (Recommended)', 'wp-security-audit-log' ); ?>
477
+ </label>
478
+ <br/>
479
+ <label for="pagination">
480
+ <input type="radio" name="events-type-nav" value="pagination" id="pagination" <?php checked( $this->plugin->settings()->get_events_type_nav(), 'pagination' ); ?> />
481
  <?php esc_html_e( 'Pagination', 'wp-security-audit-log' ); ?>
482
+ </label>
483
+ <br />
484
+ </fieldset>
485
+ </td>
486
+ </tr>
487
+ <!-- / Reverse Proxy / Firewall Options -->
488
+ </tbody>
489
+ </table>
490
+ <!-- Events Navigation Type -->
491
+
492
+ <h3><?php esc_html_e( 'Do you want the activity log viewer to auto refresh?', 'wp-security-audit-log' ); ?></h3>
493
+ <p class="description"><?php esc_html_e( 'The activity log viewer auto refreshes every 30 seconds when opened so you can see the latest events as they happen almost in real time.', 'wp-security-audit-log' ); ?></p>
494
+ <table class="form-table wsal-tab">
495
+ <tbody>
496
+ <tr>
497
+ <th><label for="aroption_on"><?php esc_html_e( 'Refresh activity log viewer', 'wp-security-audit-log' ); ?></label></th>
498
+ <td>
499
+ <fieldset>
500
+ <?php $are = $this->plugin->settings()->is_refresh_alerts_enabled(); ?>
501
+ <label for="aroption_on">
502
+ <input type="radio" name="EnableAuditViewRefresh" id="aroption_on" style="margin-top: -2px;" <?php checked( $are ); ?> value="1">
503
+ <span><?php esc_html_e( 'Auto refresh', 'wp-security-audit-log' ); ?></span>
504
+ </label>
505
+ <br/>
506
+ <label for="aroption_off">
507
+ <input type="radio" name="EnableAuditViewRefresh" id="aroption_off" style="margin-top: -2px;" <?php checked( $are, false ); ?> value="0">
508
+ <span><?php esc_html_e( 'Do not auto refresh', 'wp-security-audit-log' ); ?></span>
509
+ </label>
510
+ </fieldset>
511
+ </td>
512
+ </tr>
513
+ <!-- Refresh activity log viewer -->
514
+ </tbody>
515
+ </table>
516
+ <!-- Refresh activity log -->
517
+
518
+ <h3><?php esc_html_e( 'Display latest events widget in Dashboard & Admin bar', 'wp-security-audit-log' ); ?></h3>
519
+ <p class="description">
520
  <?php
521
  echo sprintf(
522
  /* translators: Max number of dashboard widget alerts. */
523
  esc_html__( 'The events widget displays the latest %d security events in the dashboard and the admin bar notification displays the latest event.', 'wp-security-audit-log' ),
524
+ esc_html( $this->plugin->settings()->get_dashboard_widget_max_alerts() )
525
  );
526
  ?>
527
+ </p>
528
+ <table class="form-table wsal-tab">
529
+ <tbody>
530
+ <tr>
531
+ <th><label for="dwoption_on"><?php esc_html_e( 'Dashboard Widget', 'wp-security-audit-log' ); ?></label></th>
532
+ <td>
533
+ <fieldset>
534
+ <?php $dwe = $this->plugin->settings()->is_widgets_enabled(); ?>
535
+ <label for="dwoption_on">
536
+ <input type="radio" name="EnableDashboardWidgets" id="dwoption_on" style="margin-top: -2px;" <?php checked( $dwe ); ?> value="1">
537
+ <span><?php esc_html_e( 'Yes', 'wp-security-audit-log' ); ?></span>
538
+ </label>
539
+ <br/>
540
+ <label for="dwoption_off">
541
+ <input type="radio" name="EnableDashboardWidgets" id="dwoption_off" style="margin-top: -2px;" <?php checked( $dwe, false ); ?> value="0">
542
+ <span><?php esc_html_e( 'No', 'wp-security-audit-log' ); ?></span>
543
+ </label>
544
+ </fieldset>
545
+ </td>
546
+ </tr>
547
+ <!-- / Events Dashboard Widget -->
548
+
549
+ <tr>
550
  <?php
551
  $disabled = '';
552
+ $label = esc_html__( 'Admin Bar Notification', 'wp-security-audit-log' );
553
  if ( wsal_freemius()->is_free_plan() ) {
554
  $disabled = 'disabled';
555
+ $label = esc_html__( 'Admin Bar Notification (Premium)', 'wp-security-audit-log' );
556
  }
557
  ?>
558
+ <th><label for="admin_bar_notif_on"><?php echo esc_html( $label ); ?></label></th>
559
+ <td>
560
+ <fieldset <?php echo esc_attr( $disabled ); ?>>
561
+ <?php $abn = $this->plugin->settings()->is_admin_bar_notif(); ?>
562
+ <label for="admin_bar_notif_on">
563
+ <input type="radio" name="admin_bar_notif" id="admin_bar_notif_on" style="margin-top: -2px;" <?php checked( $abn ); ?> value="1">
564
+ <span><?php esc_html_e( 'Yes', 'wp-security-audit-log' ); ?></span>
565
+ </label>
566
+ <br/>
567
+ <label for="admin_bar_notif_off">
568
+ <input type="radio" name="admin_bar_notif" id="admin_bar_notif_off" style="margin-top: -2px;" <?php checked( $abn, false ); ?> value="0">
569
+ <span><?php esc_html_e( 'No', 'wp-security-audit-log' ); ?></span>
570
+ </label>
571
+ </fieldset>
572
+ </td>
573
+ </tr>
574
+ <!-- / Admin Bar Notification -->
575
+
576
+ <tr>
577
  <?php
578
  $disabled = '';
579
+ $label = esc_html__( 'Admin Bar Notification Updates', 'wp-security-audit-log' );
580
  if ( wsal_freemius()->is_free_plan() ) {
581
  $disabled = 'disabled';
582
+ $label = esc_html__( 'Admin Bar Notification Updates (Premium)', 'wp-security-audit-log' );
583
  }
584
  ?>
585
+ <th><label for="admin_bar_notif_refresh"><?php echo esc_html( $label ); ?></label></th>
586
+ <td>
587
+ <fieldset <?php echo esc_attr( $disabled ); ?>>
588
+ <?php $abn_updates = $this->plugin->settings()->get_admin_bar_notif_updates(); ?>
589
+ <label for="admin_bar_notif_realtime">
590
+ <input type="radio" name="admin_bar_notif_updates" id="admin_bar_notif_realtime" style="margin-top: -2px;" <?php checked( $abn_updates, 'real-time' ); ?> value="real-time">
591
+ <span><?php esc_html_e( 'Update in near real time', 'wp-security-audit-log' ); ?></span>
592
+ </label>
593
+ <br/>
594
+ <label for="admin_bar_notif_refresh">
595
+ <input type="radio" name="admin_bar_notif_updates" id="admin_bar_notif_refresh" style="margin-top: -2px;" <?php checked( $abn_updates, 'page-refresh' ); ?> value="page-refresh">
596
+ <span><?php esc_html_e( 'Update only on page refreshes', 'wp-security-audit-log' ); ?></span>
597
+ </label>
598
+ </fieldset>
599
+ </td>
600
+ </tr>
601
+ <!-- / Admin Bar Notification Updates -->
602
+ </tbody>
603
+ </table>
604
+ <!-- Dashboard Widget -->
605
+
606
+ <h3><?php esc_html_e( 'Add user notification on the WordPress login page', 'wp-security-audit-log' ); ?></h3>
607
+ <p class="description"><?php esc_html_e( 'Many compliance regulations (such as the GDPR) require website administrators to tell the users of their website that all the changes they do when logged in are being logged.', 'wp-security-audit-log' ); ?></p>
608
+ <table class="form-table wsal-tab">
609
+ <tbody>
610
+ <tr>
611
+ <th><label for="login_page_notification"><?php esc_html_e( 'Login Page Notification', 'wp-security-audit-log' ); ?></label></th>
612
+ <td>
613
+ <fieldset <?php echo disabled( $login_page_notification_settings_enforced_by_mainwp ); ?>>
614
  <?php
615
  // Get login page notification checkbox.
616
+ $wsal_lpn = $this->plugin->settings()->is_login_page_notification();
617
  if ( $wsal_lpn && 'true' === $wsal_lpn ) {
618
  // If option exists, value is true then set to true.
619
  $wsal_lpn = true;
625
  $wsal_lpn = false;
626
  }
627
  ?>
628
+ <label for="wsal_lpn_yes">
629
+ <input type="radio" name="login_page_notification" id="wsal_lpn_yes" <?php checked( $wsal_lpn ); ?> value="true" />
630
  <?php esc_html_e( 'Yes', 'wp-security-audit-log' ); ?>
631
+ </label>
632
+ <br />
633
  <?php
634
  // Get login page notification text.
635
+ $wsal_lpn_text = $this->plugin->settings()->get_login_page_notification_text();
636
+ if ( ! $wsal_lpn_text ) {
637
+ $wsal_lpn_text = __( 'For security and auditing purposes, a record of all of your logged-in actions and changes within the WordPress dashboard will be recorded in an activity log with the <a href="https://wpactivitylog.com/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=settings+pages" target="_blank">WP Activity Log plugin</a>. The audit log also includes the IP address where you accessed this site from.', 'wp-security-audit-log' );
638
+ }
639
  // Allowed HTML tags for this setting.
640
  $allowed_tags = array(
641
  'a' => array(
644
  'target' => array(),
645
  ),
646
  );
647
+
648
  ?>
649
+ <textarea name="login_page_notification_text"
650
+ id="login_page_notification_text"
651
+ cols="60" rows="6"
652
  <?php echo ( $wsal_lpn ) ? false : 'disabled'; ?>
653
+ ><?php echo wp_kses( $wsal_lpn_text, $allowed_tags ); ?></textarea>
654
+ <br/>
655
+ <p class="description">
656
+ <?php echo wp_kses( __( '<strong>Note: </strong>', 'wp-security-audit-log' ), $this->plugin->allowed_html_tags ) . esc_html__( 'The only HTML code allowed in the login page notification is for links ( < a href >< /a > ).', 'wp-security-audit-log' ); // phpcs:ignore ?>
657
+ </p>
658
+ <br />
659
+
660
+ <label for="wsal_lpn_no">
661
+ <input type="radio" name="login_page_notification" id="wsal_lpn_no" <?php checked( $wsal_lpn, false ); ?> value="false" />
662
  <?php esc_html_e( 'No', 'wp-security-audit-log' ); ?>
663
+ </label>
664
+ </fieldset>
665
+ </td>
666
+ </tr>
667
+ <!-- / Login Page Notification -->
668
+ </tbody>
669
+ </table>
670
+ <!-- Login Page Notification -->
671
+
672
+ <h3><?php esc_html_e( 'Is your website running behind a firewall or reverse proxy?', 'wp-security-audit-log' ); ?></h3>
673
+ <p class="description">
674
  <?php
675
  echo sprintf(
676
  /* translators: Learn more link. */
678
  '<a href="https://wpactivitylog.com/support/kb/support-reverse-proxies-web-application-firewalls/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=settings+pages" target="_blank">' . esc_html__( 'learn more', 'wp-security-audit-log' ) . '</a>'
679
  );
680
  ?>
681
+ </p>
682
+ <table class="form-table wsal-tab">
683
+ <tbody>
684
+ <tr>
685
+ <th><label for="pioption_on"><?php esc_html_e( 'Reverse Proxy / Firewall Options', 'wp-security-audit-log' ); ?></label></th>
686
+ <td>
687
+ <fieldset>
688
+ <label for="enable_proxy_ip_capture_yes">
689
+ <input type="radio" name="EnableProxyIpCapture" value="1" id="enable_proxy_ip_capture_yes" <?php checked( $this->plugin->settings()->is_main_ip_from_proxy() ); ?> />
690
  <?php esc_html_e( 'Yes', 'wp-security-audit-log' ); ?>
691
+ </label>
692
+ <br/>
693
+ <label for="EnableIpFiltering">
694
+ <input type="checkbox" name="EnableIpFiltering" value="1" id="EnableIpFiltering" <?php checked( $this->plugin->settings()->is_internal_ips_filtered() ); ?> />
695
  <?php esc_html_e( 'Filter internal IP addresses from the proxy headers. Enable this option only if you are are still seeing the internal IP addresses of the firewall or proxy.', 'wp-security-audit-log' ); ?>
696
+ </label>
697
+ <br/>
698
+ <label for="enable_proxy_ip_capture_no">
699
+ <input type="radio" name="EnableProxyIpCapture" value="0" id="enable_proxy_ip_capture_no" <?php checked( $this->plugin->settings()->is_main_ip_from_proxy(), false ); ?> />
700
  <?php esc_html_e( 'No', 'wp-security-audit-log' ); ?>
701
+ </label>
702
+ <br />
703
+ </fieldset>
704
+ </td>
705
+ </tr>
706
+ <!-- / Reverse Proxy / Firewall Options -->
707
+ </tbody>
708
+ </table>
709
+ <!-- Reverse Proxy -->
710
+
711
+ <h3><?php esc_html_e( 'Who can change the plugin settings?', 'wp-security-audit-log' ); ?></h3>
712
+ <p class="description">
713
  <?php
714
  $allowed_tags = array(
715
  'a' => array(
719
  );
720
  echo wp_kses(
721
  sprintf(
722
+ /* translators: Learn more link. */
723
  esc_html__( 'By default only users with administrator role (single site) and super administrator role (multisite) can change the settings of the plugin. Though you can restrict the privileges to just your user - %s.', 'wp-security-audit-log' ),
724
  '<a href="https://wpactivitylog.com/support/kb/managing-wordpress-activity-log-plugin-privileges/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=settings+pages" target="_blank">' . __( 'learn more', 'wp-security-audit-log' ) . '</a>'
725
  ),
726
  $allowed_tags
727
  );
728
+ $restrict_settings = $this->plugin->settings()->get_restrict_plugin_setting();
729
  ?>
730
+ </p>
731
+ <table class="form-table wsal-tab">
732
+ <tbody>
733
+ <tr>
734
+ <th><label for="RestrictAdmins"><?php esc_html_e( 'Restrict plugin access', 'wp-security-audit-log' ); ?></label></th>
735
+ <td>
736
+ <fieldset>
737
+ <label for="only_me">
738
+ <input type="radio" name="restrict-plugin-settings" id="only_me" value="only_me" <?php checked( $restrict_settings, 'only_me' ); ?> />
739
  <?php esc_html_e( 'Only me', 'wp-security-audit-log' ); ?>
740
+ </label>
741
+ <br/>
742
+ <label for="only_admins">
743
+ <input type="radio" name="restrict-plugin-settings" id="only_admins" value="only_admins" <?php checked( $restrict_settings, 'only_admins' ); ?> />
744
  <?php
745
+ if ( $this->plugin->is_multisite() ) {
746
  esc_html_e( 'All superadmins', 'wp-security-audit-log' );
747
  } else {
748
  esc_html_e( 'All administrators', 'wp-security-audit-log' );
749
  }
750
  ?>
751
+ </label>
752
+ <br/>
753
+ </fieldset>
754
+ </td>
755
+ </tr>
756
+ <!-- / Restrict Plugin Access -->
757
+ </tbody>
758
+ </table>
759
+ <!-- Restrict Plugin Access -->
760
+
761
+ <h3><?php esc_html_e( 'Allow other users to view the activity log', 'wp-security-audit-log' ); ?></h3>
762
+ <p class="description">
763
  <?php
764
+ $is_multisite = $this->plugin->is_multisite();
765
+ if ( $is_multisite ) {
766
+ $section_label = esc_html__( 'By default only super administrators and the child sites\' administrators can view the WordPress activity log. Though you can change this by using the setting below.', 'wp-security-audit-log' );
 
 
 
 
 
 
 
767
  } else {
768
+ $section_label = esc_html__( 'By default only users with administrator role can view the WordPress activity log. To allow someone who does not have an admin role to view the activity log, specify them in the below setting.', 'wp-security-audit-log' );
769
  }
770
 
771
  echo wp_kses(
773
  $allowed_tags
774
  );
775
  ?>
776
+ </p>
777
+ <?php if ( $is_multisite ) : ?>
778
+ <table class="form-table wsal-tab">
779
+ <tbody>
780
+ <tr>
781
+ <th><?php esc_html_e( 'Can view events', 'wp-security-audit-log' ); ?></th>
782
+ <td>
783
+ <fieldset>
784
  <?php
785
+ $restrict_settings = $this->plugin->settings()->get_restrict_log_viewer();
786
  $viewer_restriction_options = array(
787
  'only_me' => __( 'Only me', 'wp-security-audit-log' ),
788
  'only_superadmins' => __( 'Super administators only', 'wp-security-audit-log' ),
789
  'only_admins' => __( 'Super administators and site administrators', 'wp-security-audit-log' ),
790
  );
791
  ?>
792
+ <?php foreach ( $viewer_restriction_options as $option => $label ) : ?>
793
+ <label for="<?php esc_attr( 'log_viewer_' . $option ); ?>">
794
+ <?php $disabled = ( 'only_me' === $option && 'only_superadmins' === $restrict_settings ); ?>
795
+ <input type="radio" name="restrict-log-viewer" id="<?php esc_attr( 'log_viewer_' . $option ); ?>" value="<?php echo esc_attr( $option ); ?>" <?php checked( $restrict_settings, $option ); ?> <?php disabled( $disabled ); ?> />
796
  <?php echo esc_html( $label ); ?>
797
+ </label>
798
+ <br/>
799
  <?php endforeach; ?>
800
+ </fieldset>
801
+ </td>
802
+ </tr>
803
+ </tbody>
804
+ </table>
805
+ <p class="description"><?php esc_html_e( 'To allow someone who does not have an admin role to view the activity log, specify them in the below setting.', 'wp-security-audit-log' ); ?></p>
806
  <?php endif; ?>
807
+ <table class="form-table wsal-tab">
808
+ <tbody>
 
809
  <tr>
810
+ <?php $row_label = $is_multisite ? esc_html__( 'Can also view events', 'wp-security-audit-log' ) : esc_html__( 'Can view events', 'wp-security-audit-log' ); ?>
811
+ <th><label for="ViewerQueryBox"><?php echo $row_label; // phpcs:ignore ?></label></th>
812
  <td>
813
  <fieldset>
814
  <label>
822
 
823
  <div id="ViewerList">
824
  <?php
825
+ foreach ( $this->plugin->settings()->get_allowed_plugin_viewers() as $item ) :
826
  if ( wp_get_current_user()->user_login === $item ) {
827
  continue;
828
  }
829
  ?>
830
+ <span class="sectoken-<?php echo esc_attr( $this->get_token_type( $item ) ); ?>">
831
  <input type="hidden" name="Viewers[]" value="<?php echo esc_attr( $item ); ?>"/>
832
  <?php echo esc_html( $item ); ?>
833
  <a href="javascript:;" title="<?php esc_attr_e( 'Remove', 'wp-security-audit-log' ); ?>">&times;</a>
850
  <th><label for="FromEmail"><?php esc_html_e( 'From Email & Name', 'wp-security-audit-log' ); ?></label></th>
851
  <td>
852
  <fieldset>
853
+ <?php $use_email = $this->plugin->get_global_setting( 'use-email', 'default_email' ); ?>
854
  <label for="default_email">
855
  <input type="radio" name="use-email" id="default_email" value="default_email" <?php checked( $use_email, 'default_email' ); ?> />
856
  <?php esc_html_e( 'Use the email address from the WordPress general settings', 'wp-security-audit-log' ); ?>
863
  <br>
864
  <label for="FromEmail">
865
  <?php esc_html_e( 'Email Address', 'wp-security-audit-log' ); ?>
866
+ <input type="email" id="FromEmail" name="FromEmail" value="<?php echo esc_attr( $this->plugin->settings()->get_from_email() ); ?>" />
867
  </label>
868
  <br>
869
  <label for="DisplayName">
870
  <?php esc_html_e( 'Display Name', 'wp-security-audit-log' ); ?>&nbsp;
871
+ <input type="text" id="DisplayName" name="DisplayName" value="<?php echo esc_attr( $this->plugin->settings()->get_display_name() ); ?>" />
872
  </label>
873
  </fieldset>
874
  </td>
878
  </table>
879
  <!-- From Email & Name -->
880
 
881
+ <?php
882
+ $is_incognito = $this->plugin->settings()->is_incognito();
883
+ ?>
884
  <h3><?php esc_html_e( 'Do you want to hide the plugin from the list of installed plugins?', 'wp-security-audit-log' ); ?></h3>
885
  <p class="description"><?php esc_html_e( 'By default all installed plugins are listed in the plugins page. Set this option to Yes remove WP Activity Log from the list of installed plugins for users who are unable to access the WP Activity Log settings.', 'wp-security-audit-log' ); ?></p>
886
  <table class="form-table wsal-tab">
888
  <tr>
889
  <th><label for="incognito_yes"><?php esc_html_e( 'Hide Plugin in Plugins Page', 'wp-security-audit-log' ); ?></label></th>
890
  <td>
891
+ <fieldset <?php echo disabled( $incognito_setting_enforced_by_mainwp ); ?>>
892
  <label for="incognito_yes">
893
+ <input type="radio" name="Incognito" value="yes" id="incognito_yes" <?php checked( $is_incognito ); ?> />
894
  <?php esc_html_e( 'Yes, hide the plugin and any WP Activity Log plugin extensions from the list of installed plugins', 'wp-security-audit-log' ); ?>
895
  </label>
896
  <br/>
897
  <label for="incognito_no">
898
+ <input type="radio" name="Incognito" value="no" id="incognito_no" <?php checked( $is_incognito, false ); ?> />
899
  <?php esc_html_e( 'No, do not hide the plugin', 'wp-security-audit-log' ); ?>
900
  </label>
901
  </fieldset>
915
  // Get $_POST global array.
916
  $post_array = filter_input_array( INPUT_POST );
917
 
918
+ $this->plugin->settings()->set_refresh_alerts_enabled( $post_array['EnableAuditViewRefresh'] );
919
+ $this->plugin->settings()->set_events_type_nav( sanitize_text_field( $post_array['events-type-nav'] ) );
920
+ $this->plugin->settings()->set_use_email( sanitize_text_field( $post_array['use-email'] ) );
921
+ $this->plugin->settings()->set_from_email( sanitize_email( $post_array['FromEmail'] ) );
922
+ $this->plugin->settings()->set_display_name( sanitize_text_field( $post_array['DisplayName'] ) );
923
+ $this->plugin->settings()->set_widgets_enabled( sanitize_text_field( $post_array['EnableDashboardWidgets'] ) );
 
924
 
925
  if ( ! wsal_freemius()->is_free_plan() ) {
926
+ $this->plugin->settings()->set_admin_bar_notif( sanitize_text_field( $post_array['admin_bar_notif'] ) );
927
+ $this->plugin->settings()->set_admin_bar_notif_updates( sanitize_text_field( $post_array['admin_bar_notif_updates'] ) );
928
  }
929
 
930
+ // Handle log viewer settings in multisite context.
931
+ if ( $this->plugin->is_multisite() ) {
932
  $log_viewer_restrictions = isset( $post_array['restrict-log-viewer'] ) ? sanitize_text_field( $post_array['restrict-log-viewer'] ) : '';
933
+ $this->plugin->settings()->set_restrict_log_viewer( $log_viewer_restrictions );
934
  if ( 'only_me' === $log_viewer_restrictions ) {
935
+ $this->plugin->settings()->set_only_me_user_id( get_current_user_id() );
936
  }
937
  }
938
 
939
  // Get plugin viewers.
940
  $viewers = isset( $post_array['Viewers'] ) ? array_map( 'sanitize_text_field', $post_array['Viewers'] ) : array();
941
+ $this->plugin->settings()->set_allowed_plugin_viewers( $viewers );
942
 
943
+ // Handle plugin settings permissions.
944
  $restrict_settings = isset( $post_array['restrict-plugin-settings'] ) ? sanitize_text_field( $post_array['restrict-plugin-settings'] ) : false;
945
+ $this->plugin->settings()->set_restrict_plugin_setting( $restrict_settings );
946
  if ( 'only_me' === $restrict_settings ) {
947
+ $this->plugin->settings()->set_only_me_user_id( get_current_user_id() );
948
  }
949
 
950
+ $this->plugin->settings()->set_login_page_notification( isset( $post_array['login_page_notification'] ) ? sanitize_text_field( $post_array['login_page_notification'] ) : false );
951
+ $this->plugin->settings()->set_login_page_notification_text( isset( $post_array['login_page_notification_text'] ) ? $post_array['login_page_notification_text'] : false );
952
+ $this->plugin->settings()->set_main_ip_from_proxy( isset( $post_array['EnableProxyIpCapture'] ) ? sanitize_text_field( $post_array['EnableProxyIpCapture'] ) : false );
953
+ $this->plugin->settings()->set_internal_ips_filtering( isset( $post_array['EnableIpFiltering'] ) ? sanitize_text_field( $post_array['EnableIpFiltering'] ) : false );
954
 
955
  $is_incognito = isset( $post_array['Incognito'] ) ? \WSAL\Helpers\Options::string_to_bool( sanitize_text_field( $post_array['Incognito'] ) ) : false;
956
+ $this->plugin->settings()->set_incognito( $is_incognito );
957
  }
958
 
959
  /**
961
  */
962
  private function tab_audit_log() {
963
  ?>
964
+ <h3><?php esc_html_e( 'For how long do you want to keep the activity log events (Retention settings)?', 'wp-security-audit-log' ); ?></h3>
965
+ <p class="description">
966
  <?php
967
  esc_html_e( 'The plugin uses an efficient way to store the activity log data in the WordPress database, though the more data you keep the more disk space will be required. ', 'wp-security-audit-log' );
968
  $retention_help_text = __( '<a href="https://wpactivitylog.com/pricing/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=settings+pages" target="_blank">Upgrade to Premium</a> to store the activity log data in an external database.', 'wp-security-audit-log' );
969
 
970
+ echo wp_kses( $retention_help_text, $this->plugin->allowed_html_tags );
971
  ?>
972
+ </p>
973
 
974
  <?php
975
+ // Ensure it doesn't load a 2nd time for premium users.
976
  if ( ! wsal_freemius()->can_use_premium_code() ) {
977
  $this->render_retention_settings_table();
978
  }
987
  <td>
988
  <fieldset>
989
  <?php
990
+ $timezone = $this->plugin->settings()->get_timezone();
991
 
992
  /**
993
  * Transform timezone values.
1019
  <th><?php esc_html_e( 'Show Milliseconds', 'wp-security-audit-log' ); ?></th>
1020
  <td>
1021
  <fieldset>
1022
+ <?php $show_milliseconds = $this->plugin->settings()->get_show_milliseconds(); ?>
1023
  <label for="show_milliseconds">
1024
  <input type="checkbox" name="show_milliseconds" id="show_milliseconds" style="margin-top: -2px;"
1025
  <?php checked( $show_milliseconds ); ?> value="yes">
1041
  <th><label for="timezone-default"><?php esc_html_e( 'User information in Activity log', 'wp-security-audit-log' ); ?></label></th>
1042
  <td>
1043
  <fieldset>
1044
+ <?php $type_username = $this->plugin->settings()->get_type_username(); ?>
1045
  <label for="column_username">
1046
  <input type="radio" name="type_username" id="column_username" style="margin-top: -2px;" <?php checked( $type_username, 'username' ); ?> value="username">
1047
  <span><?php esc_html_e( 'WordPress username', 'wp-security-audit-log' ); ?></span>
1072
  <th><label for="columns"><?php esc_html_e( 'Activity log columns selection', 'wp-security-audit-log' ); ?></label></th>
1073
  <td>
1074
  <fieldset>
1075
+ <?php $columns = $this->plugin->settings()->get_columns(); ?>
1076
  <?php foreach ( $columns as $key => $value ) { ?>
1077
  <label for="columns">
1078
  <input type="checkbox" name="Columns[<?php echo esc_attr( $key ); ?>]" id="<?php echo esc_attr( $key ); ?>" class="sel-columns" style="margin-top: -2px;"
1103
  </table>
1104
  <!-- Activity log columns -->
1105
 
1106
+ <?php $is_wp_backend = $this->plugin->settings()->is_wp_backend(); ?>
1107
  <h3><?php esc_html_e( 'Do you want to keep a log of WordPress background activity?', 'wp-security-audit-log' ); ?></h3>
1108
  <p class="description">
1109
  <?php esc_html_e( 'WordPress does a lot of things in the background that you do not necessarily need to know about, such as; deletion of post revisions, deletion of auto saved drafts etc. By default the plugin does not report them since there might be a lot and are irrelevant to the user.', 'wp-security-audit-log' ); ?>
1145
  $pruning_unit = isset( $post_array['pruning-unit'] ) ? sanitize_text_field( $post_array['pruning-unit'] ) : false;
1146
  $pruning_date = ( ! empty( $pruning_date ) && ! empty( $pruning_unit ) ) ? $pruning_date . ' ' . $pruning_unit : false;
1147
 
1148
+ $this->plugin->settings()->set_pruning_date_enabled( isset( $post_array['PruneBy'] ) ? 'date' === $post_array['PruneBy'] : '' );
1149
+ $this->plugin->settings()->set_pruning_date( $pruning_date );
1150
+ $this->plugin->settings()->set_pruning_unit( $pruning_unit );
1151
+ $this->plugin->settings()->set_timezone( $post_array['Timezone'] );
1152
+ $this->plugin->settings()->set_type_username( $post_array['type_username'] );
1153
+ $this->plugin->settings()->set_wp_backend( isset( $post_array['WPBackend'] ) ? sanitize_text_field( $post_array['WPBackend'] ) : false );
1154
  if ( ! empty( $post_array['Columns'] ) ) {
1155
+ $this->plugin->settings()->set_columns( $post_array['Columns'] );
1156
  }
1157
+ $show_milliseconds = isset( $post_array['show_milliseconds'] ) && 'yes' === $post_array['show_milliseconds'];
1158
+ $this->plugin->settings()->set_show_milliseconds( $show_milliseconds );
1159
  }
1160
 
1161
  /**
1169
  <tr>
1170
  <?php if ( ! defined( 'WFCM_PLUGIN_FILE' ) ) : ?>
1171
  <div class="addon-wrapper" style="max-width: 380px; text-align: center; border: 1px solid #ccc; padding: 25px;">
1172
+ <img src="<?php echo esc_html( trailingslashit( WSAL_BASE_URL ) . 'img/help/website-file-changes-monitor.jpg' ); ?>">
1173
  <h4><?php echo esc_html__( 'Website File Changes Monitor', 'wp-security-audit-log' ); ?></h4>
1174
  <p><?php echo esc_html__( 'To keep a log of file changes please install Website File Changes Monitor, a plugin which is also developed by us.', 'wp-security-audit-log' ); ?></p><br>
1175
+ <p><button class="install-addon button button-primary" data-nonce="<?php echo esc_attr( wp_create_nonce( 'wsal-install-addon' ) ); ?>" data-plugin-slug="website-file-changes-monitor/website-file-changes-monitor.php" data-plugin-download-url="https://downloads.wordpress.org/plugin/website-file-changes-monitor.latest-stable.zip"><?php esc_html_e( 'Install plugin now', 'wp-security-audit-log' ); ?></button><span class="spinner" style="display: none; visibility: visible; float: none; margin: 0 0 0 8px;"></span> <a href="https://wpactivitylog.com/support/kb/wordpress-files-changes-warning-activity-logs/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=settings+pages" rel="noopener noreferrer" target="_blank" style="margin-left: 15px;"><?php esc_html_e( 'Learn More', 'wp-security-audit-log' ); ?></a></p>
1176
  </div>
1177
  <?php else : ?>
1178
  <?php
1179
+ $redirect_args = array(
 
1180
  'page' => 'wfcm-file-changes',
1181
  );
1182
  if ( ! is_multisite() ) {
1210
  <input type="button" id="ExUserQueryAdd" class="button-primary" value="<?php esc_attr_e( 'Add', 'wp-security-audit-log' ); ?>">
1211
  <br style="clear: both;"/>
1212
  <div id="ExUserList">
1213
+ <?php foreach ( $this->plugin->settings()->get_excluded_monitoring_users() as $item ) : ?>
1214
+ <span class="sectoken-<?php echo esc_attr( $this->get_token_type( $item ) ); ?>">
1215
  <input type="hidden" name="ExUsers[]" value="<?php echo esc_attr( $item ); ?>"/>
1216
  <?php echo esc_html( $item ); ?>
1217
  <a href="javascript:;" title="<?php esc_attr_e( 'Remove', 'wp-security-audit-log' ); ?>">&times;</a>
1231
  <input type="button" id="ExRoleQueryAdd" class="button-primary" value="<?php esc_attr_e( 'Add', 'wp-security-audit-log' ); ?>">
1232
  <br style="clear: both;"/>
1233
  <div id="ExRoleList">
1234
+ <?php foreach ( $this->plugin->settings()->get_excluded_monitoring_roles() as $item ) : ?>
1235
+ <span class="sectoken-<?php echo esc_attr( $this->get_token_type( $item ) ); ?>">
1236
  <input type="hidden" name="ExRoles[]" value="<?php echo esc_attr( $item ); ?>"/>
1237
  <?php echo esc_html( $item ); ?>
1238
  <a href="javascript:;" title="<?php esc_attr_e( 'Remove', 'wp-security-audit-log' ); ?>">&times;</a>
1252
  <input type="button" id="IpAddrQueryAdd" class="button-primary" value="<?php esc_attr_e( 'Add', 'wp-security-audit-log' ); ?>">
1253
  <br style="clear: both;"/>
1254
  <div id="IpAddrList">
1255
+ <?php foreach ( $this->plugin->settings()->get_excluded_monitoring_ip() as $item ) : ?>
1256
+ <span class="sectoken-<?php echo esc_attr( $this->get_token_type( $item ) ); ?>">
1257
  <input type="hidden" name="IpAddrs[]" value="<?php echo esc_attr( $item ); ?>"/>
1258
  <?php echo esc_html( $item ); ?>
1259
  <a href="javascript:;" title="<?php esc_attr_e( 'Remove', 'wp-security-audit-log' ); ?>">&times;</a>
1260
  </span>
1261
  <?php endforeach; ?>
1262
+ </div>
1263
+ </fieldset>
1264
+ <p class="description"><?php esc_html_e( 'You can exclude an individual IP address or a range of IP addresses. To exclude a range use the following format: [first IP]-[last octet of the last IP]. Example: 172.16.180.6-127.', 'wp-security-audit-log' ); ?></p>
1265
+ </td>
1266
+ </tr>
1267
+ <!-- Exclude IP Addresses -->
1268
+
1269
+ <tr>
1270
+ <th><label for="ExCPTsQueryBox"><?php esc_html_e( 'Exclude Post Type:', 'wp-security-audit-log' ); ?></label></th>
1271
+ <td>
1272
+ <fieldset>
1273
+ <input type="text" id="ExCPTsQueryBox" style="width: 250px;">
1274
+ <input type="button" id="ExCPTsQueryAdd" class="button-primary" value="<?php esc_attr_e( 'Add', 'wp-security-audit-log' ); ?>">
1275
+ <br style="clear: both;"/>
1276
+ <div id="ExCPTsList">
1277
+ <?php foreach ( $this->plugin->settings()->get_excluded_post_types() as $item ) : ?>
1278
+ <span class="sectoken-<?php echo esc_attr( $this->get_token_type( $item ) ); ?>">
1279
  <input type="hidden" name="ExCPTss[]" value="<?php echo esc_attr( $item ); ?>"/>
1280
  <?php echo esc_html( $item ); ?>
1281
  <a href="javascript:;" title="<?php esc_attr_e( 'Remove', 'wp-security-audit-log' ); ?>">&times;</a>
1282
  </span>
1283
  <?php endforeach; ?>
1284
+ </div>
1285
+ </fieldset>
1286
+ <p class="description"><?php esc_html_e( 'WordPress has the post and page post types by default though your website might use more post types (custom post types). You can exclude all post types, including the default WordPress ones.', 'wp-security-audit-log' ); ?></p>
1287
+ </td>
1288
+ </tr>
1289
+ <!-- Exclude Custom Post Types -->
1290
+
1291
+ <?php
1292
+ $this->renderMetaExclusionSection(
1293
+ esc_html__( 'Exclude custom post fields:', 'wp-security-audit-log' ),
1294
+ $this->plugin->settings()->get_excluded_post_meta_fields(),
1295
+ 'PostMeta'
1296
+ );
1297
+ ?>
1298
+ <!-- Exclude Custom Post Fields -->
1299
 
1300
  <?php
1301
  $this->renderMetaExclusionSection(
1302
  esc_html__( 'Exclude custom user fields:', 'wp-security-audit-log' ),
1303
+ $this->plugin->settings()->get_excluded_user_meta_fields(),
1304
  'UserMeta'
1305
  );
1306
+ ?>
1307
+ <!-- Exclude Custom User Fields -->
1308
 
1309
+ </tbody>
1310
+ </table>
1311
+ <!-- / Exclude Objects Tab -->
1312
  <?php
1313
  }
1314
 
1315
+ /**
1316
+ * Renders form section for excluding metadata of certain object type.
1317
+ *
1318
+ * @param string $title Section title.
1319
+ * @param array $values Values.
1320
+ * @param string $type Object type.
1321
+ */
1322
  private function renderMetaExclusionSection( $title, $values, $type ) {
1323
+ // @codingStandardsIgnoreStart
1324
  ?>
1325
+ <tr>
1326
+ <th><label for="Custom<?php echo $type; ?>QueryBox"><?php echo $title; ?></label></th>
1327
+ <td>
1328
+ <fieldset data-type="<?php echo $type; ?>">
1329
+ <input type="text" id="<?php echo $type; ?>QueryBox" class="js-query-box" style="width: 250px;">
1330
+ <input type="button" id="<?php echo $type; ?>QueryAdd" class="js-query-add button-primary"
1331
+ value="<?php esc_attr_e( 'Add', 'wp-security-audit-log' ); ?>">
1332
+ <br style="clear: both;"/>
1333
+ <div id="<?php echo $type; ?>List" class="js-list">
1334
  <?php foreach ( $values as $item ) : ?>
1335
+ <span class="sectoken-<?php echo esc_attr( $this->get_token_type( $item ) ); ?>">
1336
  <input type="hidden" name="<?php echo $type; ?>s[]"
1337
+ value="<?php echo esc_attr( $item ); ?>"/>
1338
  <?php echo esc_html( $item ); ?>
1339
  <a href="javascript:;" title="<?php esc_attr_e( 'Remove', 'wp-security-audit-log' ); ?>">&times;</a>
1340
  </span>
1341
  <?php endforeach; ?>
1342
+ </div>
1343
+ </fieldset>
1344
+ <p class="description"><?php esc_html_e( 'You can use the * wildcard to exclude multiple matching custom fields. For example to exclude all custom fields starting with wp123 enter wp123*', 'wp-security-audit-log' ); ?></p>
1345
+ </td>
1346
+ </tr>
1347
  <?php
1348
+ // @codingStandardsIgnoreEnd
1349
  }
1350
 
1351
  /**
1355
  // Get $_POST global array.
1356
  $post_array = filter_input_array( INPUT_POST );
1357
 
1358
+ $this->plugin->settings()->set_excluded_monitoring_users( isset( $post_array['ExUsers'] ) ? $post_array['ExUsers'] : array() );
1359
+ $this->plugin->settings()->set_excluded_monitoring_roles( isset( $post_array['ExRoles'] ) ? $post_array['ExRoles'] : array() );
1360
+ $this->plugin->settings()->set_excluded_post_meta_fields( isset( $post_array['PostMetas'] ) ? $post_array['PostMetas'] : array() );
1361
+ $this->plugin->settings()->set_excluded_user_meta_fields( isset( $post_array['UserMetas'] ) ? $post_array['UserMetas'] : array() );
1362
+ $this->plugin->settings()->set_excluded_monitoring_ip( isset( $post_array['IpAddrs'] ) ? $post_array['IpAddrs'] : array() );
1363
+ $this->plugin->settings()->set_excluded_post_types( isset( $post_array['ExCPTss'] ) ? $post_array['ExCPTss'] : array() );
1364
  }
1365
 
1366
  /**
1368
  */
1369
  private function tab_advanced_settings() {
1370
  ?>
1371
+ <p class="description">
1372
  <?php esc_html_e( 'These settings are for advanced users.', 'wp-security-audit-log' ); ?>
1373
+ <?php echo sprintf( __( 'If you have any questions <a href="https://wpactivitylog.com/contact/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=settings+pages" target="_blank">contact us</a>.', 'wp-security-audit-log' ), $this->plugin->allowed_html_tags ); // phpcs:ignore ?>
1374
  </p>
1375
 
1376
+ <h3><?php esc_html_e( 'Reset plugin settings to default', 'wp-security-audit-log' ); ?></h3>
1377
+ <p class="description"><?php _e( 'Use this button to <em>factory reset</em> the plugin. This means that all the configured settings will be reset to default and all email notifications, scheduled reports, external database / third party services connections, archiving and mirroring rule will be deleted. NOTE: the activity log data will not be purged. Use the setting below to purge the activity log.', 'wp-security-audit-log' ); // phpcs:ignore ?></p>
1378
+ <table class="form-table wsal-tab">
1379
+ <tbody>
1380
+ <tr>
1381
+ <th><?php esc_html_e( 'Reset Settings', 'wp-security-audit-log' ); ?></th>
1382
+ <td>
1383
+ <a href="#wsal_reset_settings" class="button-primary js-settings-reset"><?php esc_html_e( 'RESET', 'wp-security-audit-log' ); ?></a>
1384
+ </td>
1385
+ </tr>
1386
+ </tbody>
1387
+ </table>
1388
 
1389
  <h3><?php esc_html_e( 'Purge the WordPress activity log', 'wp-security-audit-log' ); ?></h3>
1390
  <p class="description"><?php esc_html_e( 'Click the Purge button below to delete all the data from the WordPress activity log and start afresh.', 'wp-security-audit-log' ); ?></p>
1399
  </tbody>
1400
  </table>
1401
 
1402
+ <?php $stealth_mode = $this->plugin->settings()->is_stealth_mode(); ?>
1403
  <h3><?php esc_html_e( 'MainWP Child Site Stealth Mode', 'wp-security-audit-log' ); ?></h3>
1404
  <p class="description"><?php esc_html_e( 'This option is enabled automatically when the plugin detects the MainWP Child plugin on the site. When this setting is enabled plugin access is restricted to the administrator who installs the plugin, the plugin is not shown in the list of installed plugins and no admin notifications are shown. Disable this option to change the plugin to the default setup.', 'wp-security-audit-log' ); ?></p>
1405
  <table class="form-table wsal-tab">
1423
  </td>
1424
  </tr>
1425
  <!-- / MainWP Child Site Stealth Mode -->
1426
+ <?php $admin_blocking_plugins_support = $this->plugin->settings()->get_admin_blocking_plugin_support(); ?>
1427
  <tr>
1428
  <th>
1429
  <label for="mwp_admin_blocking_support"><?php esc_html_e( 'Admin blocking plugins support', 'wp-security-audit-log' ); ?></label>
1442
  </tbody>
1443
  </table>
1444
 
1445
+ <?php
1446
+ $data_deletion_enabled = $this->plugin->settings()->is_delete_data();
1447
+ ?>
1448
  <h3><?php esc_html_e( 'Do you want to delete the plugin data from the database upon uninstall?', 'wp-security-audit-log' ); ?></h3>
1449
  <p class="description"><?php esc_html_e( 'The plugin saves the activity log data and settings in the WordPress database. By default upon uninstalling the plugin the data is kept in the database so if it is installed again, you can still access the data. If the data is deleted it is not possible to recover it so you won\'t be able to access it again even when you reinstall the plugin.', 'wp-security-audit-log' ); ?></p>
1450
  <table class="form-table wsal-tab">
1455
  <fieldset>
1456
  <label for="delete_data_yes">
1457
  <input type="radio" name="DeleteData" value="1" id="delete_data_yes" onclick="return delete_confirm(this);"
1458
+ <?php checked( $data_deletion_enabled ); ?>
1459
  />
1460
  <?php esc_html_e( 'Yes', 'wp-security-audit-log' ); ?>
1461
  </label>
1462
  <br>
1463
  <label for="delete_data_no">
1464
  <input type="radio" name="DeleteData" value="0" id="delete_data_no"
1465
+ <?php checked( $data_deletion_enabled, false ); ?>
1466
  />
1467
  <?php esc_html_e( 'No', 'wp-security-audit-log' ); ?>
1468
  </label>
1473
  </tbody>
1474
  </table>
1475
 
1476
+ <div class="remodal" data-remodal-id="wsal_reset_settings">
1477
+ <button data-remodal-action="close" class="remodal-close"></button>
1478
+ <h3><?php esc_html_e( 'Are you sure you want to reset all the plugin settings to default? This action cannot be undone.', 'wp-security-audit-log' ); ?></h3>
1479
+ <br>
1480
+ <input type="hidden" id="wsal-reset-settings-nonce" value="<?php echo esc_attr( wp_create_nonce( 'wsal-reset-settings' ) ); ?>">
1481
+ <button data-remodal-action="confirm" class="remodal-confirm"><?php esc_html_e( 'Yes' ); ?></button>
1482
+ <button data-remodal-action="cancel" class="remodal-cancel"><?php esc_html_e( 'No' ); ?></button>
1483
+ </div>
1484
+ <!-- Reset Settings Modal -->
1485
 
1486
  <div class="remodal" data-remodal-id="wsal_purge_activity">
1487
  <button data-remodal-action="close" class="remodal-close"></button>
1504
  // Get $_POST global array.
1505
  $post_array = filter_input_array( INPUT_POST );
1506
 
1507
+ $this->plugin->settings()->set_delete_data( isset( $post_array['DeleteData'] ) ? sanitize_text_field( $post_array['DeleteData'] ) : false );
1508
 
1509
  $stealth_mode = isset( $post_array['mwp_stealth_mode'] ) ? $post_array['mwp_stealth_mode'] : false;
1510
  if ( 'yes' === $stealth_mode ) {
1511
  if ( ! WpSecurityAuditLog::is_mainwp_active() ) {
1512
  throw new Exception( __( 'MainWP Child plugin is not active on this website.', 'wp-security-audit-log' ) );
1513
  }
1514
+ $this->plugin->settings()->set_mainwp_child_stealth_mode();
1515
 
1516
  $admin_blocking_plugins_support = isset( $post_array['mwp_admin_blocking_support'] ) ? $post_array['mwp_admin_blocking_support'] : false;
1517
  if ( 'yes' === $admin_blocking_plugins_support ) {
1518
+ $this->plugin->settings()->set_admin_blocking_plugin_support( true );
1519
  }
1520
  } else {
1521
+ $this->plugin->settings()->deactivate_mainwp_child_stealth_mode();
1522
  }
1523
  }
1524
 
1525
  /**
1526
+ * {@inheritDoc}
1527
  */
1528
+ public function header() {
1529
  wp_enqueue_style(
1530
  'settings',
1531
+ $this->plugin->get_base_url() . '/css/settings.css',
1532
  array(),
1533
+ filemtime( $this->plugin->get_base_dir() . '/css/settings.css' )
1534
  );
1535
 
1536
  // Check current tab.
1540
  wp_enqueue_style( 'wsal-remodal-theme', WSAL_BASE_URL . 'css/remodal-default-theme.css', array(), '1.1.1' );
1541
  }
1542
  ?>
1543
+ <style type="text/css">
1544
+ .wsal-tab {
1545
+ /* display: none; */
1546
+ }
1547
+ .wsal-tab tr.alert-incomplete td {
1548
+ color: #9BE;
1549
+ }
1550
+ .wsal-tab tr.alert-unavailable td {
1551
+ color: #CCC;
1552
+ }
1553
+ </style>
1554
  <?php
1555
  }
1556
 
1557
  /**
1558
+ * {@inheritDoc}
1559
  */
1560
+ public function footer() {
1561
  // Enqueue jQuery UI from core.
1562
  wp_enqueue_script(
1563
  'wsal-jquery-ui',
1582
  // Register settings script.
1583
  wp_register_script(
1584
  'settings',
1585
+ $this->plugin->get_base_url() . '/js/settings.js',
1586
  array(),
1587
+ filemtime( $this->plugin->get_base_dir() . '/js/settings.js' ),
1588
  true
1589
  );
1590
  // Passing nonce for security to JS file.
1603
  wp_localize_script( 'settings', 'wsal_data', $wsal_data );
1604
  wp_enqueue_script( 'settings' );
1605
  ?>
1606
+ <script type="text/javascript">
1607
+ jQuery( document ).ready( function() {
1608
+ jQuery( '.sel-columns' ).change( function() {
1609
+ var notChecked = 1;
1610
+ jQuery( '.sel-columns' ).each( function() {
1611
+ if ( this.checked ) notChecked = 0;
1612
+ })
1613
+ if ( notChecked == 1 ) {
1614
+ alert( "<?php esc_html_e( 'You have to select at least one column!', 'wp-security-audit-log' ); ?>" );
1615
+ }
1616
+ });
1617
+ });</script>
1618
  <?php
1619
  }
1620
 
1621
  /**
1622
  * Method: Ajax Request handler for AjaxGetAllUsers.
1623
  */
1624
+ public function ajax_get_all_users() {
1625
  // Filter $_GET array for security.
1626
  $get_array = filter_input_array( INPUT_GET );
1627
  $this->check_ajax_request_is_valid( $get_array );
1640
  /**
1641
  * Method: Ajax Request handler for AjaxGetAllRoles.
1642
  */
1643
+ public function ajax_get_all_roles() {
1644
  // Filter $_GET array for security.
1645
  $get_array = filter_input_array( INPUT_GET );
1646
  $this->check_ajax_request_is_valid( $get_array );
1667
  $get_array = filter_input_array( INPUT_GET );
1668
  $this->check_ajax_request_is_valid( $get_array );
1669
 
1670
+ echo $this->filter_values_for_searched_term( // phpcs:ignore
1671
+ array_values( WSAL_ConstantManager::get_severities() ),
1672
+ $get_array['term'] // phpcs:ignore
1673
+ );
1674
  exit;
1675
  }
1676
 
1677
  /**
1678
  * Filters values to return ones matching the desired term.
1679
  *
1680
+ * @param array $items_to_filter List of items to filter.
1681
+ * @param string $term Search term.
1682
+ *
1683
+ * @return string JSON encoded filtered list.
1684
  */
1685
  public function filter_values_for_searched_term( $items_to_filter, $term ) {
1686
 
1687
+ $result = array_filter(
1688
+ $items_to_filter,
1689
+ function( $value ) use ( $term ) {
1690
+ return strpos( strtolower( $value ), strtolower( $term ) ) !== false;
1691
+ }
1692
+ );
1693
 
1694
  return wp_json_encode( $result );
1695
  }
1705
  $get_array = filter_input_array( INPUT_GET );
1706
  $this->check_ajax_request_is_valid( $get_array );
1707
 
1708
+ $event_types = $this->plugin->alerts->get_event_type_data();
1709
 
1710
+ echo $this->filter_values_for_searched_term( array_values( $event_types ), $get_array['term'] ); // phpcs:ignore
1711
  exit;
1712
  }
1713
 
1722
  $get_array = filter_input_array( INPUT_GET );
1723
  $this->check_ajax_request_is_valid( $get_array );
1724
 
1725
+ $event_objects = $this->plugin->alerts->get_event_objects_data();
1726
 
1727
+ echo $this->filter_values_for_searched_term( array_values( $event_objects ), $get_array['term'] ); // phpcs:ignore
1728
  exit;
1729
  }
1730
 
1739
  $get_array = filter_input_array( INPUT_GET );
1740
  $this->check_ajax_request_is_valid( $get_array );
1741
 
1742
+ $registered_alerts = $this->plugin->alerts->get_alerts();
1743
 
1744
+ $alerts = array();
1745
  foreach ( $registered_alerts as $alert => $details ) {
1746
  $alerts[] = (string) $details->code;
1747
  }
1748
 
1749
+ echo $this->filter_values_for_searched_term( array_values( $alerts ), $get_array['term'] ); // phpcs:ignore
1750
  exit;
1751
  }
1752
 
1755
  *
1756
  * @since 2.6.7
1757
  */
1758
+ public function ajax_get_all_cpts() {
1759
  // Filter $_GET array for security.
1760
  $get_array = filter_input_array( INPUT_GET );
1761
  $this->check_ajax_request_is_valid( $get_array );
1762
 
1763
  // Get custom post types.
1764
  $custom_post_types = array();
1765
+ $post_types = get_post_types(
1766
+ array(
1767
+ 'public' => false,
1768
+ ),
1769
+ 'names'
1770
+ );
1771
  // if we are running multisite and have networkwide cpt tracker get the
1772
  // list from and merge to the post_types array.
1773
  if ( is_multisite() && class_exists( '\WSAL\Multisite\NetworkWide\CPTsTracker' ) ) {
1776
  $post_types[ $cpt ] = $cpt;
1777
  }
1778
  }
1779
+
1780
  $post_types = array_diff( $post_types, array( 'attachment', 'revision', 'nav_menu_item', 'customize_changeset', 'custom_css' ) );
1781
  foreach ( $post_types as $post_type ) {
1782
  if ( strpos( $post_type, $get_array['term'] ) !== false ) {
1790
  /**
1791
  * Checks if provided GET array is valid and bails if not.
1792
  *
1793
+ * @param array $get_array Get data.
 
1794
  */
1795
  public function check_ajax_request_is_valid( $get_array ) {
1796
  // Die if user does not have permission to edit.
1797
+ if ( ! $this->plugin->settings()->current_user_can( 'edit' ) ) {
1798
  die( 'Access Denied.' );
1799
  }
1800
+
1801
  // Die if nonce verification failed.
1802
  if ( ! wp_verify_nonce( $get_array['wsal_nonce'], 'wsal-exclude-nonce' ) ) {
1803
  die( esc_html__( 'Nonce verification failed.', 'wp-security-audit-log' ) );
1809
  */
1810
  public function reset_settings() {
1811
  // Die if user does not have permission to change settings.
1812
+ if ( ! $this->plugin->settings()->current_user_can( 'edit' ) ) {
1813
  wp_send_json_error( esc_html__( 'Access Denied.', 'wp-security-audit-log' ) );
1814
  }
1815
 
1819
  wp_send_json_error( esc_html__( 'Nonce Verification Failed.', 'wp-security-audit-log' ) );
1820
  }
1821
 
1822
+ // Delete all settings.
1823
+ WSAL_Uninstall::delete_options_from_wp_options();
1824
 
1825
+ // Log settings reset event.
1826
+ $this->plugin->alerts->trigger_event( 6006 );
1827
+ wp_send_json_success( esc_html__( 'Plugin settings have been reset.', 'wp-security-audit-log' ) );
1828
  }
1829
 
1830
  /**
1831
  * Method: Purge plugin occurrence & meta tables.
1832
  */
1833
+ public function purge_activity() {
1834
  // Die if user does not have permission to change settings.
1835
+ if ( ! $this->plugin->settings()->current_user_can( 'edit' ) ) {
1836
  wp_send_json_error( esc_html__( 'Access Denied.', 'wp-security-audit-log' ) );
1837
  }
1838
 
1842
  wp_send_json_error( esc_html__( 'Nonce Verification Failed.', 'wp-security-audit-log' ) );
1843
  }
1844
 
1845
+ $connector = WpSecurityAuditLog::get_connector();
1846
+ $result = $connector->purge_activity();
1847
 
1848
+ if ( $result ) {
1849
+ // Log purge activity event.
1850
+ $this->plugin->alerts->trigger_event( 6034 );
1851
+ wp_send_json_success( esc_html__( 'Tables has been reset.', 'wp-security-audit-log' ) );
1852
+ } else {
1853
+ wp_send_json_error( esc_html__( 'Reset query failed.', 'wp-security-audit-log' ) );
1854
+ }
1855
  }
1856
 
1857
+ /**
1858
+ * Renders table with retention related settings.
1859
+ */
1860
+ public function render_retention_settings_table() {
1861
+ // Check if the retention settings are enforced from the MainWP master site.
1862
+ $settings = $this->plugin->settings();
1863
+ $enforced_settings = $settings->get_mainwp_enforced_settings();
1864
+ $retention_settings_enforced_by_mainwp = array_key_exists( 'pruning_enabled', $enforced_settings );
1865
+ ?>
1866
+ <table class="form-table wsal-tab">
1867
+ <tbody>
1868
+ <tr>
1869
+ <th><label for="delete1"><?php esc_html_e( 'Activity log retention', 'wp-security-audit-log' ); ?></label></th>
1870
+ <td>
1871
+ <fieldset>
1872
+ <?php $nbld = ! $this->plugin->settings()->is_pruning_date_enabled(); ?>
1873
+ <label for="delete0">
1874
+ <input type="radio" id="delete0" name="PruneBy" value="" <?php checked( $nbld ); ?>
1875
+ <?php disabled( $retention_settings_enforced_by_mainwp ); ?> />
1876
+ <?php esc_html_e( 'Keep all data', 'wp-security-audit-log' ); ?>
1877
+ </label>
1878
+ </fieldset>
1879
+
1880
+ <fieldset>
1881
+ <?php
1882
+ // Check pruning date option.
1883
+ $nbld = $this->plugin->settings()->is_pruning_date_enabled();
1884
+
1885
+ // Find and replace ` months` in the string.
1886
+ $pruning_date = $this->plugin->settings()->get_pruning_date();
1887
+ $pruning_date = preg_replace( '/[^0-9]/', '', $pruning_date );
1888
+
1889
+ $pruning_unit = $this->plugin->settings()->get_pruning_unit();
1890
+
1891
+ $pruning_unit_options = array(
1892
  'days' => esc_html__( 'Days', 'wp-security-audit-log' ),
1893
  'months' => esc_html__( 'Months', 'wp-security-audit-log' ),
1894
  'years' => esc_html__( 'Years', 'wp-security-audit-log' ),
1895
+ );
1896
+
1897
+ // Check if pruning limit was enabled for backwards compatibility.
1898
+ if ( $this->plugin->settings()->is_pruning_limit_enabled() ) {
1899
+ $nbld = true;
1900
+ $pruning_date = '6';
1901
+ $pruning_unit = 'months';
1902
+ $this->plugin->settings()->set_pruning_date( $pruning_date . ' ' . $pruning_unit );
1903
+ $this->plugin->settings()->set_pruning_date_enabled( true );
1904
+ $this->plugin->settings()->set_pruning_limit_enabled( false );
1905
+ }
1906
+ ?>
1907
+ <label for="delete1">
1908
+ <input type="radio" id="delete1" name="PruneBy" value="date" <?php checked( $nbld ); ?>
1909
+ <?php disabled( $retention_settings_enforced_by_mainwp ); ?> />
1910
+ <?php esc_html_e( 'Delete events older than', 'wp-security-audit-log' ); ?>
1911
+ </label>
1912
+ <input type="text" id="PruningDate" name="PruningDate"
1913
+ value="<?php echo esc_attr( $pruning_date ); ?>"
1914
+ onfocus="jQuery('#delete1').attr('checked', true);"
1915
+ <?php disabled( $retention_settings_enforced_by_mainwp ); ?>
1916
+ />
1917
+ <select name="pruning-unit" id="pruning-unit" <?php disabled( $retention_settings_enforced_by_mainwp ); ?>>
1918
+ <?php
1919
+ foreach ( $pruning_unit_options as $option => $label ) {
1920
+ echo '<option value="' . esc_attr( $option ) . '" ' . selected( $pruning_unit, $option, true ) . '>' . ucwords( $label ) . '</option>'; // phpcs:disable
1921
+ }
1922
+ ?>
1923
+ </select>
1924
+ </fieldset>
1925
+
1926
+ <?php if ( $this->plugin->settings()->is_pruning_date_enabled() ) : ?>
1927
+ <p class="description">
1928
+ <?php
1929
+ $next = wp_next_scheduled( 'wsal_cleanup' );
1930
+ echo esc_html__( 'The next scheduled purging of activity log data that is older than ', 'wp-security-audit-log' );
1931
+ echo esc_html( $pruning_date . ' ' . $pruning_unit );
1932
+ echo sprintf(
1933
+ ' is in %s.',
1934
+ esc_html( human_time_diff( current_time( 'timestamp' ), $next ) )
1935
+ );
1936
+ echo '<!-- ' . esc_html( date( 'dMy H:i:s', $next ) ) . ' --> ';
1937
+ echo esc_html__( 'You can run the purging process now by clicking the button below.', 'wp-security-audit-log' );
1938
+ ?>
1939
+ </p>
1940
+ <p>
1941
+ <a class="button-primary" href="<?php echo esc_url( add_query_arg( 'action', 'AjaxRunCleanup', admin_url( 'admin-ajax.php' ) ) ); ?>"><?php esc_html_e( 'Purge Old Data', 'wp-security-audit-log' ); ?></a>
1942
+ </p>
1943
+ <?php endif; ?>
1944
+ </td>
1945
+ </tr>
1946
+ <!-- Activity log retention -->
1947
+ </tbody>
1948
+ </table>
1949
+ <?php
1950
+ }
1951
  }
classes/Views/SetupWizard.php CHANGED
@@ -4,8 +4,9 @@
4
  *
5
  * WSAL setup class file.
6
  *
7
- * @since 3.2.3
8
- * @package wsal
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -18,6 +19,9 @@ if ( ! defined( 'ABSPATH' ) ) {
18
  *
19
  * WSAL setup wizard class which manages the functionality
20
  * related to setup.
 
 
 
21
  */
22
  final class WSAL_Views_SetupWizard {
23
 
@@ -26,7 +30,7 @@ final class WSAL_Views_SetupWizard {
26
  *
27
  * @var WpSecurityAuditLog
28
  */
29
- private $wsal;
30
 
31
  /**
32
  * Wizard Steps
@@ -62,9 +66,9 @@ final class WSAL_Views_SetupWizard {
62
  * @param WpSecurityAuditLog $wsal – Instance of main plugin.
63
  */
64
  public function __construct( WpSecurityAuditLog $wsal ) {
65
- $this->wsal = $wsal;
66
 
67
- if ( $wsal->settings()->CurrentUserCan( 'edit' ) ) {
68
  add_action( 'admin_init', array( $this, 'setup_page' ), 10 );
69
  add_action( 'admin_menu', array( $this, 'admin_menus' ), 10 );
70
  add_action( 'network_admin_menu', array( $this, 'admin_menus' ), 10 );
@@ -76,7 +80,7 @@ final class WSAL_Views_SetupWizard {
76
  * Ajax handler to verify setting token.
77
  */
78
  public function setup_check_security_token() {
79
- if ( ! $this->wsal->settings()->CurrentUserCan( 'edit' ) ) {
80
  echo wp_json_encode(
81
  array(
82
  'success' => false,
@@ -154,7 +158,7 @@ final class WSAL_Views_SetupWizard {
154
  $all_plugins = get_plugins();
155
  $plugin_filenames = array();
156
  foreach ( $all_plugins as $plugin => $info ) {
157
- $plugin_info = pathinfo( $plugin );
158
  $plugin_filenames[] = $plugin_info['filename'];
159
  }
160
 
@@ -174,31 +178,31 @@ final class WSAL_Views_SetupWizard {
174
  * Wizard Steps.
175
  */
176
  $wizard_steps = array(
177
- 'welcome' => array(
178
  'name' => __( 'Welcome', 'wp-security-audit-log' ),
179
  'content' => array( $this, 'wsal_step_welcome' ),
180
  ),
181
- 'log_details' => array(
182
  'name' => __( 'Log Details', 'wp-security-audit-log' ),
183
  'content' => array( $this, 'wsal_step_log_details' ),
184
  'save' => array( $this, 'wsal_step_log_details_save' ),
185
  ),
186
- 'login' => array(
187
  'name' => __( 'Log In', 'wp-security-audit-log' ),
188
  'content' => array( $this, 'wsal_step_login' ),
189
  'save' => array( $this, 'wsal_step_login_save' ),
190
  ),
191
- 'register' => array(
192
  'name' => __( 'User Registrations', 'wp-security-audit-log' ),
193
  'content' => array( $this, 'wsal_step_register' ),
194
  'save' => array( $this, 'wsal_step_register_save' ),
195
  ),
196
- 'log_retention' => array(
197
  'name' => __( 'Log Retention', 'wp-security-audit-log' ),
198
  'content' => array( $this, 'wsal_step_log_retention' ),
199
  'save' => array( $this, 'wsal_step_log_retention_save' ),
200
  ),
201
- 'finish' => array(
202
  'name' => __( 'Finish', 'wp-security-audit-log' ),
203
  'content' => array( $this, 'wsal_step_finish' ),
204
  'save' => array( $this, 'wsal_step_finish_save' ),
@@ -226,39 +230,39 @@ final class WSAL_Views_SetupWizard {
226
  /**
227
  * Enqueue Styles.
228
  */
229
- $wizard_css = WSAL_ViewManager::get_asset_path('/css/dist/', 'wsal-wizard', 'css');
230
  wp_enqueue_style(
231
  'wsal-wizard-css',
232
- $this->wsal->GetBaseUrl() . $wizard_css,
233
  array( 'dashicons', 'install', 'forms' ),
234
- filemtime( $this->wsal->GetBaseDir() . $wizard_css )
235
  );
236
 
237
  /**
238
  * Enqueue Scripts.
239
  */
240
- $wizard_js = WSAL_ViewManager::get_asset_path( '/js/dist/', 'wsal-wizard', 'js');
241
  wp_register_script(
242
- 'wsal-wizard-js',
243
- $this->wsal->GetBaseUrl() .$wizard_js,
244
- array( 'jquery' ),
245
- filemtime( $this->wsal->GetBaseDir() .$wizard_js ),
246
- false
247
- );
248
-
249
- $common_js = '/js/common.js';
250
  wp_register_script(
251
  'wsal-common',
252
- $this->wsal->GetBaseUrl() . $common_js,
253
  array( 'jquery' ),
254
- filemtime( $this->wsal->GetBaseDir() . $common_js ),
255
  true
256
- );
257
 
258
  // Data array.
259
  $data_array = array(
260
  'ajaxURL' => admin_url( 'admin-ajax.php' ),
261
- 'nonce' => ( ( ! $this->wsal->settings()->CurrentUserCan( 'edit' ) ) && ! 'invalid-step' === $this->current_step ) ? wp_create_nonce( 'wsal-verify-wizard-page' ) : '',
262
  'usersError' => esc_html__( 'Specified value in not a user.', 'wp-security-audit-log' ),
263
  'rolesError' => esc_html__( 'Specified value in not a role.', 'wp-security-audit-log' ),
264
  'ipError' => esc_html__( 'Specified value in not an IP address.', 'wp-security-audit-log' ),
@@ -272,11 +276,10 @@ final class WSAL_Views_SetupWizard {
272
  'installed' => esc_html__( 'Extension installed', 'wp-security-audit-log' ),
273
  'activated' => esc_html__( 'Extension activated', 'wp-security-audit-log' ),
274
  'failed' => esc_html__( 'Install failed', 'wp-security-audit-log' ),
275
- 'reloading_page' => esc_html__( 'Reloading page', 'wp-security-audit-log' )
276
  );
277
  wp_localize_script( 'wsal-common', 'wsalCommonData', $installer_script_data );
278
 
279
-
280
  /**
281
  * Save Wizard Settings.
282
  */
@@ -309,7 +312,7 @@ final class WSAL_Views_SetupWizard {
309
  <?php do_action( 'admin_print_styles' ); ?>
310
  </head>
311
  <body class="wsal-setup wp-core-ui">
312
- <h1 id="wsal-logo"><a href="https://wpactivitylog.com/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=wizard+configuration" rel="noopener noreferrer" target="_blank"><img src="<?php echo esc_url( $this->wsal->GetBaseUrl() ); ?>/img/wsal-logo-full.png" alt="WP Activity Log" /></a></h1>
313
  <?php
314
  }
315
 
@@ -409,25 +412,23 @@ final class WSAL_Views_SetupWizard {
409
  * @since 4.0.2
410
  */
411
  private function render_invalid_step() {
412
- ?>
413
- <p><?php
414
  printf(
415
  /* translators: 1 - an opening link tag, 2 - a closing link tag. */
416
  esc_html__( 'You have reached an invaild step - %1$sreturn to the start of the wizard%2$s.', 'wp-security-audit-log' ),
417
  '<a href="' . esc_url( $this->get_welcome_step() ) . '">',
418
  '</a>'
419
  );
420
- ?></p>
421
- <?php
422
  }
423
 
424
  /**
425
  * Step View: `Welcome`
426
  */
427
  private function wsal_step_welcome() {
428
- // dismiss the setup modal in case if not already done
429
- if ( ! $this->wsal->GetGlobalBooleanSetting( 'setup-modal-dismissed', false ) ) {
430
- $this->wsal->SetGlobalBooleanSetting( 'setup-modal-dismissed', true, true );
431
  }
432
  ?>
433
  <p><?php esc_html_e( 'This wizard helps you configure the basic plugin settings. All these settings can be changed at a later stage from the plugin settings.', 'wp-security-audit-log' ); ?></p>
@@ -489,11 +490,11 @@ final class WSAL_Views_SetupWizard {
489
  }
490
 
491
  // Save log details option.
492
- $this->wsal->SetGlobalSetting( 'details-level', $log_details );
493
  if ( ! empty( $log_details ) && 'basic' === $log_details ) {
494
- $this->wsal->settings()->set_basic_mode();
495
  } elseif ( ! empty( $log_details ) && 'geek' === $log_details ) {
496
- $this->wsal->settings()->set_geek_mode();
497
  }
498
 
499
  wp_safe_redirect( esc_url_raw( $this->get_next_step() ) );
@@ -539,7 +540,7 @@ final class WSAL_Views_SetupWizard {
539
  if ( isset( $_POST['wsal-frontend-login'] ) ) {
540
  $frontend_sensors = WSAL_Settings::get_frontend_events(); // Get the frontend sensors setting.
541
  $login_sensor = sanitize_text_field( wp_unslash( $_POST['wsal-frontend-login'] ) );
542
- $login_sensor = '1' === $login_sensor ? true : false; // Update the sensor option.
543
 
544
  $frontend_sensors['login'] = $login_sensor;
545
  WSAL_Settings::set_frontend_events( $frontend_sensors );
@@ -588,7 +589,7 @@ final class WSAL_Views_SetupWizard {
588
  if ( isset( $_POST['wsal-frontend-register'] ) ) {
589
  $frontend_sensors = WSAL_Settings::get_frontend_events(); // Get the frontend sensors setting.
590
  $register_sensor = sanitize_text_field( wp_unslash( $_POST['wsal-frontend-register'] ) );
591
- $register_sensor = '1' === $register_sensor ? true : false; // Update the sensor option.
592
 
593
  $frontend_sensors['register'] = $register_sensor;
594
  WSAL_Settings::set_frontend_events( $frontend_sensors );
@@ -644,7 +645,7 @@ final class WSAL_Views_SetupWizard {
644
  // Step help text.
645
  $step_help = __( 'The plugin stores the data in the WordPress database in a very efficient way, though the more data you keep the more hard disk space it will consume. If you need need to retain a lot of data we would recommend you to <a href="https://wpactivitylog.com/features/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=wizard+configuration" target="_blank">upgrade to Premium</a> and use the Database tools to store the WordPress activity log in an external database.', 'wp-security-audit-log' );
646
 
647
- echo wp_kses( $step_help, $this->wsal->allowed_html_tags );
648
  ?>
649
  </em>
650
  </p>
@@ -673,13 +674,13 @@ final class WSAL_Views_SetupWizard {
673
  case '6':
674
  case '12':
675
  // 6 or 12 months.
676
- $this->wsal->SetGlobalBooleanSetting( 'pruning-date-e', true );
677
- $this->wsal->SetGlobalSetting( 'pruning-date', $pruning_limit . ' months' );
678
  break;
679
 
680
  case 'none':
681
  // None.
682
- $this->wsal->SetGlobalBooleanSetting( 'pruning-date-e', false );
683
  break;
684
 
685
  default:
@@ -697,7 +698,7 @@ final class WSAL_Views_SetupWizard {
697
  * @param string $token - Token type.
698
  */
699
  protected function get_token_type( $token ) {
700
- return $this->wsal->settings()->get_token_type( $token );
701
  }
702
 
703
  /**
@@ -731,7 +732,7 @@ final class WSAL_Views_SetupWizard {
731
  $help_page = 'https://wpactivitylog.com/contact/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=settings+pages';
732
  ?>
733
 
734
- <p><?php echo wp_kses( __( 'We trust this plugin meets all your activity log requirements. Should you encounter any problems, have feature requests or would like to share some feedback', 'wp-security-audit-log' ), $this->wsal->allowed_html_tags ); ?> <a href="<?php echo esc_url( $help_page ); ?>" rel="noopener noreferrer" target="_blank"><?php esc_html_e( 'please get in touch!', 'wp-security-audit-log' ); ?></a></p>
735
 
736
  <form method="post" class="wsal-setup-form">
737
  <?php wp_nonce_field( 'wsal-step-finish' ); ?>
@@ -755,18 +756,20 @@ final class WSAL_Views_SetupWizard {
755
  check_admin_referer( 'wsal-step-finish' );
756
 
757
  // Mark the finish of the setup.
758
- $this->wsal->SetGlobalBooleanSetting( 'setup-complete', true );
759
 
760
  wp_safe_redirect( esc_url_raw( $this->get_next_step() ) );
761
  exit();
762
  }
763
 
764
  /**
765
- * 3rd Party plugins
 
 
766
  */
767
- function wsal_add_wizard_step( $wizard_steps ) {
768
  $new_wizard_steps = array(
769
- 'test' => array(
770
  'name' => __( 'Third Party Extensions', 'wp-security-audit-log' ),
771
  'content' => array( $this, 'addons_step' ),
772
  'save' => array( $this, 'addons_step_save' ),
@@ -776,11 +779,11 @@ final class WSAL_Views_SetupWizard {
776
  // Count number of items in the array.
777
  $number_of_steps = count( $wizard_steps );
778
  // Subtract 1, as we want to insert our step one before the last item.
779
- $number_of_steps = $number_of_steps - 1;
780
 
781
  // Slice the steps up, so we have 2 parts we can insert our slide between.
782
  $first_part = array_slice( $wizard_steps, 0, $number_of_steps, true );
783
- $last_part = array_slice( $wizard_steps, -1, 1, true );
784
 
785
  // combine the two arrays.
786
  $wizard_steps = $first_part + $new_wizard_steps + $last_part;
@@ -788,6 +791,9 @@ final class WSAL_Views_SetupWizard {
788
  return $wizard_steps;
789
  }
790
 
 
 
 
791
  private function addons_step() {
792
  $our_plugins = WSAL_PluginInstallAndActivate::get_installable_plugins();
793
 
@@ -795,7 +801,7 @@ final class WSAL_Views_SetupWizard {
795
  $all_plugins = get_plugins();
796
  $plugin_filenames = array();
797
  foreach ( $all_plugins as $plugin => $info ) {
798
- $plugin_info = pathinfo( $plugin );
799
  $plugin_filenames[] = $plugin_info['filename'];
800
  }
801
 
@@ -812,7 +818,7 @@ final class WSAL_Views_SetupWizard {
812
  <p><?php esc_html_e( 'We noticed that the below plugins are installed on this website. You can install our extensions to also keep a log of changes users do on these plugins.', 'wp-security-audit-log' ); ?></p>
813
  <?php
814
  // Create a nonce to pass through via data attr.
815
- $nonce = wp_create_nonce( 'wsal-install-addon' );
816
 
817
  // Loop through plugins and output.
818
  foreach ( $our_plugins as $details ) {
@@ -820,7 +826,7 @@ final class WSAL_Views_SetupWizard {
820
  if ( WpSecurityAuditLog::is_plugin_active( $details['plugin_slug'] ) || 'wsal-wpforms.php' === basename( $details['plugin_slug'] ) && function_exists( 'wsal_wpforms_init_actions' ) || 'wsal-bbpress.php' === basename( $details['plugin_slug'] ) && function_exists( 'wsal_bbpress_init_actions' ) ) {
821
  $disable_button = 'disabled';
822
  }
823
- if ( ! in_array( $details['addon_for'], $we_have_addon ) ) {
824
  continue;
825
  }
826
  // Check if this is actually an addon for something, otherwise bail.
@@ -833,7 +839,7 @@ final class WSAL_Views_SetupWizard {
833
  <img src="<?php echo esc_url( trailingslashit( WSAL_BASE_URL ) . 'img/addons/' . $details['image_filename'] ); ?>">
834
  <div class="addon-content">
835
  <h5><?php esc_html_e( 'Extension for ', 'wp-security-audit-log' ); ?><?php echo esc_html( $details['title'] ); ?></h5>
836
- <p><?php echo sanitize_text_field( $details['plugin_description'] ); ?></p>
837
  <p><button class="install-addon button button-primary <?php echo esc_attr( $disable_button ); ?>" data-nonce="<?php echo esc_attr( $nonce ); ?>" data-plugin-slug="<?php echo esc_attr( $details['plugin_slug'] ); ?>" data-plugin-download-url="<?php echo esc_url( $details['plugin_url'] ); ?>" data-plugin-event-tab-id="<?php echo esc_attr( $details['event_tab_id'] ); ?>">
838
  <?php
839
  if ( WSAL_PluginInstallAndActivate::is_plugin_installed( $details['plugin_slug'] ) && ! WpSecurityAuditLog::is_plugin_active( $details['plugin_slug'] ) ) {
@@ -848,8 +854,8 @@ final class WSAL_Views_SetupWizard {
848
  </div>
849
  </div>
850
  <?php
851
- }
852
- ?>
853
  <div class="wsal-setup-actions">
854
  <button class="button button-primary"
855
  type="submit"
@@ -872,5 +878,4 @@ final class WSAL_Views_SetupWizard {
872
  wp_safe_redirect( esc_url_raw( $this->get_next_step() ) );
873
  exit();
874
  }
875
-
876
  }
4
  *
5
  * WSAL setup class file.
6
  *
7
+ * @since 3.2.3
8
+ * @package wsal
9
+ * @subpackage views
10
  */
11
 
12
  // Exit if accessed directly.
19
  *
20
  * WSAL setup wizard class which manages the functionality
21
  * related to setup.
22
+ *
23
+ * @package wsal
24
+ * @subpackage views
25
  */
26
  final class WSAL_Views_SetupWizard {
27
 
30
  *
31
  * @var WpSecurityAuditLog
32
  */
33
+ private $plugin;
34
 
35
  /**
36
  * Wizard Steps
66
  * @param WpSecurityAuditLog $wsal – Instance of main plugin.
67
  */
68
  public function __construct( WpSecurityAuditLog $wsal ) {
69
+ $this->plugin = $wsal;
70
 
71
+ if ( $wsal->settings()->current_user_can( 'edit' ) ) {
72
  add_action( 'admin_init', array( $this, 'setup_page' ), 10 );
73
  add_action( 'admin_menu', array( $this, 'admin_menus' ), 10 );
74
  add_action( 'network_admin_menu', array( $this, 'admin_menus' ), 10 );
80
  * Ajax handler to verify setting token.
81
  */
82
  public function setup_check_security_token() {
83
+ if ( ! $this->plugin->settings()->current_user_can( 'edit' ) ) {
84
  echo wp_json_encode(
85
  array(
86
  'success' => false,
158
  $all_plugins = get_plugins();
159
  $plugin_filenames = array();
160
  foreach ( $all_plugins as $plugin => $info ) {
161
+ $plugin_info = pathinfo( $plugin );
162
  $plugin_filenames[] = $plugin_info['filename'];
163
  }
164
 
178
  * Wizard Steps.
179
  */
180
  $wizard_steps = array(
181
+ 'welcome' => array(
182
  'name' => __( 'Welcome', 'wp-security-audit-log' ),
183
  'content' => array( $this, 'wsal_step_welcome' ),
184
  ),
185
+ 'log_details' => array(
186
  'name' => __( 'Log Details', 'wp-security-audit-log' ),
187
  'content' => array( $this, 'wsal_step_log_details' ),
188
  'save' => array( $this, 'wsal_step_log_details_save' ),
189
  ),
190
+ 'login' => array(
191
  'name' => __( 'Log In', 'wp-security-audit-log' ),
192
  'content' => array( $this, 'wsal_step_login' ),
193
  'save' => array( $this, 'wsal_step_login_save' ),
194
  ),
195
+ 'register' => array(
196
  'name' => __( 'User Registrations', 'wp-security-audit-log' ),
197
  'content' => array( $this, 'wsal_step_register' ),
198
  'save' => array( $this, 'wsal_step_register_save' ),
199
  ),
200
+ 'log_retention' => array(
201
  'name' => __( 'Log Retention', 'wp-security-audit-log' ),
202
  'content' => array( $this, 'wsal_step_log_retention' ),
203
  'save' => array( $this, 'wsal_step_log_retention_save' ),
204
  ),
205
+ 'finish' => array(
206
  'name' => __( 'Finish', 'wp-security-audit-log' ),
207
  'content' => array( $this, 'wsal_step_finish' ),
208
  'save' => array( $this, 'wsal_step_finish_save' ),
230
  /**
231
  * Enqueue Styles.
232
  */
233
+ $wizard_css = WSAL_ViewManager::get_asset_path( 'css/dist/', 'wsal-wizard', 'css', false );
234
  wp_enqueue_style(
235
  'wsal-wizard-css',
236
+ $this->plugin->get_base_url() . '/' . $wizard_css,
237
  array( 'dashicons', 'install', 'forms' ),
238
+ filemtime( $this->plugin->get_base_dir() . $wizard_css )
239
  );
240
 
241
  /**
242
  * Enqueue Scripts.
243
  */
244
+ $wizard_js = WSAL_ViewManager::get_asset_path( 'js/dist/', 'wsal-wizard', 'js', false );
245
  wp_register_script(
246
+ 'wsal-wizard-js',
247
+ $this->plugin->get_base_url() . '/' . $wizard_js,
248
+ array( 'jquery' ),
249
+ filemtime( $this->plugin->get_base_dir() . $wizard_js ),
250
+ false
251
+ );
252
+
253
+ $common_js = '/js/common.js';
254
  wp_register_script(
255
  'wsal-common',
256
+ $this->plugin->get_base_url() . $common_js,
257
  array( 'jquery' ),
258
+ filemtime( $this->plugin->get_base_dir() . $common_js ),
259
  true
260
+ );
261
 
262
  // Data array.
263
  $data_array = array(
264
  'ajaxURL' => admin_url( 'admin-ajax.php' ),
265
+ 'nonce' => ( ( ! $this->plugin->settings()->current_user_can( 'edit' ) ) && ! 'invalid-step' === $this->current_step ) ? wp_create_nonce( 'wsal-verify-wizard-page' ) : '',
266
  'usersError' => esc_html__( 'Specified value in not a user.', 'wp-security-audit-log' ),
267
  'rolesError' => esc_html__( 'Specified value in not a role.', 'wp-security-audit-log' ),
268
  'ipError' => esc_html__( 'Specified value in not an IP address.', 'wp-security-audit-log' ),
276
  'installed' => esc_html__( 'Extension installed', 'wp-security-audit-log' ),
277
  'activated' => esc_html__( 'Extension activated', 'wp-security-audit-log' ),
278
  'failed' => esc_html__( 'Install failed', 'wp-security-audit-log' ),
279
+ 'reloading_page' => esc_html__( 'Reloading page', 'wp-security-audit-log' ),
280
  );
281
  wp_localize_script( 'wsal-common', 'wsalCommonData', $installer_script_data );
282
 
 
283
  /**
284
  * Save Wizard Settings.
285
  */
312
  <?php do_action( 'admin_print_styles' ); ?>
313
  </head>
314
  <body class="wsal-setup wp-core-ui">
315
+ <h1 id="wsal-logo"><a href="https://wpactivitylog.com/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=wizard+configuration" rel="noopener noreferrer" target="_blank"><img src="<?php echo esc_url( $this->plugin->get_base_url() ); ?>/img/wsal-logo-full.png" alt="WP Activity Log" /></a></h1>
316
  <?php
317
  }
318
 
412
  * @since 4.0.2
413
  */
414
  private function render_invalid_step() {
415
+ echo '<p>';
 
416
  printf(
417
  /* translators: 1 - an opening link tag, 2 - a closing link tag. */
418
  esc_html__( 'You have reached an invaild step - %1$sreturn to the start of the wizard%2$s.', 'wp-security-audit-log' ),
419
  '<a href="' . esc_url( $this->get_welcome_step() ) . '">',
420
  '</a>'
421
  );
422
+ echo '</p>';
 
423
  }
424
 
425
  /**
426
  * Step View: `Welcome`
427
  */
428
  private function wsal_step_welcome() {
429
+ // Dismiss the setup modal in case if not already done.
430
+ if ( ! $this->plugin->get_global_boolean_setting( 'setup-modal-dismissed', false ) ) {
431
+ $this->plugin->set_global_boolean_setting( 'setup-modal-dismissed', true, true );
432
  }
433
  ?>
434
  <p><?php esc_html_e( 'This wizard helps you configure the basic plugin settings. All these settings can be changed at a later stage from the plugin settings.', 'wp-security-audit-log' ); ?></p>
490
  }
491
 
492
  // Save log details option.
493
+ $this->plugin->set_global_setting( 'details-level', $log_details );
494
  if ( ! empty( $log_details ) && 'basic' === $log_details ) {
495
+ $this->plugin->settings()->set_basic_mode();
496
  } elseif ( ! empty( $log_details ) && 'geek' === $log_details ) {
497
+ $this->plugin->settings()->set_geek_mode();
498
  }
499
 
500
  wp_safe_redirect( esc_url_raw( $this->get_next_step() ) );
540
  if ( isset( $_POST['wsal-frontend-login'] ) ) {
541
  $frontend_sensors = WSAL_Settings::get_frontend_events(); // Get the frontend sensors setting.
542
  $login_sensor = sanitize_text_field( wp_unslash( $_POST['wsal-frontend-login'] ) );
543
+ $login_sensor = '1' === $login_sensor; // Update the sensor option.
544
 
545
  $frontend_sensors['login'] = $login_sensor;
546
  WSAL_Settings::set_frontend_events( $frontend_sensors );
589
  if ( isset( $_POST['wsal-frontend-register'] ) ) {
590
  $frontend_sensors = WSAL_Settings::get_frontend_events(); // Get the frontend sensors setting.
591
  $register_sensor = sanitize_text_field( wp_unslash( $_POST['wsal-frontend-register'] ) );
592
+ $register_sensor = '1' === $register_sensor; // Update the sensor option.
593
 
594
  $frontend_sensors['register'] = $register_sensor;
595
  WSAL_Settings::set_frontend_events( $frontend_sensors );
645
  // Step help text.
646
  $step_help = __( 'The plugin stores the data in the WordPress database in a very efficient way, though the more data you keep the more hard disk space it will consume. If you need need to retain a lot of data we would recommend you to <a href="https://wpactivitylog.com/features/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=wizard+configuration" target="_blank">upgrade to Premium</a> and use the Database tools to store the WordPress activity log in an external database.', 'wp-security-audit-log' );
647
 
648
+ echo wp_kses( $step_help, $this->plugin->allowed_html_tags );
649
  ?>
650
  </em>
651
  </p>
674
  case '6':
675
  case '12':
676
  // 6 or 12 months.
677
+ $this->plugin->set_global_boolean_setting( 'pruning-date-e', true );
678
+ $this->plugin->set_global_setting( 'pruning-date', $pruning_limit . ' months' );
679
  break;
680
 
681
  case 'none':
682
  // None.
683
+ $this->plugin->set_global_boolean_setting( 'pruning-date-e', false );
684
  break;
685
 
686
  default:
698
  * @param string $token - Token type.
699
  */
700
  protected function get_token_type( $token ) {
701
+ return $this->plugin->settings()->get_token_type( $token );
702
  }
703
 
704
  /**
732
  $help_page = 'https://wpactivitylog.com/contact/?utm_source=plugin&utm_medium=referral&utm_campaign=WSAL&utm_content=settings+pages';
733
  ?>
734
 
735
+ <p><?php echo wp_kses( __( 'We trust this plugin meets all your activity log requirements. Should you encounter any problems, have feature requests or would like to share some feedback', 'wp-security-audit-log' ), $this->plugin->allowed_html_tags ); ?> <a href="<?php echo esc_url( $help_page ); ?>" rel="noopener noreferrer" target="_blank"><?php esc_html_e( 'please get in touch!', 'wp-security-audit-log' ); ?></a></p>
736
 
737
  <form method="post" class="wsal-setup-form">
738
  <?php wp_nonce_field( 'wsal-step-finish' ); ?>
756
  check_admin_referer( 'wsal-step-finish' );
757
 
758
  // Mark the finish of the setup.
759
+ $this->plugin->set_global_boolean_setting( 'setup-complete', true );
760
 
761
  wp_safe_redirect( esc_url_raw( $this->get_next_step() ) );
762
  exit();
763
  }
764
 
765
  /**
766
+ * 3rd Party plugins.
767
+ *
768
+ * @param array $wizard_steps Wizard steps data.
769
  */
770
+ public function wsal_add_wizard_step( $wizard_steps ) {
771
  $new_wizard_steps = array(
772
+ 'test' => array(
773
  'name' => __( 'Third Party Extensions', 'wp-security-audit-log' ),
774
  'content' => array( $this, 'addons_step' ),
775
  'save' => array( $this, 'addons_step_save' ),
779
  // Count number of items in the array.
780
  $number_of_steps = count( $wizard_steps );
781
  // Subtract 1, as we want to insert our step one before the last item.
782
+ $number_of_steps--;
783
 
784
  // Slice the steps up, so we have 2 parts we can insert our slide between.
785
  $first_part = array_slice( $wizard_steps, 0, $number_of_steps, true );
786
+ $last_part = array_slice( $wizard_steps, -1, 1, true );
787
 
788
  // combine the two arrays.
789
  $wizard_steps = $first_part + $new_wizard_steps + $last_part;
791
  return $wizard_steps;
792
  }
793
 
794
+ /**
795
+ * Renders wizard step showing available add-ons.
796
+ */
797
  private function addons_step() {
798
  $our_plugins = WSAL_PluginInstallAndActivate::get_installable_plugins();
799
 
801
  $all_plugins = get_plugins();
802
  $plugin_filenames = array();
803
  foreach ( $all_plugins as $plugin => $info ) {
804
+ $plugin_info = pathinfo( $plugin );
805
  $plugin_filenames[] = $plugin_info['filename'];
806
  }
807
 
818
  <p><?php esc_html_e( 'We noticed that the below plugins are installed on this website. You can install our extensions to also keep a log of changes users do on these plugins.', 'wp-security-audit-log' ); ?></p>
819
  <?php
820
  // Create a nonce to pass through via data attr.
821
+ $nonce = wp_create_nonce( 'wsal-install-addon' );
822
 
823
  // Loop through plugins and output.
824
  foreach ( $our_plugins as $details ) {
826
  if ( WpSecurityAuditLog::is_plugin_active( $details['plugin_slug'] ) || 'wsal-wpforms.php' === basename( $details['plugin_slug'] ) && function_exists( 'wsal_wpforms_init_actions' ) || 'wsal-bbpress.php' === basename( $details['plugin_slug'] ) && function_exists( 'wsal_bbpress_init_actions' ) ) {
827
  $disable_button = 'disabled';
828
  }
829
+ if ( ! in_array( $details['addon_for'], $we_have_addon, true ) ) {
830
  continue;
831
  }
832
  // Check if this is actually an addon for something, otherwise bail.
839
  <img src="<?php echo esc_url( trailingslashit( WSAL_BASE_URL ) . 'img/addons/' . $details['image_filename'] ); ?>">
840
  <div class="addon-content">
841
  <h5><?php esc_html_e( 'Extension for ', 'wp-security-audit-log' ); ?><?php echo esc_html( $details['title'] ); ?></h5>
842
+ <p><?php echo sanitize_text_field( $details['plugin_description'] ); // phpcs:ignore ?></p>
843
  <p><button class="install-addon button button-primary <?php echo esc_attr( $disable_button ); ?>" data-nonce="<?php echo esc_attr( $nonce ); ?>" data-plugin-slug="<?php echo esc_attr( $details['plugin_slug'] ); ?>" data-plugin-download-url="<?php echo esc_url( $details['plugin_url'] ); ?>" data-plugin-event-tab-id="<?php echo esc_attr( $details['event_tab_id'] ); ?>">
844
  <?php
845
  if ( WSAL_PluginInstallAndActivate::is_plugin_installed( $details['plugin_slug'] ) && ! WpSecurityAuditLog::is_plugin_active( $details['plugin_slug'] ) ) {
854
  </div>
855
  </div>
856
  <?php
857
+ }
858
+ ?>
859
  <div class="wsal-setup-actions">
860
  <button class="button button-primary"
861
  type="submit"
878
  wp_safe_redirect( esc_url_raw( $this->get_next_step() ) );
879
  exit();
880
  }
 
881
  }
classes/Views/ToggleAlerts.php CHANGED
@@ -4,8 +4,9 @@
4
  *
5
  * Settings page of the plugin.
6
  *
7
- * @since 1.0.0
8
- * @package wsal
 
9
  */
10
 
11
  // Exit if accessed directly.
@@ -16,35 +17,36 @@ if ( ! defined( 'ABSPATH' ) ) {
16
  /**
17
  * Enable/Disable Alerts Page.
18
  *
19
- * @package wsal
 
20
  */
21
  class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
22
 
23
  /**
24
- * Method: Get View Title.
25
  */
26
- public function GetTitle() {
27
- return __( 'Enable/Disable Events', 'wp-security-audit-log' );
28
  }
29
 
30
  /**
31
- * Method: Get View Icon.
32
  */
33
- public function GetIcon() {
34
  return 'dashicons-forms';
35
  }
36
 
37
  /**
38
- * Method: Get View Name.
39
  */
40
- public function GetName() {
41
- return __( 'Enable/Disable Events', 'wp-security-audit-log' );
42
  }
43
 
44
  /**
45
- * Method: Get View Weight.
46
  */
47
- public function GetWeight() {
48
  return 9;
49
  }
50
 
@@ -53,7 +55,7 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
53
  *
54
  * @param string $name - Name of the category.
55
  */
56
- protected function GetSafeCatgName( $name ) {
57
  return strtolower(
58
  preg_replace( '/[^A-Za-z0-9\-]/', '-', $name )
59
  );
@@ -84,19 +86,19 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
84
  WSAL_Settings::set_frontend_events( $frontend_events );
85
 
86
  // Ensure we attempt to save even if eveything is disabled.
87
- $post_array['alert'] = ( isset( $post_array['alert'] ) ) ? $post_array['alert'] : [];
88
 
89
  $enabled = array_map( 'intval', $post_array['alert'] );
90
  $disabled = array();
91
- $registered_alerts = $this->_plugin->alerts->GetAlerts();
92
  $disabled = apply_filters( 'wsal_save_settings_disabled_events', $disabled, $registered_alerts, $frontend_events, $enabled );
93
 
94
  // Save the disabled events.
95
- $this->_plugin->alerts->SetDisabledAlerts( $disabled ); // Save the disabled events.
96
 
97
  // Update failed login limits.
98
- $this->_plugin->settings()->set_failed_login_limit( $post_array['log_failed_login_limit'] );
99
- $this->_plugin->settings()->set_visitor_failed_login_limit( $post_array['log_visitor_failed_login_limit'] );
100
 
101
  // Allow 3rd parties to process and save more of the posted data.
102
  do_action( 'wsal_togglealerts_process_save_settings', $post_array );
@@ -106,9 +108,9 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
106
  /**
107
  * Method: Get View.
108
  */
109
- public function Render() {
110
  // Die if user does not have permission to view.
111
- if ( ! $this->_plugin->settings()->CurrentUserCan( 'edit' ) ) {
112
  wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'wp-security-audit-log' ) );
113
  }
114
 
@@ -134,36 +136,36 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
134
  }
135
 
136
  // Log level form submission.
137
- $log_level_to_set = isset( $post_array['wsal-log-level'] ) ? sanitize_text_field( $post_array['wsal-log-level'] ) : false;
138
- $log_level_nonce = isset( $post_array['wsal-log-level-nonce'] ) ? sanitize_text_field( $post_array['wsal-log-level-nonce'] ) : false;
139
 
140
  if ( wp_verify_nonce( $log_level_nonce, 'wsal-log-level' ) ) {
141
- $this->_plugin->SetGlobalSetting( 'details-level', $log_level_to_set );
142
 
143
  if ( 'basic' === $log_level_to_set ) {
144
- $this->_plugin->settings()->set_basic_mode();
145
  } elseif ( 'geek' === $log_level_to_set ) {
146
- $this->_plugin->settings()->set_geek_mode();
147
  }
148
  }
149
 
150
  $alert = new WSAL_Alert(); // IDE type hinting.
151
- $grouped_alerts = $this->_plugin->alerts->GetCategorizedAlerts( false );
152
- $safe_names = array_map( array( $this, 'GetSafeCatgName' ), array_keys( $grouped_alerts ) );
153
  $safe_names = array_combine( array_keys( $grouped_alerts ), $safe_names );
154
 
155
- $disabled_events = $this->_plugin->GetGlobalSetting( 'disabled-alerts' ); // Get disabled events.
156
  $disabled_events = explode( ',', $disabled_events );
157
 
158
- // check if the log level is custom
159
- $log_level = $this->get_log_level_based_on_events( $disabled_events );
160
- $log_level_options = [
161
  'basic' => esc_html__( 'Basic', 'wp-security-audit-log' ),
162
  'geek' => esc_html__( 'Geek', 'wp-security-audit-log' ),
163
  'custom' => esc_html__( 'Custom', 'wp-security-audit-log' ),
164
- ];
165
 
166
- $subcat_alerts = array( 1000, 1004, 2010, 2111 );
167
 
168
  // Allow further items to be added externally.
169
  $subcat_alerts = apply_filters( 'wsal_togglealerts_sub_category_events', $subcat_alerts );
@@ -171,12 +173,12 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
171
  $obsolete_events = array( 9999, 2126, 99999 );
172
  $obsolete_events = apply_filters( 'wsal_togglealerts_obsolete_events', $obsolete_events );
173
 
174
- // check if the disabled events are enforced from the MainWP master site
175
- $settings = $this->_plugin->settings();
176
- $enforced_settings = $settings->get_mainwp_enforced_settings();
177
- $disabled_events_enforced_by_mainwp = array_key_exists( 'disabled_events', $enforced_settings ) && ! empty( $enforced_settings[ 'disabled_events' ]);
178
  ?>
179
-
180
  <h2 id="wsal-tabs" class="nav-tab-wrapper">
181
  <a href="#tab-all" class="nav-tab"><?php esc_html_e( 'Enable/Disable alerts', 'wp-security-audit-log' ); ?></a>
182
  <a href="#tab-third-party-plugins" class="nav-tab">
@@ -185,20 +187,21 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
185
  </h2>
186
 
187
  <div class="nav-tabs">
188
-
189
  <div id="tab-all" class="wsal-tab widefat fixed">
190
 
191
  <form method="post" id="wsal-alerts-level">
192
  <?php wp_nonce_field( 'wsal-log-level', 'wsal-log-level-nonce' ); ?>
193
  <fieldset>
194
  <label for="wsal-log-level"><?php esc_html_e( 'Log Level: ', 'wp-security-audit-log' ); ?></label>
195
- <select name="wsal-log-level" id="wsal-log-level" onchange="this.form.submit()"<?php if ( $disabled_events_enforced_by_mainwp ): ?> disabled="disabled"<?php endif; ?>>
196
- <?php foreach ( $log_level_options as $log_level_id => $log_level_label ): ?>
197
- <option value="<?php echo $log_level_id; ?>" <?php echo selected( $log_level, $log_level_id ); ?>><?php echo $log_level_label; ?></option>
 
198
  <?php endforeach; ?>
199
  </select>
200
  <p class="description">
201
- <?php echo wp_kses( __( 'Use the Log level drop down menu above to use one of our preset log levels. Alternatively you can enable or disable any of the individual events from the below tabs. Refer to <a href="https://wpactivitylog.com/support/kb/list-wordpress-activity-log-event-ids/" target="_blank">the complete list of WordPress activity log event IDs</a> for reference on all the events the plugin can keep a log of.', 'wp-security-audit-log' ), $this->_plugin->allowed_html_tags ); ?>
202
  </p>
203
  </fieldset>
204
  </form>
@@ -243,14 +246,14 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
243
  if ( in_array( $alert->code, $obsolete_events, true ) ) {
244
  continue; // <- Ignore promo alerts.
245
  }
246
- $active[ $alert->code ] = $this->_plugin->alerts->IsEnabled( $alert->code );
247
  if ( ! $active[ $alert->code ] ) {
248
  $allactive = false;
249
  }
250
  }
251
  }
252
  }
253
- ?>
254
  <th width="48"><input type="checkbox" <?php checked( $allactive ); ?> /></th>
255
  <th width="80"><?php esc_html_e( 'Code', 'wp-security-audit-log' ); ?></th>
256
  <th width="100"><?php esc_html_e( 'Severity', 'wp-security-audit-log' ); ?></th>
@@ -268,14 +271,14 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
268
  $allactive = true;
269
  /** @var WSAL_Alert $alert */
270
  foreach ( $alerts as $alert ) {
271
- $active[ $alert->code ] = $this->_plugin->alerts->IsEnabled( $alert->code );
272
  if ( ! $active[ $alert->code ] ) {
273
  $allactive = false;
274
  }
275
  }
276
 
277
  // Disabled alerts.
278
- $disable_inputs = '';
279
  $disabled_message = '';
280
 
281
  // Skip Pages and CPTs section.
@@ -302,7 +305,7 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
302
  case 'WooCommerce Products':
303
  // Check if WooCommerce plugin exists.
304
  if ( ! WpSecurityAuditLog::is_woocommerce_active() ) {
305
- $disable_inputs = 'disabled';
306
  $disabled_message = esc_html__( 'Please activate WooCommerce to enable this alert', 'wp-security-audit-log' );
307
  }
308
  break;
@@ -310,7 +313,7 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
310
  case 'Yoast SEO':
311
  // Check if Yoast SEO plugin exists.
312
  if ( ! WpSecurityAuditLog::is_wpseo_active() ) {
313
- $disable_inputs = 'disabled';
314
  $disabled_message = esc_html__( 'Please activate the Yoast SEO Plugin', 'wp-security-audit-log' );
315
  }
316
  break;
@@ -318,7 +321,7 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
318
  case 'Multisite Network Sites':
319
  // Disable if not multisite.
320
  if ( ! is_multisite() ) {
321
- $disable_inputs = 'disabled';
322
  $disabled_message = esc_html__( 'Your website is a single site so the multisite events have been disabled.', 'wp-security-audit-log' );
323
  }
324
  break;
@@ -343,9 +346,9 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
343
 
344
  $disable_inputs_needed = ( ! empty( $disable_inputs ) ) ? esc_attr( $disable_inputs ) : '';
345
  $disabled_tooltip = ( $disabled_message ) ? 'data-tooltip="' . $disabled_message . '"' : '';
346
- $checkbox_markup = '<input name="alert[]" type="checkbox" class="alert"'. checked( $this->_plugin->alerts->IsEnabled( $alert->code ), true, false ) .' value="'. esc_attr( (int) $alert->code ) .'" '. $disable_inputs_needed .' />';
347
  $severity = '';
348
- $severity_obj = $this->_plugin->constants->GetConstantBy( 'value', $alert->severity );
349
 
350
  if ( is_object( $severity_obj ) ) {
351
  if ( 'E_CRITICAL' === $severity_obj->name ) {
@@ -367,19 +370,21 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
367
  } else {
368
  $severity = esc_html__( 'Notification', 'wp-security-audit-log' );
369
  }
370
- }
371
-
372
- echo '<tr class="alert-wrapper '. $disable_inputs_needed .'" data-alert-cat="' . $alert->catg . '" data-alert-subcat="' . $alert->subcatg . '" ' . $disabled_tooltip . '>';
373
- echo '<th>' . $checkbox_markup . '</th>';
374
- echo '<td>' . $alert->code . '</td>';
375
- echo '<td>' . $severity . '</td>';
376
- echo '<td>' . $alert->desc . '</td>';
377
- echo '<td style="display: none;">' . $alert->catg . '</td>';
378
- echo '<td style="display: none;">' . $alert->subcatg . '</td>';
 
379
  echo '</tr>';
 
380
 
381
  if ( 4000 === $alert->code ) {
382
- $frontend_events = WSAL_Settings::get_frontend_events();
383
  ?>
384
  <tr class="alert-wrapper" data-alert-cat="Users Logins & Sessions Events" data-alert-subcat="User Activity">
385
  <td></td>
@@ -392,7 +397,7 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
392
  }
393
 
394
  if ( 1002 === $alert->code ) {
395
- $log_failed_login_limit = (int) $this->_plugin->GetGlobalSetting( 'log-failed-login-limit', 10 );
396
  $log_failed_login_limit = ( -1 === $log_failed_login_limit ) ? '0' : $log_failed_login_limit;
397
  ?>
398
  <tr class="alert-wrapper" data-alert-cat="Users Logins & Sessions Events" data-alert-subcat="User Activity">
@@ -405,7 +410,7 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
405
  <?php
406
  }
407
  if ( 1003 === $alert->code ) {
408
- $log_visitor_failed_login_limit = (int) $this->_plugin->GetGlobalSetting( 'log-visitor-failed-login-limit', 10 );
409
  $log_visitor_failed_login_limit = ( -1 === $log_visitor_failed_login_limit ) ? '0' : $log_visitor_failed_login_limit;
410
  ?>
411
  <tr class="alert-wrapper" data-alert-cat="Users Logins & Sessions Events" data-alert-subcat="User Activity">
@@ -419,7 +424,7 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
419
  }
420
 
421
  if ( 1000 === $alert->code ) {
422
- $frontend_events = WSAL_Settings::get_frontend_events();
423
  ?>
424
  <tr class="alert-wrapper" data-alert-cat="Users Logins & Sessions Events" data-alert-subcat="User Activity">
425
  <td></td>
@@ -447,7 +452,7 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
447
  <?php
448
  $addons = new WSAL_PluginInstallAndActivate();
449
  $addons->render();
450
- ?>
451
  </div>
452
 
453
 
@@ -459,7 +464,7 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
459
  <p>
460
  <?php
461
  /* translators: Alerts log level. */
462
- echo sprintf( esc_html__( 'The %s log level has been successfully loaded and applied.', 'wp-security-audit-log' ), $log_level_to_set );
463
  ?>
464
  </p>
465
  <br>
@@ -493,12 +498,11 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
493
  /**
494
  * Method: Get View Header.
495
  */
496
- public function Header() {
497
  // Remodal styles.
498
  wp_enqueue_style( 'wsal-remodal', WSAL_BASE_URL . 'css/remodal.css', array(), '1.1.1' );
499
  wp_enqueue_style( 'wsal-remodal-theme', WSAL_BASE_URL . 'css/remodal-default-theme.css', array(), '1.1.1' );
500
 
501
-
502
  // Darktooltip styles.
503
  wp_enqueue_style(
504
  'darktooltip',
@@ -685,7 +689,7 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
685
  margin-top: 10px;
686
  padding: 10px;
687
  border: 1px solid #c3c4c7;
688
- box-shadow: 0 1px 1px rgb(0 0 0 / 4%);
689
  }
690
  </style>
691
  <?php
@@ -694,7 +698,7 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
694
  /**
695
  * Method: Get View Footer.
696
  */
697
- public function Footer() {
698
  // Remodal script.
699
  wp_enqueue_script(
700
  'wsal-remodal-js',
@@ -870,14 +874,14 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
870
  * @since 4.2.0
871
  */
872
  private function get_log_level_based_on_events( $disabled_events ) {
873
- $events_to_cross_check = $this->_plugin->settings()->always_disabled_alerts;
874
  $events_diff = array_diff( $disabled_events, $events_to_cross_check );
875
  $events_diff = array_filter( $events_diff ); // Remove empty values.
876
  if ( empty( $events_diff ) ) {
877
  return 'geek';
878
  }
879
 
880
- $events_to_cross_check = array_merge( $events_to_cross_check, $this->_plugin->settings()->geek_alerts );
881
  $events_diff = array_diff( $disabled_events, $events_to_cross_check );
882
  $events_diff = array_filter( $events_diff ); // Remove empty values.
883
  if ( empty( $events_diff ) ) {
4
  *
5
  * Settings page of the plugin.
6
  *
7
+ * @since 1.0.0
8
+ * @package wsal
9
+ * @subpackage views
10
  */
11
 
12
  // Exit if accessed directly.
17
  /**
18
  * Enable/Disable Alerts Page.
19
  *
20
+ * @package wsal
21
+ * @subpackage views
22
  */
23
  class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
24
 
25
  /**
26
+ * {@inheritDoc}
27
  */
28
+ public function get_title() {
29
+ return esc_html__( 'Enable/Disable Events', 'wp-security-audit-log' );
30
  }
31
 
32
  /**
33
+ * {@inheritDoc}
34
  */
35
+ public function get_icon() {
36
  return 'dashicons-forms';
37
  }
38
 
39
  /**
40
+ * {@inheritDoc}
41
  */
42
+ public function get_name() {
43
+ return esc_html__( 'Enable/Disable Events', 'wp-security-audit-log' );
44
  }
45
 
46
  /**
47
+ * {@inheritDoc}
48
  */
49
+ public function get_weight() {
50
  return 9;
51
  }
52
 
55
  *
56
  * @param string $name - Name of the category.
57
  */
58
+ protected function get_safe_category_name( $name ) {
59
  return strtolower(
60
  preg_replace( '/[^A-Za-z0-9\-]/', '-', $name )
61
  );
86
  WSAL_Settings::set_frontend_events( $frontend_events );
87
 
88
  // Ensure we attempt to save even if eveything is disabled.
89
+ $post_array['alert'] = ( isset( $post_array['alert'] ) ) ? $post_array['alert'] : array();
90
 
91
  $enabled = array_map( 'intval', $post_array['alert'] );
92
  $disabled = array();
93
+ $registered_alerts = $this->plugin->alerts->get_alerts();
94
  $disabled = apply_filters( 'wsal_save_settings_disabled_events', $disabled, $registered_alerts, $frontend_events, $enabled );
95
 
96
  // Save the disabled events.
97
+ $this->plugin->settings()->set_disabled_alerts( $disabled ); // Save the disabled events.
98
 
99
  // Update failed login limits.
100
+ $this->plugin->settings()->set_failed_login_limit( $post_array['log_failed_login_limit'] );
101
+ $this->plugin->settings()->set_visitor_failed_login_limit( $post_array['log_visitor_failed_login_limit'] );
102
 
103
  // Allow 3rd parties to process and save more of the posted data.
104
  do_action( 'wsal_togglealerts_process_save_settings', $post_array );
108
  /**
109
  * Method: Get View.
110
  */
111
+ public function render() {
112
  // Die if user does not have permission to view.
113
+ if ( ! $this->plugin->settings()->current_user_can( 'edit' ) ) {
114
  wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'wp-security-audit-log' ) );
115
  }
116
 
136
  }
137
 
138
  // Log level form submission.
139
+ $log_level_to_set = isset( $post_array['wsal-log-level'] ) ? sanitize_text_field( $post_array['wsal-log-level'] ) : false;
140
+ $log_level_nonce = isset( $post_array['wsal-log-level-nonce'] ) ? sanitize_text_field( $post_array['wsal-log-level-nonce'] ) : false;
141
 
142
  if ( wp_verify_nonce( $log_level_nonce, 'wsal-log-level' ) ) {
143
+ $this->plugin->set_global_setting( 'details-level', $log_level_to_set );
144
 
145
  if ( 'basic' === $log_level_to_set ) {
146
+ $this->plugin->settings()->set_basic_mode();
147
  } elseif ( 'geek' === $log_level_to_set ) {
148
+ $this->plugin->settings()->set_geek_mode();
149
  }
150
  }
151
 
152
  $alert = new WSAL_Alert(); // IDE type hinting.
153
+ $grouped_alerts = $this->plugin->alerts->get_categorized_alerts( false );
154
+ $safe_names = array_map( array( $this, 'get_safe_category_name' ), array_keys( $grouped_alerts ) );
155
  $safe_names = array_combine( array_keys( $grouped_alerts ), $safe_names );
156
 
157
+ $disabled_events = $this->plugin->get_global_setting( 'disabled-alerts' ); // Get disabled events.
158
  $disabled_events = explode( ',', $disabled_events );
159
 
160
+ // Check if the log level is custom.
161
+ $log_level = $this->get_log_level_based_on_events( $disabled_events );
162
+ $log_level_options = array(
163
  'basic' => esc_html__( 'Basic', 'wp-security-audit-log' ),
164
  'geek' => esc_html__( 'Geek', 'wp-security-audit-log' ),
165
  'custom' => esc_html__( 'Custom', 'wp-security-audit-log' ),
166
+ );
167
 
168
+ $subcat_alerts = array( 1000, 1004, 2010, 2111 );
169
 
170
  // Allow further items to be added externally.
171
  $subcat_alerts = apply_filters( 'wsal_togglealerts_sub_category_events', $subcat_alerts );
173
  $obsolete_events = array( 9999, 2126, 99999 );
174
  $obsolete_events = apply_filters( 'wsal_togglealerts_obsolete_events', $obsolete_events );
175
 
176
+ // Check if the disabled events are enforced from the MainWP master site.
177
+ $settings = $this->plugin->settings();
178
+ $enforced_settings = $settings->get_mainwp_enforced_settings();
179
+ $disabled_events_enforced_by_mainwp = array_key_exists( 'disabled_events', $enforced_settings ) && ! empty( $enforced_settings['disabled_events'] );
180
  ?>
181
+
182
  <h2 id="wsal-tabs" class="nav-tab-wrapper">
183
  <a href="#tab-all" class="nav-tab"><?php esc_html_e( 'Enable/Disable alerts', 'wp-security-audit-log' ); ?></a>
184
  <a href="#tab-third-party-plugins" class="nav-tab">
187
  </h2>
188
 
189
  <div class="nav-tabs">
190
+
191
  <div id="tab-all" class="wsal-tab widefat fixed">
192
 
193
  <form method="post" id="wsal-alerts-level">
194
  <?php wp_nonce_field( 'wsal-log-level', 'wsal-log-level-nonce' ); ?>
195
  <fieldset>
196
  <label for="wsal-log-level"><?php esc_html_e( 'Log Level: ', 'wp-security-audit-log' ); ?></label>
197
+ <select name="wsal-log-level" id="wsal-log-level" onchange="this.form.submit()"
198
+ <?php disabled( $disabled_events_enforced_by_mainwp ); ?>>
199
+ <?php foreach ( $log_level_options as $log_level_id => $log_level_label ) : ?>
200
+ <option value="<?php echo $log_level_id; ?>" <?php echo selected( $log_level, $log_level_id ); ?>><?php echo $log_level_label; // phpcs:ignore ?></option>
201
  <?php endforeach; ?>
202
  </select>
203
  <p class="description">
204
+ <?php echo wp_kses( __( 'Use the Log level drop down menu above to use one of our preset log levels. Alternatively you can enable or disable any of the individual events from the below tabs. Refer to <a href="https://wpactivitylog.com/support/kb/list-wordpress-activity-log-event-ids/" target="_blank">the complete list of WordPress activity log event IDs</a> for reference on all the events the plugin can keep a log of.', 'wp-security-audit-log' ), $this->plugin->allowed_html_tags ); ?>
205
  </p>
206
  </fieldset>
207
  </form>
246
  if ( in_array( $alert->code, $obsolete_events, true ) ) {
247
  continue; // <- Ignore promo alerts.
248
  }
249
+ $active[ $alert->code ] = $this->plugin->alerts->is_enabled( $alert->code );
250
  if ( ! $active[ $alert->code ] ) {
251
  $allactive = false;
252
  }
253
  }
254
  }
255
  }
256
+ ?>
257
  <th width="48"><input type="checkbox" <?php checked( $allactive ); ?> /></th>
258
  <th width="80"><?php esc_html_e( 'Code', 'wp-security-audit-log' ); ?></th>
259
  <th width="100"><?php esc_html_e( 'Severity', 'wp-security-audit-log' ); ?></th>
271
  $allactive = true;
272
  /** @var WSAL_Alert $alert */
273
  foreach ( $alerts as $alert ) {
274
+ $active[ $alert->code ] = $this->plugin->alerts->is_enabled( $alert->code );
275
  if ( ! $active[ $alert->code ] ) {
276
  $allactive = false;
277
  }
278
  }
279
 
280
  // Disabled alerts.
281
+ $disable_inputs = '';
282
  $disabled_message = '';
283
 
284
  // Skip Pages and CPTs section.
305
  case 'WooCommerce Products':
306
  // Check if WooCommerce plugin exists.
307
  if ( ! WpSecurityAuditLog::is_woocommerce_active() ) {
308
+ $disable_inputs = 'disabled';
309
  $disabled_message = esc_html__( 'Please activate WooCommerce to enable this alert', 'wp-security-audit-log' );
310
  }
311
  break;
313
  case 'Yoast SEO':
314
  // Check if Yoast SEO plugin exists.
315
  if ( ! WpSecurityAuditLog::is_wpseo_active() ) {
316
+ $disable_inputs = 'disabled';
317
  $disabled_message = esc_html__( 'Please activate the Yoast SEO Plugin', 'wp-security-audit-log' );
318
  }
319
  break;
321
  case 'Multisite Network Sites':
322
  // Disable if not multisite.
323
  if ( ! is_multisite() ) {
324
+ $disable_inputs = 'disabled';
325
  $disabled_message = esc_html__( 'Your website is a single site so the multisite events have been disabled.', 'wp-security-audit-log' );
326
  }
327
  break;
346
 
347
  $disable_inputs_needed = ( ! empty( $disable_inputs ) ) ? esc_attr( $disable_inputs ) : '';
348
  $disabled_tooltip = ( $disabled_message ) ? 'data-tooltip="' . $disabled_message . '"' : '';
349
+ $checkbox_markup = '<input name="alert[]" type="checkbox" class="alert"' . checked( $this->plugin->alerts->is_enabled( $alert->code ), true, false ) . ' value="' . esc_attr( (int) $alert->code ) . '" ' . $disable_inputs_needed . ' />';
350
  $severity = '';
351
+ $severity_obj = $this->plugin->constants->get_constant_by( 'value', $alert->severity );
352
 
353
  if ( is_object( $severity_obj ) ) {
354
  if ( 'E_CRITICAL' === $severity_obj->name ) {
370
  } else {
371
  $severity = esc_html__( 'Notification', 'wp-security-audit-log' );
372
  }
373
+ }
374
+
375
+ // @codingStandardsIgnoreStart
376
+ echo '<tr class="alert-wrapper ' . $disable_inputs_needed . '" data-alert-cat="' . $alert->catg . '" data-alert-subcat="' . $alert->subcatg . '" ' . $disabled_tooltip . '>';
377
+ echo '<th>' . $checkbox_markup . '</th>';
378
+ echo '<td>' . $alert->code . '</td>';
379
+ echo '<td>' . $severity . '</td>';
380
+ echo '<td>' . $alert->desc . '</td>';
381
+ echo '<td style="display: none;">' . $alert->catg . '</td>';
382
+ echo '<td style="display: none;">' . $alert->subcatg . '</td>';
383
  echo '</tr>';
384
+ // @codingStandardsIgnoreEnd
385
 
386
  if ( 4000 === $alert->code ) {
387
+ $frontend_events = WSAL_Settings::get_frontend_events();
388
  ?>
389
  <tr class="alert-wrapper" data-alert-cat="Users Logins & Sessions Events" data-alert-subcat="User Activity">
390
  <td></td>
397
  }
398
 
399
  if ( 1002 === $alert->code ) {
400
+ $log_failed_login_limit = (int) $this->plugin->get_global_setting( 'log-failed-login-limit', 10 );
401
  $log_failed_login_limit = ( -1 === $log_failed_login_limit ) ? '0' : $log_failed_login_limit;
402
  ?>
403
  <tr class="alert-wrapper" data-alert-cat="Users Logins & Sessions Events" data-alert-subcat="User Activity">
410
  <?php
411
  }
412
  if ( 1003 === $alert->code ) {
413
+ $log_visitor_failed_login_limit = (int) $this->plugin->get_global_setting( 'log-visitor-failed-login-limit', 10 );
414
  $log_visitor_failed_login_limit = ( -1 === $log_visitor_failed_login_limit ) ? '0' : $log_visitor_failed_login_limit;
415
  ?>
416
  <tr class="alert-wrapper" data-alert-cat="Users Logins & Sessions Events" data-alert-subcat="User Activity">
424
  }
425
 
426
  if ( 1000 === $alert->code ) {
427
+ $frontend_events = WSAL_Settings::get_frontend_events();
428
  ?>
429
  <tr class="alert-wrapper" data-alert-cat="Users Logins & Sessions Events" data-alert-subcat="User Activity">
430
  <td></td>
452
  <?php
453
  $addons = new WSAL_PluginInstallAndActivate();
454
  $addons->render();
455
+ ?>
456
  </div>
457
 
458
 
464
  <p>
465
  <?php
466
  /* translators: Alerts log level. */
467
+ echo sprintf( esc_html__( 'The %s log level has been successfully loaded and applied.', 'wp-security-audit-log' ), $log_level_to_set ); // phpcs:ignore
468
  ?>
469
  </p>
470
  <br>
498
  /**
499
  * Method: Get View Header.
500
  */
501
+ public function header() {
502
  // Remodal styles.
503
  wp_enqueue_style( 'wsal-remodal', WSAL_BASE_URL . 'css/remodal.css', array(), '1.1.1' );
504
  wp_enqueue_style( 'wsal-remodal-theme', WSAL_BASE_URL . 'css/remodal-default-theme.css', array(), '1.1.1' );
505
 
 
506
  // Darktooltip styles.
507
  wp_enqueue_style(
508
  'darktooltip',
689
  margin-top: 10px;
690
  padding: 10px;
691
  border: 1px solid #c3c4c7;
692
+ box-shadow: 0 1px 1px rgb(0 0 0 / 4%);
693
  }
694
  </style>
695
  <?php
698
  /**
699
  * Method: Get View Footer.
700
  */
701
+ public function footer() {
702
  // Remodal script.
703
  wp_enqueue_script(
704
  'wsal-remodal-js',
874
  * @since 4.2.0
875
  */
876
  private function get_log_level_based_on_events( $disabled_events ) {
877
+ $events_to_cross_check = $this->plugin->settings()->always_disabled_alerts;
878
  $events_diff = array_diff( $disabled_events, $events_to_cross_check );
879
  $events_diff = array_filter( $events_diff ); // Remove empty values.
880
  if ( empty( $events_diff ) ) {
881
  return 'geek';
882
  }
883
 
884
+ $events_to_cross_check = array_merge( $events_to_cross_check, $this->plugin->settings()->geek_alerts );
885
  $events_diff = array_diff( $disabled_events, $events_to_cross_check );
886
  $events_diff = array_filter( $events_diff ); // Remove empty values.
887
  if ( empty( $events_diff ) ) {
classes/Views/addons/html-view.php CHANGED
@@ -3,6 +3,7 @@
3
  * Addons HTML View in Admin.
4
  *
5
  * @package wsal
 
6
  */
7
 
8
  if ( ! defined( 'ABSPATH' ) ) {
@@ -32,9 +33,9 @@ switch ( $this->hook_suffix ) {
32
  case 'wp-activity-log_page_wsal-search':
33
  $utm_params['utm_content'] = 'search';
34
  break;
35
- default:
36
- // fallback for any other hook suffices would go here
37
- break;
38
  }
39
  // Links.
40
  $more_info = add_query_arg(
@@ -46,7 +47,7 @@ $more_info = add_query_arg(
46
  $trial_args = array(
47
  'page' => 'wsal-auditlog-pricing',
48
  'billing_cycle' => 'annual',
49
- 'trial' => 'true'
50
  );
51
 
52
  // Buy Now button link.
@@ -55,14 +56,14 @@ $buy_now_target = '';
55
  $trial_link = add_query_arg( $trial_args, admin_url( 'admin.php' ) );
56
 
57
  // If user is not super admin and website is multisite then change the URL.
58
- if ( $this->_plugin->IsMultisite() && ! is_super_admin() ) {
59
  $buy_now = 'https://wpactivitylog.com/pricing/';
60
  $trial_link = 'https://wpactivitylog.com/pricing/';
61
  $buy_now_target = ' target="_blank"';
62
- } elseif ( $this->_plugin->IsMultisite() && is_super_admin() ) {
63
  $buy_now = add_query_arg( 'page', 'wsal-auditlog-pricing', network_admin_url( 'admin.php' ) );
64
  $trial_link = add_query_arg( $trial_args, network_admin_url( 'admin.php' ) );
65
- } elseif ( ! $this->_plugin->IsMultisite() && ! current_user_can( 'manage_options' ) ) {
66
  $buy_now = 'https://wpactivitylog.com/pricing/';
67
  $trial_link = 'https://wpactivitylog.com/pricing/';
68
  $buy_now_target = ' target="_blank"';
3
  * Addons HTML View in Admin.
4
  *
5
  * @package wsal
6
+ * @subpackage views
7
  */
8
 
9
  if ( ! defined( 'ABSPATH' ) ) {
33
  case 'wp-activity-log_page_wsal-search':
34
  $utm_params['utm_content'] = 'search';
35
  break;
36
+ default:
37
+ // Fallback for any other hook suffix would go here.
38
+ break;
39
  }
40
  // Links.
41
  $more_info = add_query_arg(
47
  $trial_args = array(
48
  'page' => 'wsal-auditlog-pricing',
49
  'billing_cycle' => 'annual',
50
+ 'trial' => 'true',
51
  );
52
 
53
  // Buy Now button link.
56
  $trial_link = add_query_arg( $trial_args, admin_url( 'admin.php' ) );
57
 
58
  // If user is not super admin and website is multisite then change the URL.
59
+ if ( $this->plugin->is_multisite() && ! is_super_admin() ) {
60
  $buy_now = 'https://wpactivitylog.com/pricing/';
61
  $trial_link = 'https://wpactivitylog.com/pricing/';
62
  $buy_now_target = ' target="_blank"';
63
+ } elseif ( $this->plugin->is_multisite() && is_super_admin() ) {
64
  $buy_now = add_query_arg( 'page', 'wsal-auditlog-pricing', network_admin_url( 'admin.php' ) );
65
  $trial_link = add_query_arg( $trial_args, network_admin_url( 'admin.php' ) );
66
+ } elseif ( $this->plugin->is_multisite() && ! current_user_can( 'manage_options' ) ) {
67
  $buy_now = 'https://wpactivitylog.com/pricing/';
68
  $trial_link = 'https://wpactivitylog.com/pricing/';
69
  $buy_now_target = ' target="_blank"';
classes/WidgetManager.php CHANGED
@@ -27,7 +27,7 @@ class WSAL_WidgetManager {
27
  *
28
  * @var WpSecurityAuditLog
29
  */
30
- protected $_plugin;
31
 
32
  /**
33
  * Method: Constructor.
@@ -35,7 +35,7 @@ class WSAL_WidgetManager {
35
  * @param WpSecurityAuditLog $plugin - Instance of WpSecurityAuditLog.
36
  */
37
  public function __construct( WpSecurityAuditLog $plugin ) {
38
- $this->_plugin = $plugin;
39
  add_action( 'wp_dashboard_setup', array( $this, 'add_widgets' ) );
40
  }
41
 
@@ -46,13 +46,13 @@ class WSAL_WidgetManager {
46
  global $pagenow;
47
 
48
  if (
49
- $this->_plugin->settings()->IsWidgetsEnabled() // If widget is enabled.
50
- && $this->_plugin->settings()->CurrentUserCan( 'view' ) // If user has permission to view.
51
- && 'index.php' === $pagenow // If the current page is dashboard.
52
  ) {
53
  wp_add_dashboard_widget(
54
  'wsal',
55
- __( 'Latest Events', 'wp-security-audit-log' ) . ' | WP Activity Log',
56
  array( $this, 'render_widget' )
57
  );
58
  }
@@ -64,7 +64,7 @@ class WSAL_WidgetManager {
64
  public function render_widget() {
65
  // get the events for the dashboard widget.
66
  $query = $this->get_dashboard_widget_query();
67
- $results = $query->getAdapter()->Execute( $query );
68
 
69
  ?><div>
70
  <?php if ( ! count( $results ) ) : ?>
@@ -80,21 +80,21 @@ class WSAL_WidgetManager {
80
  </thead>
81
  <tbody>
82
  <?php
83
- $url = 'admin.php?page=' . $this->_plugin->views->views[0]->GetSafeViewName();
84
  foreach ( $results as $entry ) :
85
- $event_meta = $entry->GetMetaArray();
86
- $username = WSAL_Utilities_UsersUtils::GetUsername( $event_meta );
87
  ?>
88
- <tr>
89
- <td><?php echo ( $username ) ? esc_html( $username ) : '<i>unknown</i>'; ?></td>
90
- <td><?php echo ( $event_meta['Object'] ) ? esc_html( $event_meta['Object'] ) : '<i>unknown</i>'; ?></td>
91
- <td><?php echo ( $event_meta['EventType'] ) ? esc_html( $event_meta['EventType'] ) : '<i>unknown</i>'; ?></td>
92
- <td>
93
- <a href="<?php echo esc_url( $url ) . '#Event' . esc_attr( $entry->getId() ); ?>">
94
- <?php echo wp_kses( $entry->GetMessage( $event_meta, 'dashboard-widget' ), $this->_plugin->allowed_html_tags ); ?>
95
- </a>
96
- </td>
97
- </tr>
98
  <?php endforeach; ?>
99
  </tbody>
100
  </table>
@@ -115,12 +115,12 @@ class WSAL_WidgetManager {
115
  // get the site we are on (of multisite).
116
  $bid = (int) $this->get_view_site_id();
117
  if ( $bid ) {
118
- $query->addCondition( 'site_id = %s ', $bid );
119
  }
120
  // order by date of creation.
121
- $query->addOrderBy( 'created_on', true );
122
  // set the limit based on the limit option for dashboard alerts.
123
- $query->setLimit( $this->_plugin->settings()->GetDashboardWidgetMaxAlerts() );
124
  return $query;
125
  }
126
 
27
  *
28
  * @var WpSecurityAuditLog
29
  */
30
+ protected $plugin;
31
 
32
  /**
33
  * Method: Constructor.
35
  * @param WpSecurityAuditLog $plugin - Instance of WpSecurityAuditLog.
36
  */
37
  public function __construct( WpSecurityAuditLog $plugin ) {
38
+ $this->plugin = $plugin;
39
  add_action( 'wp_dashboard_setup', array( $this, 'add_widgets' ) );
40
  }
41
 
46
  global $pagenow;
47
 
48
  if (
49
+ $this->plugin->settings()->is_widgets_enabled() // If widget is enabled.
50
+ && $this->plugin->settings()->current_user_can( 'view' ) // If user has permission to view.
51
+ && 'index.php' === $pagenow // If the current page is dashboard.
52
  ) {
53
  wp_add_dashboard_widget(
54
  'wsal',
55
+ esc_html__( 'Latest Events', 'wp-security-audit-log' ) . ' | WP Activity Log',
56
  array( $this, 'render_widget' )
57
  );
58
  }
64
  public function render_widget() {
65
  // get the events for the dashboard widget.
66
  $query = $this->get_dashboard_widget_query();
67
+ $results = $query->get_adapter()->execute_query( $query );
68
 
69
  ?><div>
70
  <?php if ( ! count( $results ) ) : ?>
80
  </thead>
81
  <tbody>
82
  <?php
83
+ $url = 'admin.php?page=' . $this->plugin->views->views[0]->get_safe_view_name();
84
  foreach ( $results as $entry ) :
85
+ $event_meta = $entry->get_meta_array();
86
+ $username = WSAL_Utilities_UsersUtils::get_username( $event_meta );
87
  ?>
88
+ <tr>
89
+ <td><?php echo ( $username ) ? esc_html( $username ) : '<i>unknown</i>'; ?></td>
90
+ <td><?php echo ( $event_meta['Object'] ) ? esc_html( $event_meta['Object'] ) : '<i>unknown</i>'; ?></td>
91
+ <td><?php echo ( $event_meta['EventType'] ) ? esc_html( $event_meta['EventType'] ) : '<i>unknown</i>'; ?></td>
92
+ <td>
93
+ <a href="<?php echo esc_url( $url ) . '#Event' . esc_attr( $entry->get_id() ); ?>">
94
+ <?php echo wp_kses( $entry->get_message( $event_meta, 'dashboard-widget' ), $this->plugin->allowed_html_tags ); ?>
95
+ </a>
96
+ </td>
97
+ </tr>
98
  <?php endforeach; ?>
99
  </tbody>
100
  </table>
115
  // get the site we are on (of multisite).
116
  $bid = (int) $this->get_view_site_id();
117
  if ( $bid ) {
118
+ $query->add_condition( 'site_id = %s ', $bid );
119
  }
120
  // order by date of creation.
121
+ $query->add_order_by( 'created_on', true );
122
  // set the limit based on the limit option for dashboard alerts.
123
+ $query->set_limit( $this->plugin->settings()->get_dashboard_widget_max_alerts() );
124
  return $query;
125
  }
126
 
css/dist/wsal-wizard.css CHANGED
@@ -1,177 +1 @@
1
- /**
2
- * WSAL Wizard Styles
3
- */
4
- body {
5
- margin: 65px auto 24px;
6
- -webkit-box-shadow: none;
7
- box-shadow: none;
8
- background: #f1f1f1;
9
- padding: 0;
10
- border: none; }
11
-
12
- #wsal-logo {
13
- border: 0;
14
- margin: 0 0 24px;
15
- padding: 0;
16
- text-align: center; }
17
- #wsal-logo img {
18
- width: 400px; }
19
-
20
- .steps {
21
- display: flex;
22
- list-style-type: none;
23
- margin: 0;
24
- padding: 0 0 25px;
25
- text-align: center; }
26
- .steps li {
27
- flex: 1 0 auto;
28
- font-weight: 700;
29
- margin: 0 0 5px;
30
- color: #b4b9be;
31
- padding-bottom: 15px;
32
- position: relative; }
33
- .steps li.is-active {
34
- color: #009344; }
35
- .steps li.is-active::before {
36
- border: 4px solid #009344;
37
- background: #009344; }
38
- .steps li::before {
39
- content: '';
40
- border: 4px solid #b4b9be;
41
- border-radius: 100%;
42
- width: 4px;
43
- height: 4px;
44
- position: absolute;
45
- bottom: 0;
46
- left: 50%;
47
- margin-left: -6px;
48
- margin-bottom: -8px;
49
- background: #b4b9be; }
50
-
51
- .wsal-setup-content {
52
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.13);
53
- padding: 2em;
54
- margin: 0 0 20px;
55
- background: #fff;
56
- overflow: hidden;
57
- zoom: 1;
58
- text-align: left; }
59
- .wsal-setup-content h4,
60
- .wsal-setup-content fieldset {
61
- line-height: 1.5; }
62
- .wsal-setup-content .addon-wrapper {
63
- border: 1px solid #eee;
64
- padding: 15px;
65
- display: flex;
66
- margin-bottom: 15px; }
67
- .wsal-setup-content .addon-wrapper:hover {
68
- border-color: #ccc; }
69
- .wsal-setup-content .addon-wrapper img {
70
- align-self: center;
71
- max-width: 200px;
72
- margin-right: 15px; }
73
-
74
- .wsal-setup-actions {
75
- text-align: center; }
76
- .wsal-setup-actions .button {
77
- box-shadow: none;
78
- font-size: 14px;
79
- height: auto;
80
- padding: 8px 20px;
81
- min-width: 12em;
82
- min-width: auto;
83
- transition: 0.1s all linear; }
84
- .wsal-setup-actions .button-primary {
85
- background-color: #009344;
86
- border-color: #009344;
87
- box-shadow: none;
88
- text-shadow: none;
89
- margin: 0;
90
- opacity: 1; }
91
- .wsal-setup-actions .button-primary:hover, .wsal-setup-actions .button-primary:focus {
92
- background: #00ad50;
93
- border-color: #00ad50;
94
- box-shadow: none;
95
- color: #fff; }
96
-
97
- .wsal-setup-footer {
98
- text-align: center; }
99
- .wsal-setup-footer a {
100
- color: #009344;
101
- font-size: 14px;
102
- text-decoration: none; }
103
-
104
- .wsal-setup-form label[for="editor-users-box"],
105
- .wsal-setup-form label[for="editor-roles-box"],
106
- .wsal-setup-form label[for="exuser-query-box"],
107
- .wsal-setup-form label[for="exrole-query-box"],
108
- .wsal-setup-form label[for="ipaddr-query-box"] {
109
- display: inline-block;
110
- margin: 5px 0; }
111
- .wsal-setup-form label[for="editor-users-box"] span,
112
- .wsal-setup-form label[for="editor-roles-box"] span,
113
- .wsal-setup-form label[for="exuser-query-box"] span,
114
- .wsal-setup-form label[for="exrole-query-box"] span,
115
- .wsal-setup-form label[for="ipaddr-query-box"] span {
116
- display: inline-block;
117
- min-width: 100px; }
118
-
119
- .sectoken-user,
120
- .sectoken-role,
121
- .sectoken-ip,
122
- .sectoken-other {
123
- display: inline-block;
124
- border-width: 1px;
125
- border-style: solid;
126
- padding: 2px 4px;
127
- margin: 2px 0 0 2px;
128
- border-radius: 3px;
129
- cursor: default;
130
- line-height: 1.3;
131
- font-size: 14px; }
132
- .sectoken-user a,
133
- .sectoken-role a,
134
- .sectoken-ip a,
135
- .sectoken-other a {
136
- text-decoration: none;
137
- font-size: 12px;
138
- font-weight: bold;
139
- color: #FFF;
140
- margin-left: 2px;
141
- background: #BBB;
142
- border-radius: 25px;
143
- height: 14px;
144
- display: inline-block;
145
- vertical-align: middle;
146
- width: 14px;
147
- text-align: center;
148
- line-height: 12px; }
149
- .sectoken-user a:hover,
150
- .sectoken-role a:hover,
151
- .sectoken-ip a:hover,
152
- .sectoken-other a:hover {
153
- background: #FB9; }
154
-
155
- .sectoken-other {
156
- display: table;
157
- border-collapse: separate; }
158
-
159
- .sectoken-role {
160
- background: #EFE;
161
- border-color: #5B5; }
162
-
163
- .sectoken-user {
164
- background: #EFF;
165
- border-color: #5BE; }
166
-
167
- .sectoken-ip {
168
- background: #FFE;
169
- border-color: #ED5; }
170
-
171
- .sectoken-other {
172
- background: #FFE;
173
- border-color: #ED5; }
174
-
175
- p.description {
176
- font-size: 13px;
177
- font-style: italic; }
1
+ body{background:#f1f1f1;border:none;box-shadow:none;margin:65px auto 24px;padding:0}#wsal-logo{border:0;margin:0 0 24px;padding:0;text-align:center}#wsal-logo img{width:400px}.steps{display:flex;list-style-type:none;margin:0;padding:0 0 25px;text-align:center}.steps li{color:#b4b9be;flex:1 0 auto;font-weight:700;margin:0 0 5px;padding-bottom:15px;position:relative}.steps li.is-active{color:#009344}.steps li.is-active:before{background:#009344;border:4px solid #009344}.steps li:before{background:#b4b9be;border:4px solid #b4b9be;border-radius:100%;bottom:0;content:"";height:4px;left:50%;margin-bottom:-8px;margin-left:-6px;position:absolute;width:4px}.wsal-setup-content{zoom:1;background:#fff;box-shadow:0 1px 3px rgba(0,0,0,.13);margin:0 0 20px;overflow:hidden;padding:2em;text-align:left}.wsal-setup-content fieldset,.wsal-setup-content h4{line-height:1.5}.wsal-setup-content .addon-wrapper{border:1px solid #eee;display:flex;margin-bottom:15px;padding:15px}.wsal-setup-content .addon-wrapper:hover{border-color:#ccc}.wsal-setup-content .addon-wrapper img{align-self:center;margin-right:15px;max-width:200px}.wsal-setup-actions{text-align:center}.wsal-setup-actions .button{box-shadow:none;font-size:14px;height:auto;min-width:12em;min-width:auto;padding:8px 20px;transition:all .1s linear}.wsal-setup-actions .button-primary{background-color:#009344;border-color:#009344;box-shadow:none;margin:0;opacity:1;text-shadow:none}.wsal-setup-actions .button-primary:focus,.wsal-setup-actions .button-primary:hover{background:#00ad50;border-color:#00ad50;box-shadow:none;color:#fff}.wsal-setup-footer{text-align:center}.wsal-setup-footer a{color:#009344;font-size:14px;text-decoration:none}.wsal-setup-form label[for=editor-roles-box],.wsal-setup-form label[for=editor-users-box],.wsal-setup-form label[for=exrole-query-box],.wsal-setup-form label[for=exuser-query-box],.wsal-setup-form label[for=ipaddr-query-box]{display:inline-block;margin:5px 0}.wsal-setup-form label[for=editor-roles-box] span,.wsal-setup-form label[for=editor-users-box] span,.wsal-setup-form label[for=exrole-query-box] span,.wsal-setup-form label[for=exuser-query-box] span,.wsal-setup-form label[for=ipaddr-query-box] span{display:inline-block;min-width:100px}.sectoken-ip,.sectoken-other,.sectoken-role,.sectoken-user{border-radius:3px;border-style:solid;border-width:1px;cursor:default;display:inline-block;font-size:14px;line-height:1.3;margin:2px 0 0 2px;padding:2px 4px}.sectoken-ip a,.sectoken-other a,.sectoken-role a,.sectoken-user a{background:#bbb;border-radius:25px;color:#fff;display:inline-block;font-size:12px;font-weight:700;height:14px;line-height:12px;margin-left:2px;text-align:center;text-decoration:none;vertical-align:middle;width:14px}.sectoken-ip a:hover,.sectoken-other a:hover,.sectoken-role a:hover,.sectoken-user a:hover{background:#fb9}.sectoken-other{border-collapse:separate;display:table}.sectoken-role{background:#efe;border-color:#5b5}.sectoken-user{background:#eff;border-color:#5be}.sectoken-ip,.sectoken-other{background:#ffe;border-color:#ed5}p.description{font-size:13px;font-style:italic}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
css/dist/wsal-wizard.min.css DELETED
@@ -1 +0,0 @@
1
- body{margin:65px auto 24px;-webkit-box-shadow:none;box-shadow:none;background:#f1f1f1;padding:0;border:none}#wsal-logo{border:0;margin:0 0 24px;padding:0;text-align:center}#wsal-logo img{width:400px}.steps{display:flex;list-style-type:none;margin:0;padding:0 0 25px;text-align:center}.steps li{flex:1 0 auto;font-weight:700;margin:0 0 5px;color:#b4b9be;padding-bottom:15px;position:relative}.steps li.is-active{color:#009344}.steps li.is-active::before{border:4px solid #009344;background:#009344}.steps li::before{content:'';border:4px solid #b4b9be;border-radius:100%;width:4px;height:4px;position:absolute;bottom:0;left:50%;margin-left:-6px;margin-bottom:-8px;background:#b4b9be}.wsal-setup-content{box-shadow:0 1px 3px rgba(0,0,0,.13);padding:2em;margin:0 0 20px;background:#fff;overflow:hidden;zoom:1;text-align:left}.wsal-setup-content fieldset,.wsal-setup-content h4{line-height:1.5}.wsal-setup-content .addon-wrapper{border:1px solid #eee;padding:15px;display:flex;margin-bottom:15px}.wsal-setup-content .addon-wrapper:hover{border-color:#ccc}.wsal-setup-content .addon-wrapper img{align-self:center;max-width:200px;margin-right:15px}.wsal-setup-actions{text-align:center}.wsal-setup-actions .button{box-shadow:none;font-size:14px;height:auto;padding:8px 20px;min-width:12em;min-width:auto;transition:.1s all linear}.wsal-setup-actions .button-primary{background-color:#009344;border-color:#009344;box-shadow:none;text-shadow:none;margin:0;opacity:1}.wsal-setup-actions .button-primary:focus,.wsal-setup-actions .button-primary:hover{background:#00ad50;border-color:#00ad50;box-shadow:none;color:#fff}.wsal-setup-footer{text-align:center}.wsal-setup-footer a{color:#009344;font-size:14px;text-decoration:none}.wsal-setup-form label[for=editor-roles-box],.wsal-setup-form label[for=editor-users-box],.wsal-setup-form label[for=exrole-query-box],.wsal-setup-form label[for=exuser-query-box],.wsal-setup-form label[for=ipaddr-query-box]{display:inline-block;margin:5px 0}.wsal-setup-form label[for=editor-roles-box] span,.wsal-setup-form label[for=editor-users-box] span,.wsal-setup-form label[for=exrole-query-box] span,.wsal-setup-form label[for=exuser-query-box] span,.wsal-setup-form label[for=ipaddr-query-box] span{display:inline-block;min-width:100px}.sectoken-ip,.sectoken-other,.sectoken-role,.sectoken-user{display:inline-block;border-width:1px;border-style:solid;padding:2px 4px;margin:2px 0 0 2px;border-radius:3px;cursor:default;line-height:1.3;font-size:14px}.sectoken-ip a,.sectoken-other a,.sectoken-role a,.sectoken-user a{text-decoration:none;font-size:12px;font-weight:700;color:#fff;margin-left:2px;background:#bbb;border-radius:25px;height:14px;display:inline-block;vertical-align:middle;width:14px;text-align:center;line-height:12px}.sectoken-ip a:hover,.sectoken-other a:hover,.sectoken-role a:hover,.sectoken-user a:hover{background:#fb9}.sectoken-other{display:table;border-collapse:separate}.sectoken-role{background:#efe;border-color:#5b5}.sectoken-user{background:#eff;border-color:#5be}.sectoken-ip{background:#ffe;border-color:#ed5}.sectoken-other{background:#ffe;border-color:#ed5}p.description{font-size:13px;font-style:italic}
 
defaults.php CHANGED
@@ -7,6 +7,8 @@
7
  * @package wsal
8
  */
9
 
 
 
10
  // Exit if accessed directly.
11
  if ( ! defined( 'ABSPATH' ) ) {
12
  exit;
@@ -29,7 +31,6 @@ defined( 'E_CRITICAL' ) || define( 'E_CRITICAL', 'E_CRITICAL' );
29
  * @param WpSecurityAuditLog $wsal - Instance of main plugin.
30
  *
31
  * @since 3.5.1 - Added the `wsal_custom_alerts_dirs` filter.
32
- *
33
  */
34
  function wsal_load_include_custom_files( $wsal ) {
35
  $paths = apply_filters( 'wsal_custom_alerts_dirs', array() );
@@ -42,7 +43,7 @@ function wsal_load_include_custom_files( $wsal ) {
42
  require_once $file;
43
  if ( ! empty( $custom_alerts ) && is_array( $custom_alerts ) ) {
44
  try {
45
- $wsal->alerts->RegisterGroup( $custom_alerts );
46
  } catch ( Exception $ex ) {
47
  $wsal->wsal_log( $ex->getMessage() );
48
  }
@@ -53,14 +54,14 @@ function wsal_load_include_custom_files( $wsal ) {
53
  }
54
 
55
  /**
56
- * Builds a configuration object of links suitable for the the events definition.
57
  *
58
- * @param string[] $link_aliases
59
  *
60
  * @return array
61
  */
62
- function wsaldefaults_build_links( $link_aliases = [] ) {
63
- $result = [];
64
 
65
  if ( ! empty( $link_aliases ) ) {
66
  foreach ( $link_aliases as $link_alias ) {
@@ -68,70 +69,70 @@ function wsaldefaults_build_links( $link_aliases = [] ) {
68
  case 'CategoryLink':
69
  case 'cat_link':
70
  case 'ProductCatLink':
71
- $result[ __( 'View category', 'wp-security-audit-log' ) ] = '%' . $link_alias . '%';
72
  break;
73
 
74
  case 'ContactSupport':
75
- $result[ __( 'Contact Support', 'wp-security-audit-log' ) ] = 'https://wpactivitylog.com/contact/';
76
  break;
77
 
78
  case 'CommentLink':
79
- $result[ __( 'Comment', 'wp-security-audit-log' ) ] = [
80
- // before 4.2.1 the CommentLink meta would contain the full HTML markup for the link, now it
81
- // contains only the URL
82
  'url' => '%CommentLink%',
83
- 'label' => '%CommentDate%'
84
- ];
85
  break;
86
 
87
  case 'EditorLinkPage':
88
- $result[ __( 'View page in the editor', 'wp-security-audit-log' ) ] = '%EditorLinkPage%';
89
  break;
90
 
91
  case 'EditorLinkPost':
92
- $result[ __( 'View the post in editor', 'wp-security-audit-log' ) ] = '%EditorLinkPost%';
93
  break;
94
 
95
  case 'EditorLinkOrder':
96
- // @todo move to the WooCommerce extension
97
- $result[ __( 'View the order', 'wp-security-audit-log' ) ] = '%EditorLinkOrder%';
98
  break;
99
 
100
  case 'EditUserLink':
101
- $result[ __( 'User profile page', 'wp-security-audit-log' ) ] = '%EditUserLink%';
102
  break;
103
 
104
  case 'LinkFile':
105
- $result[ __( 'Open the log file', 'wp-security-audit-log' ) ] = '%LinkFile%';
106
  break;
107
 
108
  case 'LogFileLink':
109
- // we don't show the link anymore
110
  break;
111
 
112
  case 'MenuUrl':
113
- $result[ __( 'View menu', 'wp-security-audit-log' ) ] = '%MenuUrl%';
114
  break;
115
 
116
  case 'PostUrl':
117
- $result[ __( 'URL', 'wp-security-audit-log' ) ] = '%PostUrl%';
118
  break;
119
 
120
  case 'AttachmentUrl':
121
- $result[ __( 'View attachment page', 'wp-security-audit-log' ) ] = '%AttachmentUrl%';
122
  break;
123
 
124
  case 'PostUrlIfPlublished':
125
  case 'PostUrlIfPublished':
126
- $result[ __( 'URL', 'wp-security-audit-log' ) ] = '%PostUrlIfPlublished%';
127
  break;
128
 
129
  case 'RevisionLink':
130
- $result[ __( 'View the content changes', 'wp-security-audit-log' ) ] = '%RevisionLink%';
131
  break;
132
 
133
  case 'TagLink':
134
- $result[ __( 'View tag', 'wp-security-audit-log' ) ] = '%RevisionLink%';
135
  break;
136
 
137
  case 'LogFileText':
@@ -145,7 +146,7 @@ function wsaldefaults_build_links( $link_aliases = [] ) {
145
  break;
146
 
147
  default:
148
- // unsupported link alias
149
  }
150
  }
151
  }
@@ -159,7 +160,7 @@ function wsaldefaults_build_links( $link_aliases = [] ) {
159
  * Define default alerts for the plugin.
160
  */
161
  function wsaldefaults_wsal_init() {
162
- $wsal = WpSecurityAuditLog::GetInstance();
163
 
164
  if ( ! isset( $wsal->constants ) ) {
165
  $wsal->constants = new WSAL_ConstantManager();
@@ -173,959 +174,959 @@ function wsaldefaults_wsal_init() {
173
  * severity is based on monolog log levels
174
  * @see https://github.com/Seldaek/monolog/blob/main/doc/01-usage.md#log-levels
175
  */
176
- // ALERT (550): Action must be taken immediately.
177
- $wsal->constants->AddConstant( 'WSAL_CRITICAL', 500, __( 'Critical severity events.', 'wp-security-audit-log' ) );
178
- // ERROR (400): Runtime errors that do not require immediate action but should typically be logged and monitored.
179
- $wsal->constants->AddConstant( 'WSAL_HIGH', 400, __( 'High severity events.', 'wp-security-audit-log' ) );
180
- // WARNING (300): Exceptional occurrences that are not errors.
181
- $wsal->constants->AddConstant( 'WSAL_MEDIUM', 300, __( 'Medium severity events.', 'wp-security-audit-log' ) );
182
- // NOTICE (250): Normal but significant events.
183
- $wsal->constants->AddConstant( 'WSAL_LOW', 250, __( 'Low severity events.', 'wp-security-audit-log' ) );
184
- // INFO (200): Interesting events.
185
- $wsal->constants->AddConstant( 'WSAL_INFORMATIONAL', 200, __( 'Informational events.', 'wp-security-audit-log' ) );
186
 
187
  // Create list of default alerts.
188
- $wsal->alerts->RegisterGroup(
189
  array(
190
- __( 'Users Logins & Sessions Events', 'wp-security-audit-log' ) => array(
191
- __( 'User Activity', 'wp-security-audit-log' ) => array(
192
  array(
193
  1000,
194
  WSAL_LOW,
195
- __( 'User logged in', 'wp-security-audit-log' ),
196
- __( 'User logged in.', 'wp-security-audit-log' ),
197
- [],
198
- [],
199
  'user',
200
- 'login'
201
  ),
202
  array(
203
  1001,
204
  WSAL_LOW,
205
- __( 'User logged out', 'wp-security-audit-log' ),
206
- __( 'User logged out.', 'wp-security-audit-log' ),
207
- [],
208
- [],
209
  'user',
210
- 'logout'
211
  ),
212
  array(
213
  1002,
214
  WSAL_MEDIUM,
215
- __( 'Login failed', 'wp-security-audit-log' ),
216
- __( '%Attempts% failed login(s).', 'wp-security-audit-log' ),
217
- [],
218
- [],
219
  'user',
220
- 'failed-login'
221
  ),
222
  array(
223
  1003,
224
  WSAL_LOW,
225
- __( 'Login failed / non existing user', 'wp-security-audit-log' ),
226
- __( '%Attempts% failed login(s).', 'wp-security-audit-log' ),
227
- [],
228
- wsaldefaults_build_links( [ 'LogFileText' ] ),
229
  'system',
230
- 'failed-login'
231
  ),
232
  array(
233
  1004,
234
  WSAL_MEDIUM,
235
- __( 'Login blocked', 'wp-security-audit-log' ),
236
- __( 'Login blocked because other session(s) already exist for this user.', 'wp-security-audit-log' ),
237
- [
238
- __( 'IP address', 'wp-security-audit-log' ) => '%ClientIP%'
239
- ],
240
- [],
241
  'user',
242
- 'blocked'
243
  ),
244
  array(
245
  1005,
246
  WSAL_LOW,
247
- __( 'User logged in with existing session(s)', 'wp-security-audit-log' ),
248
- __( 'User logged in however there are other session(s) already for this user.', 'wp-security-audit-log' ),
249
- [
250
- __( 'IP address(es)', 'wp-security-audit-log' ) => '%IPAddress%'
251
- ],
252
- [],
253
  'user',
254
- 'login'
255
  ),
256
  array(
257
  1006,
258
  WSAL_MEDIUM,
259
- __( 'User logged out all other sessions with the same username', 'wp-security-audit-log' ),
260
- __( 'Logged out all other sessions with the same user.', 'wp-security-audit-log' ),
261
- [],
262
- [],
263
  'user',
264
- 'logout'
265
  ),
266
  array(
267
  1007,
268
  WSAL_MEDIUM,
269
- __( 'User session destroyed and logged out', 'wp-security-audit-log' ),
270
- __( 'Terminated the session of the user %TargetUserName%.', 'wp-security-audit-log' ),
271
- [
272
- __( 'Role', 'wp-security-audit-log' ) => '%TargetUserRole%',
273
- __( 'Session ID', 'wp-security-audit-log' ) => '%TargetSessionID%'
274
- ],
275
- [],
276
  'user',
277
- 'logout'
278
  ),
279
  array(
280
  1008,
281
  WSAL_MEDIUM,
282
- __( 'Switched to another user', 'wp-security-audit-log' ),
283
- __( 'Switched the session to being logged in as %TargetUserName%.', 'wp-security-audit-log' ),
284
- [
285
- __( 'Role', 'wp-security-audit-log' ) => '%TargetUserRole%'
286
- ],
287
- [],
288
  'user',
289
- 'login'
290
  ),
291
  array(
292
  1009,
293
  WSAL_LOW,
294
- __( 'The plugin terminated an idle session for a user', 'wp-security-audit-log' ),
295
- __( 'The plugin terminated an idle session for the user %username%.', 'wp-security-audit-log' ),
296
- [
297
- __( 'Role', 'wp-security-audit-log' ) => '%TargetUserRole%',
298
- __( 'Session ID', 'wp-security-audit-log' ) => '%SessionID%'
299
- ],
300
- [],
301
  'user',
302
- 'logout'
303
  ),
304
  array(
305
  2010,
306
  WSAL_MEDIUM,
307
- __( 'User uploaded file to the Uploads directory', 'wp-security-audit-log' ),
308
- __( 'Uploaded a file called %FileName%.', 'wp-security-audit-log' ),
309
- [
310
- __( 'Directory', 'wp-security-audit-log' ) => '%FilePath%'
311
- ],
312
- wsaldefaults_build_links( [ 'AttachmentUrl' ] ),
313
  'file',
314
- 'uploaded'
315
  ),
316
  array(
317
  2011,
318
  WSAL_LOW,
319
- __( 'User deleted file from Uploads directory', 'wp-security-audit-log' ),
320
- __( 'Deleted the file %FileName%.', 'wp-security-audit-log' ),
321
- [
322
- __( 'Directory', 'wp-security-audit-log' ) => '%FilePath%'
323
- ],
324
- [],
325
  'file',
326
- 'deleted'
327
  ),
328
  array(
329
  1010,
330
  WSAL_INFORMATIONAL,
331
- __( 'User requested a password reset', 'wp-security-audit-log' ),
332
- __( 'User requested a password reset. This does not mean that the password was changed.', 'wp-security-audit-log' ),
333
- [],
334
- [],
335
  'user',
336
- 'submitted'
337
  ),
338
  ),
339
  ),
340
 
341
- __( 'Content & Comments', 'wp-security-audit-log' ) => array(
342
- __( 'Content', 'wp-security-audit-log' ) => array(
343
  array(
344
  2000,
345
  WSAL_INFORMATIONAL,
346
- __( 'User created a new post and saved it as draft', 'wp-security-audit-log' ),
347
- __( 'Created the post %PostTitle%.', 'wp-security-audit-log' ),
348
- [
349
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
350
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
351
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%'
352
- ],
353
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
354
  'post',
355
- 'created'
356
  ),
357
  array(
358
  2001,
359
  WSAL_LOW,
360
- __( 'User published a post', 'wp-security-audit-log' ),
361
- __( 'Published the post %PostTitle%.', 'wp-security-audit-log' ),
362
- [
363
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
364
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
365
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%'
366
- ],
367
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
368
  'post',
369
- 'published'
370
  ),
371
  array(
372
  2002,
373
  WSAL_LOW,
374
- __( 'User modified a post', 'wp-security-audit-log' ),
375
- __( 'Modified the post %PostTitle%.', 'wp-security-audit-log' ),
376
- [
377
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
378
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
379
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%'
380
- ],
381
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
382
  'post',
383
- 'modified'
384
  ),
385
  array(
386
  2008,
387
  WSAL_MEDIUM,
388
- __( 'User permanently deleted a post from the trash', 'wp-security-audit-log' ),
389
- __( 'Permanently deleted the post %PostTitle%.', 'wp-security-audit-log' ),
390
- [
391
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
392
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
393
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%'
394
- ],
395
- [],
396
  'post',
397
- 'deleted'
398
  ),
399
  array(
400
  2012,
401
  WSAL_MEDIUM,
402
- __( 'User moved a post to the trash', 'wp-security-audit-log' ),
403
- __( 'Moved the post %PostTitle% to trash.', 'wp-security-audit-log' ),
404
- [
405
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
406
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
407
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%'
408
- ],
409
- wsaldefaults_build_links( [ 'PostUrlIfPublished' ] ),
410
  'post',
411
- 'deleted'
412
  ),
413
  array(
414
  2014,
415
  WSAL_LOW,
416
- __( 'User restored a post from trash', 'wp-security-audit-log' ),
417
- __( 'Restored the post %PostTitle% from trash.', 'wp-security-audit-log' ),
418
- [
419
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
420
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
421
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%'
422
- ],
423
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
424
  'post',
425
- 'restored'
426
  ),
427
  array(
428
  2017,
429
  WSAL_INFORMATIONAL,
430
- __( 'User changed post URL', 'wp-security-audit-log' ),
431
- __( 'Changed the URL of the post %PostTitle%.', 'wp-security-audit-log' ),
432
- [
433
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
434
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
435
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
436
- __( 'Previous URL', 'wp-security-audit-log' ) => '%OldUrl%',
437
- __( 'New URL', 'wp-security-audit-log' ) => '%NewUrl%'
438
- ],
439
- wsaldefaults_build_links( [ 'EditorLinkPost' ] ),
440
  'post',
441
- 'modified'
442
  ),
443
  array(
444
  2019,
445
  WSAL_INFORMATIONAL,
446
- __( 'User changed post author', 'wp-security-audit-log' ),
447
- __( 'Changed the author of the post %PostTitle% to %NewAuthor%.', 'wp-security-audit-log' ),
448
- [
449
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
450
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
451
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
452
- __( 'Previous author', 'wp-security-audit-log' ) => '%OldAuthor%'
453
- ],
454
- wsaldefaults_build_links( [ 'PostUrlIfPublished' ] ),
455
  'post',
456
- 'modified'
457
  ),
458
  array(
459
  2021,
460
  WSAL_MEDIUM,
461
- __( 'User changed post status', 'wp-security-audit-log' ),
462
- __( 'Changed the status of the post %PostTitle% to %NewStatus%.', 'wp-security-audit-log' ),
463
- [
464
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
465
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
466
- __( 'Previous status', 'wp-security-audit-log' ) => '%OldStatus%'
467
- ],
468
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
469
  'post',
470
- 'modified'
471
  ),
472
  array(
473
  2025,
474
  WSAL_LOW,
475
- __( 'User changed the visibility of a post', 'wp-security-audit-log' ),
476
- __( 'Changed the visibility of the post %PostTitle% to %NewVisibility%.', 'wp-security-audit-log' ),
477
- [
478
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
479
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
480
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
481
- __( 'Previous visibility status', 'wp-security-audit-log' ) => '%OldVisibility%'
482
- ],
483
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
484
  'post',
485
- 'modified'
486
  ),
487
  array(
488
  2027,
489
  WSAL_INFORMATIONAL,
490
- __( 'User changed the date of a post', 'wp-security-audit-log' ),
491
- __( 'Changed the date of the post %PostTitle% to %NewDate%.', 'wp-security-audit-log' ),
492
- [
493
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
494
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
495
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
496
- __( 'Previous date', 'wp-security-audit-log' ) => '%OldDate%'
497
- ],
498
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
499
  'post',
500
- 'modified'
501
  ),
502
  array(
503
  2047,
504
  WSAL_LOW,
505
- __( 'User changed the parent of a page', 'wp-security-audit-log' ),
506
- __( 'Changed the parent of the post %PostTitle% to %NewParentName%.', 'wp-security-audit-log' ),
507
- [
508
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
509
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
510
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
511
- __( 'Previous parent', 'wp-security-audit-log' ) => '%OldParentName%'
512
- ],
513
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
514
  'post',
515
- 'modified'
516
  ),
517
  array(
518
  2048,
519
  WSAL_LOW,
520
- __( 'User changed the template of a page', 'wp-security-audit-log' ),
521
- __( 'Changed the template of the post %PostTitle% to %NewTemplate%.', 'wp-security-audit-log' ),
522
- [
523
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
524
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
525
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
526
- __( 'Previous template', 'wp-security-audit-log' ) => '%OldTemplate%'
527
- ],
528
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
529
  'post',
530
- 'modified'
531
  ),
532
  array(
533
  2049,
534
  WSAL_INFORMATIONAL,
535
- __( 'User set a post as sticky', 'wp-security-audit-log' ),
536
- __( 'Set the post %PostTitle% as sticky.', 'wp-security-audit-log' ),
537
- [
538
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
539
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
540
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%'
541
- ],
542
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
543
  'post',
544
- 'modified'
545
  ),
546
  array(
547
  2050,
548
  WSAL_INFORMATIONAL,
549
- __( 'User removed post from sticky', 'wp-security-audit-log' ),
550
- __( 'Removed the post %PostTitle% from sticky.', 'wp-security-audit-log' ),
551
- [
552
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
553
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
554
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%'
555
- ],
556
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
557
  'post',
558
- 'modified'
559
  ),
560
  array(
561
  2065,
562
  WSAL_LOW,
563
- __( 'User modified the content of a post', 'wp-security-audit-log' ),
564
- __( 'Modified the content of the post %PostTitle%.', 'wp-security-audit-log' ),
565
- [
566
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
567
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
568
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%'
569
- ],
570
- wsaldefaults_build_links( [ 'RevisionLink', 'EditorLinkPost', 'PostUrlIfPublished' ] ),
571
  'post',
572
- 'modified'
573
  ),
574
  array(
575
  2073,
576
  WSAL_INFORMATIONAL,
577
- __( 'User submitted a post for review', 'wp-security-audit-log' ),
578
- __( 'Submitted the post %PostTitle% for review.', 'wp-security-audit-log' ),
579
- [
580
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
581
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
582
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%'
583
- ],
584
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
585
  'post',
586
- 'modified'
587
  ),
588
  array(
589
  2074,
590
  WSAL_LOW,
591
- __( 'User scheduled a post', 'wp-security-audit-log' ),
592
- __( 'Scheduled the post %PostTitle% to be published on %PublishingDate%.', 'wp-security-audit-log' ),
593
- [
594
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
595
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
596
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%'
597
- ],
598
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
599
  'post',
600
- 'modified'
601
  ),
602
  array(
603
  2086,
604
  WSAL_INFORMATIONAL,
605
- __( 'User changed title of a post', 'wp-security-audit-log' ),
606
- __( 'Changed the title of the post %OldTitle% to %NewTitle%.', 'wp-security-audit-log' ),
607
- [
608
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
609
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
610
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%'
611
- ],
612
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
613
  'post',
614
- 'modified'
615
  ),
616
  array(
617
  2100,
618
  WSAL_INFORMATIONAL,
619
- __( 'User opened a post in the editor', 'wp-security-audit-log' ),
620
- __( 'Opened the post %PostTitle% in the editor.', 'wp-security-audit-log' ),
621
- [
622
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
623
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
624
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%'
625
- ],
626
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
627
  'post',
628
- 'opened'
629
  ),
630
  array(
631
  2101,
632
  WSAL_INFORMATIONAL,
633
- __( 'User viewed a post', 'wp-security-audit-log' ),
634
- __( 'Viewed the post %PostTitle%.', 'wp-security-audit-log' ),
635
- [
636
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
637
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
638
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%'
639
- ],
640
- wsaldefaults_build_links( [ 'PostUrl', 'EditorLinkPost' ] ),
641
  'post',
642
- 'viewed'
643
  ),
644
  array(
645
  2111,
646
  WSAL_LOW,
647
- __( 'User enabled/disabled comments in a post', 'wp-security-audit-log' ),
648
- __( 'Comments in the post %PostTitle%.', 'wp-security-audit-log' ),
649
- [
650
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
651
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
652
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%'
653
- ],
654
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
655
  'post',
656
- 'enabled'
657
  ),
658
  array(
659
  2112,
660
  WSAL_LOW,
661
- __( 'User enabled/disabled trackbacks and pingbacks in a post', 'wp-security-audit-log' ),
662
- __( 'Pingbacks and Trackbacks in the post %PostTitle%.', 'wp-security-audit-log' ),
663
- [
664
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
665
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
666
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%'
667
- ],
668
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
669
  'post',
670
- 'enabled'
671
  ),
672
  array(
673
  2129,
674
  WSAL_INFORMATIONAL,
675
- __( 'User updated the excerpt in a post', 'wp-security-audit-log' ),
676
- __( 'The excerpt of the post %PostTitle%.', 'wp-security-audit-log' ),
677
- [
678
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
679
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
680
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
681
- __( 'Previous excerpt entry', 'wp-security-audit-log' ) => '%old_post_excerpt%',
682
- __( 'New excerpt entry', 'wp-security-audit-log' ) => '%post_excerpt%'
683
- ],
684
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
685
  'post',
686
- 'modified'
687
  ),
688
  array(
689
  2130,
690
  WSAL_INFORMATIONAL,
691
- __( 'User updated the featured image in a post', 'wp-security-audit-log' ),
692
- __( 'The featured image of the post %PostTitle%.', 'wp-security-audit-log' ),
693
- [
694
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
695
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
696
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
697
- __( 'Previous image', 'wp-security-audit-log' ) => '%previous_image%',
698
- __( 'New image', 'wp-security-audit-log' ) => '%new_image%'
699
- ],
700
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
701
  'post',
702
- 'modified'
703
  ),
704
  ),
705
 
706
- __( 'Tags', 'wp-security-audit-log' ) => array(
707
  array(
708
  2119,
709
  WSAL_INFORMATIONAL,
710
- __( 'User added post tag', 'wp-security-audit-log' ),
711
- __( 'Added tag(s) to the post %PostTitle%.', 'wp-security-audit-log' ),
712
- [
713
- __( 'ID', 'wp-security-audit-log' ) => '%PostID%',
714
- __( 'Type', 'wp-security-audit-log' ) => '%PostType%',
715
- __( 'Status', 'wp-security-audit-log' ) => '%PostStatus%',
716
- __( 'Added tag(s)', 'wp-security-audit-log' ) => '%tag%'
717
- ],
718
- wsaldefaults_build_links( [ 'EditorLinkPost' ] ),
719
  'post',
720
- 'modified'
721
  ),
722
  array(
723
  2120,
724
  WSAL_INFORMATIONAL,
725
- __( 'User removed post tag', 'wp-security-audit-log' ),
726
- __( 'Removed tag(s) from the post %PostTitle%.', 'wp-security-audit-log' ),
727
- [
728
- __( 'ID', 'wp-security-audit-log' ) => '%PostID%',
729
- __( 'Type', 'wp-security-audit-log' ) => '%PostType%',
730
- __( 'Status', 'wp-security-audit-log' ) => '%PostStatus%',
731
- __( 'Removed tag(s)', 'wp-security-audit-log' ) => '%tag%'
732
- ],
733
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
734
  'post',
735
- 'modified'
736
  ),
737
  array(
738
  2121,
739
  WSAL_INFORMATIONAL,
740
- __( 'User created new tag', 'wp-security-audit-log' ),
741
- __( 'Created the tag %TagName%.', 'wp-security-audit-log' ),
742
- [
743
- __( 'Slug', 'wp-security-audit-log' ) => 'Slug'
744
- ],
745
- wsaldefaults_build_links( [ 'TagLink' ] ),
746
  'tag',
747
- 'created'
748
  ),
749
  array(
750
  2122,
751
  WSAL_LOW,
752
- __( 'User deleted tag', 'wp-security-audit-log' ),
753
- __( 'Deleted the tag %TagName%.', 'wp-security-audit-log' ),
754
- [
755
- __( 'Slug', 'wp-security-audit-log' ) => 'Slug'
756
- ],
757
- [],
758
  'tag',
759
- 'deleted'
760
  ),
761
  array(
762
  2123,
763
  WSAL_INFORMATIONAL,
764
- __( 'Renamed the tag %old_name% to %new_name%.', 'wp-security-audit-log' ),
765
  '',
766
- [
767
- __( 'Slug', 'wp-security-audit-log' ) => '%Slug%'
768
- ],
769
- wsaldefaults_build_links( [ 'TagLink' ] ),
770
  'tag',
771
- 'renamed'
772
  ),
773
  array(
774
  2124,
775
  WSAL_INFORMATIONAL,
776
- __( 'User changed tag slug', 'wp-security-audit-log' ),
777
- __( 'Changed the slug of the tag %tag% to %new_slug%.', 'wp-security-audit-log' ),
778
- [
779
- __( 'Previous slug', 'wp-security-audit-log' ) => '%old_slug%'
780
- ],
781
- wsaldefaults_build_links( [ 'TagLink' ] ),
782
  'tag',
783
- 'modified'
784
  ),
785
  array(
786
  2125,
787
  WSAL_INFORMATIONAL,
788
- __( 'User changed tag description', 'wp-security-audit-log' ),
789
- __( 'Changed the description of the tag %tag%.', 'wp-security-audit-log' ),
790
- [
791
- __( 'Slug', 'wp-security-audit-log' ) => '%Slug%',
792
- __( 'Previous description', 'wp-security-audit-log' ) => '%old_desc%',
793
- __( 'New description', 'wp-security-audit-log' ) => '%new_desc%'
794
- ],
795
- wsaldefaults_build_links( [ 'TagLink' ] ),
796
  'tag',
797
- 'modified'
798
  ),
799
  ),
800
 
801
- __( 'Categories', 'wp-security-audit-log' ) => array(
802
  array(
803
  2016,
804
  WSAL_LOW,
805
- __( 'User changed post category', 'wp-security-audit-log' ),
806
- __( 'Changed the category(ies) of the post %PostTitle% to %NewCategories%.', 'wp-security-audit-log' ),
807
- [
808
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
809
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
810
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
811
- __( 'Previous category(ies)', 'wp-security-audit-log' ) => '%OldCategories%'
812
- ],
813
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
814
  'post',
815
- 'modified'
816
  ),
817
  array(
818
  2023,
819
  WSAL_MEDIUM,
820
- __( 'User created new category', 'wp-security-audit-log' ),
821
- __( 'Created the category %CategoryName%.', 'wp-security-audit-log' ),
822
- [
823
- __( 'Slug', 'wp-security-audit-log' ) => 'Slug'
824
- ],
825
- wsaldefaults_build_links( [ 'CategoryLink' ] ),
826
  'category',
827
- 'created'
828
  ),
829
  array(
830
  2024,
831
  WSAL_MEDIUM,
832
- __( 'User deleted category', 'wp-security-audit-log' ),
833
- __( 'Deleted the category %CategoryName%.', 'wp-security-audit-log' ),
834
- [
835
- __( 'Slug', 'wp-security-audit-log' ) => 'Slug'
836
- ],
837
- [],
838
  'category',
839
- 'deleted'
840
  ),
841
  array(
842
  2052,
843
  WSAL_LOW,
844
- __( 'Changed the parent of a category', 'wp-security-audit-log' ),
845
- __( 'Changed the parent of the category %CategoryName% to %NewParent%.', 'wp-security-audit-log' ),
846
- [
847
- __( 'Slug', 'wp-security-audit-log' ) => '%Slug%',
848
- __( 'Previous parent', 'wp-security-audit-log' ) => '%OldParent%'
849
- ],
850
- wsaldefaults_build_links( [ 'CategoryLink' ] ),
851
  'category',
852
- 'modified'
853
  ),
854
  array(
855
  2127,
856
  WSAL_LOW,
857
- __( 'User changed category name', 'wp-security-audit-log' ),
858
- __( 'Renamed the category %old_name% to %new_name%.', 'wp-security-audit-log' ),
859
- [
860
- __( 'Slug', 'wp-security-audit-log' ) => '%slug%'
861
- ],
862
- wsaldefaults_build_links( [ 'cat_link' ] ),
863
  'category',
864
- 'renamed'
865
  ),
866
  array(
867
  2128,
868
  WSAL_LOW,
869
- __( 'User changed category slug', 'wp-security-audit-log' ),
870
- __( 'Changed the slug of the category %CategoryName% to %new_slug%.', 'wp-security-audit-log' ),
871
- [
872
- __( 'Previous slug', 'wp-security-audit-log' ) => '%old_slug%'
873
- ],
874
- wsaldefaults_build_links( [ 'cat_link' ] ),
875
  'category',
876
- 'modified'
877
  ),
878
  ),
879
 
880
- __( 'Custom Fields', 'wp-security-audit-log' ) => array(
881
  array(
882
  2053,
883
  WSAL_LOW,
884
- __( 'User created a custom field for a post', 'wp-security-audit-log' ),
885
- __( 'Created the new custom field %MetaKey% in the post %PostTitle%.', 'wp-security-audit-log' ),
886
- [
887
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
888
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
889
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
890
- __( 'Custom field value', 'wp-security-audit-log' ) => '%MetaValue%'
891
- ],
892
- wsaldefaults_build_links( [ 'EditorLinkPost', 'MetaLink', 'PostUrlIfPublished' ] ),
893
  'post',
894
- 'modified'
895
  ),
896
  array(
897
  2054,
898
  WSAL_LOW,
899
- __( 'User updated a custom field value for a post', 'wp-security-audit-log' ),
900
- __( 'Modified the value of the custom field %MetaKey% in the post %PostTitle%.', 'wp-security-audit-log' ),
901
- [
902
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
903
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
904
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
905
- __( 'Previous custom field value', 'wp-security-audit-log' ) => '%MetaValueOld%',
906
- __( 'New custom field value', 'wp-security-audit-log' ) => '%MetaValueNew%'
907
- ],
908
- wsaldefaults_build_links( [ 'EditorLinkPost', 'MetaLink', 'PostUrlIfPublished' ] ),
909
  'custom-field',
910
- 'modified'
911
  ),
912
  array(
913
  2055,
914
  WSAL_MEDIUM,
915
- __( 'User deleted a custom field from a post', 'wp-security-audit-log' ),
916
- __( 'Deleted the custom field %MetaKey% from the post %PostTitle%.', 'wp-security-audit-log' ),
917
- [
918
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
919
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
920
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%'
921
- ],
922
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
923
  'custom-field',
924
- 'deleted'
925
  ),
926
  array(
927
  2062,
928
  WSAL_LOW,
929
- __( 'User updated a custom field name for a post', 'wp-security-audit-log' ),
930
- __( 'Renamed the custom field %MetaKeyOld% on post %PostTitle% to %MetaKeNew%.', 'wp-security-audit-log' ),
931
- [
932
- __( 'Post', 'wp-security-audit-log' ) => '%PostTitle%',
933
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
934
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
935
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%'
936
- ],
937
- wsaldefaults_build_links( [ 'EditorLinkPost', 'PostUrlIfPublished' ] ),
938
  'custom-field',
939
- 'renamed'
940
  ),
941
  ),
942
 
943
- __( 'Custom Fields (ACF)', 'wp-security-audit-log' ) => array(
944
  array(
945
  2131,
946
  WSAL_LOW,
947
- __( 'User added relationship to a custom field value for a post', 'wp-security-audit-log' ),
948
- __( 'Added relationships to the custom field %MetaKey% in the post %PostTitle%.', 'wp-security-audit-log' ),
949
- [
950
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
951
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
952
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
953
- __( 'New relationships', 'wp-security-audit-log' ) => '%Relationships%'
954
- ],
955
- wsaldefaults_build_links( [ 'EditorLinkPost', 'MetaLink' ] ),
956
  'custom-field',
957
- 'modified'
958
  ),
959
  array(
960
  2132,
961
  WSAL_LOW,
962
- __( 'User removed relationship from a custom field value for a post', 'wp-security-audit-log' ),
963
- __( 'Removed relationships from the custom field %MetaKey% in the post %PostTitle%.', 'wp-security-audit-log' ),
964
- [
965
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
966
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
967
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
968
- __( 'Removed relationships', 'wp-security-audit-log' ) => '%Relationships%'
969
- ],
970
- wsaldefaults_build_links( [ 'EditorLinkPost', 'MetaLink' ] ),
971
  'custom-field',
972
- 'modified'
973
  ),
974
  ),
975
 
976
  /**
977
  * Alerts: Comments
978
  */
979
- __( 'Comments', 'wp-security-audit-log' ) => array(
980
  array(
981
  2090,
982
  WSAL_INFORMATIONAL,
983
- __( 'User approved a comment', 'wp-security-audit-log' ),
984
- __( 'Approved the comment posted by %Author% on the post %PostTitle%.', 'wp-security-audit-log' ),
985
- [
986
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
987
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
988
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
989
- __( 'Comment ID', 'wp-security-audit-log' ) => '%CommentID%'
990
- ],
991
- wsaldefaults_build_links( [ 'CommentLink', 'PostUrlIfPublished' ] ),
992
  'comment',
993
- 'approved'
994
  ),
995
  array(
996
  2091,
997
  WSAL_INFORMATIONAL,
998
- __( 'User unapproved a comment', 'wp-security-audit-log' ),
999
- __( 'Unapproved the comment posted by %Author% on the post %PostTitle%.', 'wp-security-audit-log' ),
1000
- [
1001
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
1002
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
1003
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
1004
- __( 'Comment ID', 'wp-security-audit-log' ) => '%CommentID%'
1005
- ],
1006
- wsaldefaults_build_links( [ 'CommentLink', 'PostUrlIfPublished' ] ),
1007
  'comment',
1008
- 'unapproved'
1009
  ),
1010
  array(
1011
  2092,
1012
  WSAL_INFORMATIONAL,
1013
- __( 'User replied to a comment', 'wp-security-audit-log' ),
1014
- __( 'Replied to the comment posted by %Author% on the post %PostTitle%.', 'wp-security-audit-log' ),
1015
- [
1016
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
1017
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
1018
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
1019
- __( 'Comment ID', 'wp-security-audit-log' ) => '%CommentID%'
1020
- ],
1021
- wsaldefaults_build_links( [ 'CommentLink', 'PostUrlIfPublished' ] ),
1022
  'comment',
1023
- 'created'
1024
  ),
1025
  array(
1026
  2093,
1027
  WSAL_LOW,
1028
- __( 'User edited a comment', 'wp-security-audit-log' ),
1029
- __( 'Edited the comment posted by %Author% on the post %PostTitle%.', 'wp-security-audit-log' ),
1030
- [
1031
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
1032
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
1033
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
1034
- __( 'Comment ID', 'wp-security-audit-log' ) => '%CommentID%'
1035
- ],
1036
- wsaldefaults_build_links( [ 'CommentLink', 'PostUrlIfPublished' ] ),
1037
  'comment',
1038
- 'modified'
1039
  ),
1040
  array(
1041
  2094,
1042
  WSAL_INFORMATIONAL,
1043
- __( 'User marked a comment as Spam', 'wp-security-audit-log' ),
1044
- __( 'Marked the comment posted by %Author% on the post %PostTitle% as spam.', 'wp-security-audit-log' ),
1045
- [
1046
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
1047
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
1048
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
1049
- __( 'Comment ID', 'wp-security-audit-log' ) => '%CommentID%'
1050
- ],
1051
- wsaldefaults_build_links( [ 'CommentLink', 'PostUrlIfPublished' ] ),
1052
  'comment',
1053
- 'unapproved'
1054
  ),
1055
  array(
1056
  2095,
1057
  WSAL_LOW,
1058
- __( 'User marked a comment as Not Spam', 'wp-security-audit-log' ),
1059
- __( 'Marked the comment posted by %Author% on the post %PostTitle% as not spam.', 'wp-security-audit-log' ),
1060
- [
1061
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
1062
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
1063
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
1064
- __( 'Comment ID', 'wp-security-audit-log' ) => '%CommentID%'
1065
- ],
1066
- wsaldefaults_build_links( [ 'CommentLink', 'PostUrlIfPublished' ] ),
1067
  'comment',
1068
- 'approved'
1069
  ),
1070
  array(
1071
  2096,
1072
  WSAL_LOW,
1073
- __( 'User moved a comment to trash', 'wp-security-audit-log' ),
1074
- __( 'Moved the comment posted by %Author% on the post %PostTitle% to trash.', 'wp-security-audit-log' ),
1075
- [
1076
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
1077
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
1078
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
1079
- __( 'Comment ID', 'wp-security-audit-log' ) => '%CommentID%'
1080
- ],
1081
- wsaldefaults_build_links( [ 'CommentLink', 'PostUrlIfPublished' ] ),
1082
  'comment',
1083
- 'deleted'
1084
  ),
1085
  array(
1086
  2097,
1087
  WSAL_INFORMATIONAL,
1088
- __( 'User restored a comment from the trash', 'wp-security-audit-log' ),
1089
- __( 'Restored the comment posted by %Author% on the post %PostTitle% from trash.', 'wp-security-audit-log' ),
1090
- [
1091
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
1092
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
1093
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
1094
- __( 'Comment ID', 'wp-security-audit-log' ) => '%CommentID%'
1095
- ],
1096
- wsaldefaults_build_links( [ 'CommentLink', 'PostUrlIfPublished' ] ),
1097
  'comment',
1098
- 'restored'
1099
  ),
1100
  array(
1101
  2098,
1102
  WSAL_LOW,
1103
- __( 'User permanently deleted a comment', 'wp-security-audit-log' ),
1104
- __( 'Permanently deleted the comment posted by %Author% on the post %PostTitle%.', 'wp-security-audit-log' ),
1105
- [
1106
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
1107
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
1108
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
1109
- __( 'Comment ID', 'wp-security-audit-log' ) => '%CommentID%'
1110
- ],
1111
- wsaldefaults_build_links( [ 'PostUrlIfPublished' ] ),
1112
  'comment',
1113
- 'deleted'
1114
  ),
1115
  array(
1116
  2099,
1117
  WSAL_INFORMATIONAL,
1118
- __( 'User posted a comment', 'wp-security-audit-log' ),
1119
- __( 'Posted a comment on the post %PostTitle%.', 'wp-security-audit-log' ),
1120
- [
1121
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
1122
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
1123
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
1124
- __( 'Comment ID', 'wp-security-audit-log' ) => '%CommentID%'
1125
- ],
1126
- wsaldefaults_build_links( [ 'CommentLink', 'PostUrlIfPublished' ] ),
1127
  'comment',
1128
- 'created'
1129
  ),
1130
  /**
1131
  * IMPORTANT: This alert is deprecated but should not be
@@ -1134,181 +1135,181 @@ function wsaldefaults_wsal_init() {
1134
  array(
1135
  2126,
1136
  WSAL_INFORMATIONAL,
1137
- __( 'Visitor posted a comment', 'wp-security-audit-log' ),
1138
- __( 'Posted a comment on the post %PostTitle%.', 'wp-security-audit-log' ),
1139
- [
1140
- __( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
1141
- __( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
1142
- __( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
1143
- __( 'Comment ID', 'wp-security-audit-log' ) => '%CommentID%'
1144
- ],
1145
- wsaldefaults_build_links( [ 'CommentLink', 'PostUrlIfPublished' ] ),
1146
  'comment',
1147
- 'created'
1148
  ),
1149
  ),
1150
 
1151
  /**
1152
  * Alerts: Widgets
1153
  */
1154
- __( 'Widgets', 'wp-security-audit-log' ) => array(
1155
  array(
1156
  2042,
1157
  WSAL_MEDIUM,
1158
- __( 'User added a new widget', 'wp-security-audit-log' ),
1159
- __( 'Added a new %WidgetName% widget in %Sidebar%.', 'wp-security-audit-log' ),
1160
- [],
1161
- [],
1162
  'widget',
1163
- 'added'
1164
  ),
1165
  array(
1166
  2043,
1167
  WSAL_HIGH,
1168
- __( 'User modified a widget', 'wp-security-audit-log' ),
1169
- __( 'Modified the %WidgetName% widget in %Sidebar%.', 'wp-security-audit-log' ),
1170
- [],
1171
- [],
1172
  'widget',
1173
- 'modified'
1174
  ),
1175
  array(
1176
  2044,
1177
  WSAL_MEDIUM,
1178
- __( 'User deleted widget', 'wp-security-audit-log' ),
1179
- __( 'Deleted the %WidgetName% widget from %Sidebar%.', 'wp-security-audit-log' ),
1180
- [],
1181
- [],
1182
  'widget',
1183
- 'deleted'
1184
  ),
1185
  array(
1186
  2045,
1187
  WSAL_LOW,
1188
- __( 'User moved widget', 'wp-security-audit-log' ),
1189
- __( 'Moved the %WidgetName% widget.', 'wp-security-audit-log' ),
1190
- [
1191
- __( 'From', 'wp-security-audit-log' ) => '%OldSidebar%',
1192
- __( 'To', 'wp-security-audit-log' ) => '%NewSidebar%'
1193
- ],
1194
- [],
1195
  'widget',
1196
- 'modified'
1197
  ),
1198
  array(
1199
  2071,
1200
  WSAL_LOW,
1201
- __( 'User changed widget position', 'wp-security-audit-log' ),
1202
- __( 'Changed the position of the %WidgetName% widget in %Sidebar%.', 'wp-security-audit-log' ),
1203
- [],
1204
- [],
1205
  'widget',
1206
- 'modified'
1207
  ),
1208
  ),
1209
 
1210
  /**
1211
  * Alerts: Menus
1212
  */
1213
- __( 'Menus', 'wp-security-audit-log' ) => array(
1214
  array(
1215
  2078,
1216
  WSAL_LOW,
1217
- __( 'User created new menu', 'wp-security-audit-log' ),
1218
- __( 'New menu called %MenuName%.', 'wp-security-audit-log' ),
1219
- [],
1220
- wsaldefaults_build_links( [ 'MenuUrl' ] ),
1221
  'menu',
1222
- 'created'
1223
  ),
1224
  array(
1225
  2079,
1226
  WSAL_LOW,
1227
- __( 'User added content to a menu', 'wp-security-audit-log' ),
1228
- __( 'Added the item %ContentName% to the menu %MenuName%.', 'wp-security-audit-log' ),
1229
- [
1230
- __( 'Item type', 'wp-security-audit-log' ) => '%ContentType%'
1231
- ],
1232
- wsaldefaults_build_links( [ 'MenuUrl' ] ),
1233
  'menu',
1234
- 'modified'
1235
  ),
1236
  array(
1237
  2080,
1238
  WSAL_LOW,
1239
- __( 'User removed content from a menu', 'wp-security-audit-log' ),
1240
- __( 'Removed the item %ContentName% from the menu %MenuName%.', 'wp-security-audit-log' ),
1241
- [
1242
- __( 'Item type', 'wp-security-audit-log' ) => '%ContentType%'
1243
- ],
1244
- wsaldefaults_build_links( [ 'MenuUrl' ] ),
1245
  'menu',
1246
- 'modified'
1247
  ),
1248
  array(
1249
  2081,
1250
  WSAL_MEDIUM,
1251
- __( 'User deleted menu', 'wp-security-audit-log' ),
1252
- __( 'Deleted the menu %MenuName%.', 'wp-security-audit-log' ),
1253
- [],
1254
- [],
1255
  'menu',
1256
- 'deleted'
1257
  ),
1258
  array(
1259
  2082,
1260
  WSAL_LOW,
1261
- __( 'User changed menu setting', 'wp-security-audit-log' ),
1262
- __( 'The setting %MenuSetting% in the menu %MenuName%.', 'wp-security-audit-log' ),
1263
- [],
1264
- wsaldefaults_build_links( [ 'MenuUrl' ] ),
1265
  'menu',
1266
- 'enabled'
1267
  ),
1268
  array(
1269
  2083,
1270
  WSAL_LOW,
1271
- __( 'User modified content in a menu', 'wp-security-audit-log' ),
1272
- __( 'Modified the item %ContentName% in the menu %MenuName%.', 'wp-security-audit-log' ),
1273
- [
1274
- __( 'Item type', 'wp-security-audit-log' ) => '%ContentType%'
1275
- ],
1276
- wsaldefaults_build_links( [ 'MenuUrl' ] ),
1277
  'menu',
1278
- 'modified'
1279
  ),
1280
  array(
1281
  2084,
1282
  WSAL_LOW,
1283
- __( 'User changed name of a menu', 'wp-security-audit-log' ),
1284
- __( 'Renamed the menu %OldMenuName% to %MenuName%.', 'wp-security-audit-log' ),
1285
- [],
1286
- wsaldefaults_build_links( [ 'MenuUrl' ] ),
1287
  'menu',
1288
- 'renamed'
1289
  ),
1290
  array(
1291
  2085,
1292
  WSAL_LOW,
1293
- __( 'User changed order of the objects in a menu', 'wp-security-audit-log' ),
1294
- __( 'Changed the order of the items in the menu %MenuName%.', 'wp-security-audit-log' ),
1295
- [],
1296
- wsaldefaults_build_links( [ 'MenuUrl' ] ),
1297
  'menu',
1298
- 'modified'
1299
  ),
1300
  array(
1301
  2089,
1302
  WSAL_LOW,
1303
- __( 'User moved objects as a sub-item', 'wp-security-audit-log' ),
1304
- __( 'Moved items as sub-items in the menu %MenuName%.', 'wp-security-audit-log' ),
1305
- [
1306
- __( 'Moved item', 'wp-security-audit-log' ) => '%ItemName%',
1307
- __( 'as a sub-item of', 'wp-security-audit-log' ) => '%ParentName%'
1308
- ],
1309
- wsaldefaults_build_links( [ 'MenuUrl' ] ),
1310
  'menu',
1311
- 'modified'
1312
  ),
1313
  ),
1314
 
@@ -1320,180 +1321,180 @@ function wsaldefaults_wsal_init() {
1320
  *
1321
  * @deprecated 3.1.0
1322
  */
1323
- __( 'Custom Post Types', 'wp-security-audit-log' ) => array(
1324
  array(
1325
  2003,
1326
  E_NOTICE,
1327
- __( 'User modified a draft blog post', 'wp-security-audit-log' ),
1328
- __( 'Modified the draft post with the %PostTitle%. %EditorLinkPost%.', 'wp-security-audit-log' )
1329
  ),
1330
  array(
1331
  2029,
1332
  E_NOTICE,
1333
- __( 'User created a new post with custom post type and saved it as draft', 'wp-security-audit-log' ),
1334
- __( 'Created a new custom post called %PostTitle% of type %PostType%. %EditorLinkPost%.', 'wp-security-audit-log' )
1335
  ),
1336
  array(
1337
  2030,
1338
  E_NOTICE,
1339
- __( 'User published a post with custom post type', 'wp-security-audit-log' ),
1340
- __( 'Published a custom post %PostTitle% of type %PostType%. Post URL is %PostUrl%. %EditorLinkPost%.', 'wp-security-audit-log' )
1341
  ),
1342
  array(
1343
  2031,
1344
  E_NOTICE,
1345
- __( 'User modified a post with custom post type', 'wp-security-audit-log' ),
1346
- __( 'Modified the custom post %PostTitle% of type %PostType%. Post URL is %PostUrl%. %EditorLinkPost%.', 'wp-security-audit-log' )
1347
  ),
1348
  array(
1349
  2032,
1350
  E_NOTICE,
1351
- __( 'User modified a draft post with custom post type', 'wp-security-audit-log' ),
1352
- __( 'Modified the draft custom post %PostTitle% of type is %PostType%. %EditorLinkPost%.', 'wp-security-audit-log' )
1353
  ),
1354
  array(
1355
  2033,
1356
  E_WARNING,
1357
- __( 'User permanently deleted post with custom post type', 'wp-security-audit-log' ),
1358
- __( 'Permanently Deleted the custom post %PostTitle% of type %PostType%.', 'wp-security-audit-log' )
1359
  ),
1360
  array(
1361
  2034,
1362
  E_WARNING,
1363
- __( 'User moved post with custom post type to trash', 'wp-security-audit-log' ),
1364
- __( 'Moved the custom post %PostTitle% of type %PostType% to trash. Post URL was %PostUrl%.', 'wp-security-audit-log' )
1365
  ),
1366
  array(
1367
  2035,
1368
  E_CRITICAL,
1369
- __( 'User restored post with custom post type from trash', 'wp-security-audit-log' ),
1370
- __( 'The custom post %PostTitle% of type %PostType% has been restored from trash. %EditorLinkPost%.', 'wp-security-audit-log' )
1371
  ),
1372
  array(
1373
  2036,
1374
  E_NOTICE,
1375
- __( 'User changed the category of a post with custom post type', 'wp-security-audit-log' ),
1376
- __( 'Changed the category(ies) of the custom post %PostTitle% of type %PostType% from %OldCategories% to %NewCategories%. %EditorLinkPost%.', 'wp-security-audit-log' )
1377
  ),
1378
  array(
1379
  2037,
1380
  E_NOTICE,
1381
- __( 'User changed the URL of a post with custom post type', 'wp-security-audit-log' ),
1382
- __( 'Changed the URL of the custom post %PostTitle% of type %PostType% from %OldUrl% to %NewUrl%. %EditorLinkPost%.', 'wp-security-audit-log' )
1383
  ),
1384
  array(
1385
  2038,
1386
  E_NOTICE,
1387
- __( 'User changed the author or post with custom post type', 'wp-security-audit-log' ),
1388
- __( 'Changed the author of custom post %PostTitle% of type %PostType% from %OldAuthor% to %NewAuthor%. %EditorLinkPost%.', 'wp-security-audit-log' )
1389
  ),
1390
  array(
1391
  2039,
1392
  E_NOTICE,
1393
- __( 'User changed the status of post with custom post type', 'wp-security-audit-log' ),
1394
- __( 'Changed the status of custom post %PostTitle% of type %PostType% from %OldStatus% to %NewStatus%. %EditorLinkPost%.', 'wp-security-audit-log' )
1395
  ),
1396
  array(
1397
  2040,
1398
  E_WARNING,
1399
- __( 'User changed the visibility of a post with custom post type', 'wp-security-audit-log' ),
1400
- __( 'Changed the visibility of the custom post %PostTitle% of type %PostType% from %OldVisibility% to %NewVisibility%. %EditorLinkPost%.', 'wp-security-audit-log' )
1401
  ),
1402
  array(
1403
  2041,
1404
  E_NOTICE,
1405
- __( 'User changed the date of post with custom post type', 'wp-security-audit-log' ),
1406
- __( 'Changed the date of the custom post %PostTitle% of type %PostType% from %OldDate% to %NewDate%. %EditorLinkPost%.', 'wp-security-audit-log' )
1407
  ),
1408
  array(
1409
  2056,
1410
  E_CRITICAL,
1411
- __( 'User created a custom field for a custom post type', 'wp-security-audit-log' ),
1412
- __( 'Created a new custom field %MetaKey% with value %MetaValue% in custom post %PostTitle% of type %PostType%. %EditorLinkPost%.<br>%MetaLink%.', 'wp-security-audit-log' )
1413
  ),
1414
  array(
1415
  2057,
1416
  E_CRITICAL,
1417
- __( 'User updated a custom field for a custom post type', 'wp-security-audit-log' ),
1418
- __( 'Modified the value of the custom field %MetaKey% from %MetaValueOld% to %MetaValueNew% in custom post %PostTitle% of type %PostType% %EditorLinkPost%.<br>%MetaLink%.', 'wp-security-audit-log' )
1419
  ),
1420
  array(
1421
  2058,
1422
  E_CRITICAL,
1423
- __( 'User deleted a custom field from a custom post type', 'wp-security-audit-log' ),
1424
- __( 'Deleted the custom field %MetaKey% with id %MetaID% from custom post %PostTitle% of type %PostType% %EditorLinkPost%.<br>%MetaLink%.', 'wp-security-audit-log' )
1425
  ),
1426
  array(
1427
  2063,
1428
  E_CRITICAL,
1429
- __( 'User updated a custom field name for a custom post type', 'wp-security-audit-log' ),
1430
- __( 'Changed the custom field name from %MetaKeyOld% to %MetaKeyNew% in custom post %PostTitle% of type %PostType% %EditorLinkPost%.<br>%MetaLink%.', 'wp-security-audit-log' )
1431
  ),
1432
  array(
1433
  2067,
1434
  E_WARNING,
1435
- __( 'User modified content for a published custom post type', 'wp-security-audit-log' ),
1436
- __( 'Modified the content of the published custom post type %PostTitle%. Post URL is %PostUrl%. %EditorLinkPost%.', 'wp-security-audit-log' )
1437
  ),
1438
  array(
1439
  2068,
1440
  E_NOTICE,
1441
- __( 'User modified content for a draft post', 'wp-security-audit-log' ),
1442
- __( 'Modified the content of the draft post %PostTitle%.%RevisionLink% %EditorLinkPost%.', 'wp-security-audit-log' )
1443
  ),
1444
  array(
1445
  2070,
1446
  E_NOTICE,
1447
- __( 'User modified content for a draft custom post type', 'wp-security-audit-log' ),
1448
- __( 'Modified the content of the draft custom post type %PostTitle%.%EditorLinkPost%.', 'wp-security-audit-log' )
1449
  ),
1450
  array(
1451
  2072,
1452
  E_NOTICE,
1453
- __( 'User modified content of a post', 'wp-security-audit-log' ),
1454
- __( 'Modified the content of post %PostTitle% which is submitted for review.%RevisionLink% %EditorLinkPost%.', 'wp-security-audit-log' )
1455
  ),
1456
  array(
1457
  2076,
1458
  E_NOTICE,
1459
- __( 'User scheduled a custom post type', 'wp-security-audit-log' ),
1460
- __( 'Scheduled the custom post type %PostTitle% to be published %PublishingDate%. %EditorLinkPost%.', 'wp-security-audit-log' )
1461
  ),
1462
  array(
1463
  2088,
1464
  E_NOTICE,
1465
- __( 'User changed title of a custom post type', 'wp-security-audit-log' ),
1466
- __( 'Changed the title of the custom post %OldTitle% to %NewTitle%. %EditorLinkPost%.', 'wp-security-audit-log' )
1467
  ),
1468
  array(
1469
  2104,
1470
  E_NOTICE,
1471
- __( 'User opened a custom post type in the editor', 'wp-security-audit-log' ),
1472
- __( 'Opened the custom post %PostTitle% of type %PostType% in the editor. View the post: %EditorLinkPost%.', 'wp-security-audit-log' )
1473
  ),
1474
  array(
1475
  2105,
1476
  E_NOTICE,
1477
- __( 'User viewed a custom post type', 'wp-security-audit-log' ),
1478
- __( 'Viewed the custom post %PostTitle% of type %PostType%. View the post: %PostUrl%.', 'wp-security-audit-log' )
1479
  ),
1480
  array(
1481
  5021,
1482
  E_CRITICAL,
1483
- __( 'A plugin created a custom post', 'wp-security-audit-log' ),
1484
- __( 'A plugin automatically created the following custom post: %PostTitle%.', 'wp-security-audit-log' )
1485
  ),
1486
  array(
1487
  5027,
1488
  E_CRITICAL,
1489
- __( 'A plugin deleted a custom post', 'wp-security-audit-log' ),
1490
- __( 'A plugin automatically deleted the following custom post: %PostTitle%.', 'wp-security-audit-log' )
1491
  ),
1492
  array(
1493
  2108,
1494
  E_NOTICE,
1495
- __( 'A plugin modified a custom post', 'wp-security-audit-log' ),
1496
- __( 'Plugin modified the custom post %PostTitle%. View the post: %EditorLinkPost%.', 'wp-security-audit-log' )
1497
  ),
1498
  ),
1499
 
@@ -1505,883 +1506,883 @@ function wsaldefaults_wsal_init() {
1505
  *
1506
  * @deprecated 3.1.0
1507
  */
1508
- __( 'Pages', 'wp-security-audit-log' ) => array(
1509
  array(
1510
  2004,
1511
  E_NOTICE,
1512
- __( 'User created a new WordPress page and saved it as draft', 'wp-security-audit-log' ),
1513
- __( 'Created a new page called %PostTitle% and saved it as draft. %EditorLinkPage%.', 'wp-security-audit-log' )
1514
  ),
1515
  array(
1516
  2005,
1517
  E_NOTICE,
1518
- __( 'User published a WordPress page', 'wp-security-audit-log' ),
1519
- __( 'Published a page called %PostTitle%. Page URL is %PostUrl%. %EditorLinkPage%.', 'wp-security-audit-log' )
1520
  ),
1521
  array(
1522
  2006,
1523
  E_NOTICE,
1524
- __( 'User modified a published WordPress page', 'wp-security-audit-log' ),
1525
- __( 'Modified the published page %PostTitle%. Page URL is %PostUrl%. %EditorLinkPage%.', 'wp-security-audit-log' )
1526
  ),
1527
  array(
1528
  2007,
1529
  E_NOTICE,
1530
- __( 'User modified a draft WordPress page', 'wp-security-audit-log' ),
1531
- __( 'Modified the draft page %PostTitle%. Page ID is %PostID%. %EditorLinkPage%.', 'wp-security-audit-log' )
1532
  ),
1533
  array(
1534
  2009,
1535
  E_WARNING,
1536
- __( 'User permanently deleted a page from the trash', 'wp-security-audit-log' ),
1537
- __( 'Permanently deleted the page %PostTitle%.', 'wp-security-audit-log' )
1538
  ),
1539
  array(
1540
  2013,
1541
  E_WARNING,
1542
- __( 'User moved WordPress page to the trash', 'wp-security-audit-log' ),
1543
- __( 'Moved the page %PostTitle% to trash. Page URL was %PostUrl%.', 'wp-security-audit-log' )
1544
  ),
1545
  array(
1546
  2015,
1547
  E_CRITICAL,
1548
- __( 'User restored a WordPress page from trash', 'wp-security-audit-log' ),
1549
- __( 'Page %PostTitle% has been restored from trash. %EditorLinkPage%.', 'wp-security-audit-log' )
1550
  ),
1551
  array(
1552
  2018,
1553
  E_NOTICE,
1554
- __( 'User changed page URL', 'wp-security-audit-log' ),
1555
- __( 'Changed the URL of the page %PostTitle% from %OldUrl% to %NewUrl%. %EditorLinkPage%.', 'wp-security-audit-log' )
1556
  ),
1557
  array(
1558
  2020,
1559
  E_NOTICE,
1560
- __( 'User changed page author', 'wp-security-audit-log' ),
1561
- __( 'Changed the author of the page %PostTitle% from %OldAuthor% to %NewAuthor%. %EditorLinkPage%.', 'wp-security-audit-log' )
1562
  ),
1563
  array(
1564
  2022,
1565
  E_NOTICE,
1566
- __( 'User changed page status', 'wp-security-audit-log' ),
1567
- __( 'Changed the status of the page %PostTitle% from %OldStatus% to %NewStatus%. %EditorLinkPage%.', 'wp-security-audit-log' )
1568
  ),
1569
  array(
1570
  2026,
1571
  E_WARNING,
1572
- __( 'User changed the visibility of a page post', 'wp-security-audit-log' ),
1573
- __( 'Changed the visibility of the page %PostTitle% from %OldVisibility% to %NewVisibility%. %EditorLinkPage%.', 'wp-security-audit-log' )
1574
  ),
1575
  array(
1576
  2028,
1577
  E_NOTICE,
1578
- __( 'User changed the date of a page post', 'wp-security-audit-log' ),
1579
- __( 'Changed the date of the page %PostTitle% from %OldDate% to %NewDate%. %EditorLinkPage%.', 'wp-security-audit-log' )
1580
  ),
1581
  array(
1582
  2059,
1583
  E_CRITICAL,
1584
- __( 'User created a custom field for a page', 'wp-security-audit-log' ),
1585
- __( 'Created a new custom field called %MetaKey% with value %MetaValue% in the page %PostTitle% %EditorLinkPage%.<br>%MetaLink%.', 'wp-security-audit-log' )
1586
  ),
1587
  array(
1588
  2060,
1589
  E_CRITICAL,
1590
- __( 'User updated a custom field value for a page', 'wp-security-audit-log' ),
1591
- __( 'Modified the value of the custom field %MetaKey% from %MetaValueOld% to %MetaValueNew% in the page %PostTitle% %EditorLinkPage%.<br>%MetaLink%.', 'wp-security-audit-log' )
1592
  ),
1593
  array(
1594
  2061,
1595
  E_CRITICAL,
1596
- __( 'User deleted a custom field from a page', 'wp-security-audit-log' ),
1597
- __( 'Deleted the custom field %MetaKey% with id %MetaID% from page %PostTitle% %EditorLinkPage%<br>%MetaLink%.', 'wp-security-audit-log' )
1598
  ),
1599
  array(
1600
  2064,
1601
  E_CRITICAL,
1602
- __( 'User updated a custom field name for a page', 'wp-security-audit-log' ),
1603
- __( 'Changed the custom field name from %MetaKeyOld% to %MetaKeyNew% in the page %PostTitle% %EditorLinkPage%.<br>%MetaLink%.', 'wp-security-audit-log' )
1604
  ),
1605
  array(
1606
  2066,
1607
  E_WARNING,
1608
- __( 'User modified content for a published page', 'wp-security-audit-log' ),
1609
- __( 'Modified the content of the published page %PostTitle%. Page URL is %PostUrl%. %RevisionLink% %EditorLinkPage%.', 'wp-security-audit-log' )
1610
  ),
1611
  array(
1612
  2069,
1613
  E_NOTICE,
1614
- __( 'User modified content for a draft page', 'wp-security-audit-log' ),
1615
- __( 'Modified the content of draft page %PostTitle%.%RevisionLink% %EditorLinkPage%.', 'wp-security-audit-log' )
1616
  ),
1617
  array(
1618
  2075,
1619
  E_NOTICE,
1620
- __( 'User scheduled a page', 'wp-security-audit-log' ),
1621
- __( 'Scheduled the page %PostTitle% to be published %PublishingDate%. %EditorLinkPage%.', 'wp-security-audit-log' )
7
  * @package wsal
8
  */
9
 
10
+ // phpcs:disable WordPress.WP.I18n.MissingTranslatorsComment
11
+
12
  // Exit if accessed directly.
13
  if ( ! defined( 'ABSPATH' ) ) {
14
  exit;
31
  * @param WpSecurityAuditLog $wsal - Instance of main plugin.
32
  *
33
  * @since 3.5.1 - Added the `wsal_custom_alerts_dirs` filter.
 
34
  */
35
  function wsal_load_include_custom_files( $wsal ) {
36
  $paths = apply_filters( 'wsal_custom_alerts_dirs', array() );
43
  require_once $file;
44
  if ( ! empty( $custom_alerts ) && is_array( $custom_alerts ) ) {
45
  try {
46
+ $wsal->alerts->register_group( $custom_alerts );
47
  } catch ( Exception $ex ) {
48
  $wsal->wsal_log( $ex->getMessage() );
49
  }
54
  }
55
 
56
  /**
57
+ * Builds a configuration object of links suitable for the events definition.
58
  *
59
+ * @param string[] $link_aliases Link aliases.
60
  *
61
  * @return array
62
  */
63
+ function wsaldefaults_build_links( $link_aliases = array() ) {
64
+ $result = array();
65
 
66
  if ( ! empty( $link_aliases ) ) {
67
  foreach ( $link_aliases as $link_alias ) {
69
  case 'CategoryLink':
70
  case 'cat_link':
71
  case 'ProductCatLink':
72
+ $result[ esc_html__( 'View category', 'wp-security-audit-log' ) ] = '%' . $link_alias . '%';
73
  break;
74
 
75
  case 'ContactSupport':
76
+ $result[ esc_html__( 'Contact Support', 'wp-security-audit-log' ) ] = 'https://wpactivitylog.com/contact/';
77
  break;
78
 
79
  case 'CommentLink':
80
+ $result[ esc_html__( 'Comment', 'wp-security-audit-log' ) ] = array(
81
+ // Before 4.2.1 the CommentLink meta would contain the full HTML markup for the link, now it
82
+ // contains only the URL.
83
  'url' => '%CommentLink%',
84
+ 'label' => '%CommentDate%',
85
+ );
86
  break;
87
 
88
  case 'EditorLinkPage':
89
+ $result[ esc_html__( 'View page in the editor', 'wp-security-audit-log' ) ] = '%EditorLinkPage%';
90
  break;
91
 
92
  case 'EditorLinkPost':
93
+ $result[ esc_html__( 'View the post in editor', 'wp-security-audit-log' ) ] = '%EditorLinkPost%';
94
  break;
95
 
96
  case 'EditorLinkOrder':
97
+ // @todo move to the WooCommerce extension
98
+ $result[ esc_html__( 'View the order', 'wp-security-audit-log' ) ] = '%EditorLinkOrder%';
99
  break;
100
 
101
  case 'EditUserLink':
102
+ $result[ esc_html__( 'User profile page', 'wp-security-audit-log' ) ] = '%EditUserLink%';
103
  break;
104
 
105
  case 'LinkFile':
106
+ $result[ esc_html__( 'Open the log file', 'wp-security-audit-log' ) ] = '%LinkFile%';
107
  break;
108
 
109
  case 'LogFileLink':
110
+ // We don't show the link anymore.
111
  break;
112
 
113
  case 'MenuUrl':
114
+ $result[ esc_html__( 'View menu', 'wp-security-audit-log' ) ] = '%MenuUrl%';
115
  break;
116
 
117
  case 'PostUrl':
118
+ $result[ esc_html__( 'URL', 'wp-security-audit-log' ) ] = '%PostUrl%';
119
  break;
120
 
121
  case 'AttachmentUrl':
122
+ $result[ esc_html__( 'View attachment page', 'wp-security-audit-log' ) ] = '%AttachmentUrl%';
123
  break;
124
 
125
  case 'PostUrlIfPlublished':
126
  case 'PostUrlIfPublished':
127
+ $result[ esc_html__( 'URL', 'wp-security-audit-log' ) ] = '%PostUrlIfPlublished%';
128
  break;
129
 
130
  case 'RevisionLink':
131
+ $result[ esc_html__( 'View the content changes', 'wp-security-audit-log' ) ] = '%RevisionLink%';
132
  break;
133
 
134
  case 'TagLink':
135
+ $result[ esc_html__( 'View tag', 'wp-security-audit-log' ) ] = '%RevisionLink%';
136
  break;
137
 
138
  case 'LogFileText':
146
  break;
147
 
148
  default:
149
+ // Unsupported link alias.
150
  }
151
  }
152
  }
160
  * Define default alerts for the plugin.
161
  */
162
  function wsaldefaults_wsal_init() {
163
+ $wsal = WpSecurityAuditLog::get_instance();
164
 
165
  if ( ! isset( $wsal->constants ) ) {
166
  $wsal->constants = new WSAL_ConstantManager();
174
  * severity is based on monolog log levels
175
  * @see https://github.com/Seldaek/monolog/blob/main/doc/01-usage.md#log-levels
176
  */
177
+ // ALERT (550): Action must be taken immediately.
178
+ $wsal->constants->add_constant( 'WSAL_CRITICAL', 500, esc_html__( 'Critical severity events.', 'wp-security-audit-log' ) );
179
+ // ERROR (400): Runtime errors that do not require immediate action but should typically be logged and monitored.
180
+ $wsal->constants->add_constant( 'WSAL_HIGH', 400, esc_html__( 'High severity events.', 'wp-security-audit-log' ) );
181
+ // WARNING (300): Exceptional occurrences that are not errors.
182
+ $wsal->constants->add_constant( 'WSAL_MEDIUM', 300, esc_html__( 'Medium severity events.', 'wp-security-audit-log' ) );
183
+ // NOTICE (250): Normal but significant events.
184
+ $wsal->constants->add_constant( 'WSAL_LOW', 250, esc_html__( 'Low severity events.', 'wp-security-audit-log' ) );
185
+ // INFO (200): Interesting events.
186
+ $wsal->constants->add_constant( 'WSAL_INFORMATIONAL', 200, esc_html__( 'Informational events.', 'wp-security-audit-log' ) );
187
 
188
  // Create list of default alerts.
189
+ $wsal->alerts->register_group(
190
  array(
191
+ esc_html__( 'Users Logins & Sessions Events', 'wp-security-audit-log' ) => array(
192
+ esc_html__( 'User Activity', 'wp-security-audit-log' ) => array(
193
  array(
194
  1000,
195
  WSAL_LOW,
196
+ esc_html__( 'User logged in', 'wp-security-audit-log' ),
197
+ esc_html__( 'User logged in.', 'wp-security-audit-log' ),
198
+ array(),
199
+ array(),
200
  'user',
201
+ 'login',
202
  ),
203
  array(
204
  1001,
205
  WSAL_LOW,
206
+ esc_html__( 'User logged out', 'wp-security-audit-log' ),
207
+ esc_html__( 'User logged out.', 'wp-security-audit-log' ),
208
+ array(),
209
+ array(),
210
  'user',
211
+ 'logout',
212
  ),
213
  array(
214
  1002,
215
  WSAL_MEDIUM,
216
+ esc_html__( 'Login failed', 'wp-security-audit-log' ),
217
+ esc_html__( '%Attempts% failed login(s).', 'wp-security-audit-log' ),
218
+ array(),
219
+ array(),
220
  'user',
221
+ 'failed-login',
222
  ),
223
  array(
224
  1003,
225
  WSAL_LOW,
226
+ esc_html__( 'Login failed / non existing user', 'wp-security-audit-log' ),
227
+ esc_html__( '%Attempts% failed login(s).', 'wp-security-audit-log' ),
228
+ array(),
229
+ wsaldefaults_build_links( array( 'LogFileText' ) ),
230
  'system',
231
+ 'failed-login',
232
  ),
233
  array(
234
  1004,
235
  WSAL_MEDIUM,
236
+ esc_html__( 'Login blocked', 'wp-security-audit-log' ),
237
+ esc_html__( 'Login blocked because other session(s) already exist for this user.', 'wp-security-audit-log' ),
238
+ array(
239
+ esc_html__( 'IP address', 'wp-security-audit-log' ) => '%ClientIP%',
240
+ ),
241
+ array(),
242
  'user',
243
+ 'blocked',
244
  ),
245
  array(
246
  1005,
247
  WSAL_LOW,
248
+ esc_html__( 'User logged in with existing session(s)', 'wp-security-audit-log' ),
249
+ esc_html__( 'User logged in however there are other session(s) already for this user.', 'wp-security-audit-log' ),
250
+ array(
251
+ esc_html__( 'IP address(es)', 'wp-security-audit-log' ) => '%IPAddress%',
252
+ ),
253
+ array(),
254
  'user',
255
+ 'login',
256
  ),
257
  array(
258
  1006,
259
  WSAL_MEDIUM,
260
+ esc_html__( 'User logged out all other sessions with the same username', 'wp-security-audit-log' ),
261
+ esc_html__( 'Logged out all other sessions with the same user.', 'wp-security-audit-log' ),
262
+ array(),
263
+ array(),
264
  'user',
265
+ 'logout',
266
  ),
267
  array(
268
  1007,
269
  WSAL_MEDIUM,
270
+ esc_html__( 'User session destroyed and logged out', 'wp-security-audit-log' ),
271
+ esc_html__( 'Terminated the session of the user %TargetUserName%.', 'wp-security-audit-log' ),
272
+ array(
273
+ esc_html__( 'Role', 'wp-security-audit-log' ) => '%TargetUserRole%',
274
+ esc_html__( 'Session ID', 'wp-security-audit-log' ) => '%TargetSessionID%',
275
+ ),
276
+ array(),
277
  'user',
278
+ 'logout',
279
  ),
280
  array(
281
  1008,
282
  WSAL_MEDIUM,
283
+ esc_html__( 'Switched to another user', 'wp-security-audit-log' ),
284
+ esc_html__( 'Switched the session to being logged in as %TargetUserName%.', 'wp-security-audit-log' ),
285
+ array(
286
+ esc_html__( 'Role', 'wp-security-audit-log' ) => '%TargetUserRole%',
287
+ ),
288
+ array(),
289
  'user',
290
+ 'login',
291
  ),
292
  array(
293
  1009,
294
  WSAL_LOW,
295
+ esc_html__( 'The plugin terminated an idle session for a user', 'wp-security-audit-log' ),
296
+ esc_html__( 'The plugin terminated an idle session for the user %username%.', 'wp-security-audit-log' ),
297
+ array(
298
+ esc_html__( 'Role', 'wp-security-audit-log' ) => '%TargetUserRole%',
299
+ esc_html__( 'Session ID', 'wp-security-audit-log' ) => '%SessionID%',
300
+ ),
301
+ array(),
302
  'user',
303
+ 'logout',
304
  ),
305
  array(
306
  2010,
307
  WSAL_MEDIUM,
308
+ esc_html__( 'User uploaded file to the Uploads directory', 'wp-security-audit-log' ),
309
+ esc_html__( 'Uploaded a file called %FileName%.', 'wp-security-audit-log' ),
310
+ array(
311
+ esc_html__( 'Directory', 'wp-security-audit-log' ) => '%FilePath%',
312
+ ),
313
+ wsaldefaults_build_links( array( 'AttachmentUrl' ) ),
314
  'file',
315
+ 'uploaded',
316
  ),
317
  array(
318
  2011,
319
  WSAL_LOW,
320
+ esc_html__( 'User deleted file from Uploads directory', 'wp-security-audit-log' ),
321
+ esc_html__( 'Deleted the file %FileName%.', 'wp-security-audit-log' ),
322
+ array(
323
+ esc_html__( 'Directory', 'wp-security-audit-log' ) => '%FilePath%',
324
+ ),
325
+ array(),
326
  'file',
327
+ 'deleted',
328
  ),
329
  array(
330
  1010,
331
  WSAL_INFORMATIONAL,
332
+ esc_html__( 'User requested a password reset', 'wp-security-audit-log' ),
333
+ esc_html__( 'User requested a password reset. This does not mean that the password was changed.', 'wp-security-audit-log' ),
334
+ array(),
335
+ array(),
336
  'user',
337
+ 'submitted',
338
  ),
339
  ),
340
  ),
341
 
342
+ esc_html__( 'Content & Comments', 'wp-security-audit-log' ) => array(
343
+ esc_html__( 'Content', 'wp-security-audit-log' ) => array(
344
  array(
345
  2000,
346
  WSAL_INFORMATIONAL,
347
+ esc_html__( 'User created a new post and saved it as draft', 'wp-security-audit-log' ),
348
+ esc_html__( 'Created the post %PostTitle%.', 'wp-security-audit-log' ),
349
+ array(
350
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
351
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
352
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
353
+ ),
354
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
355
  'post',
356
+ 'created',
357
  ),
358
  array(
359
  2001,
360
  WSAL_LOW,
361
+ esc_html__( 'User published a post', 'wp-security-audit-log' ),
362
+ esc_html__( 'Published the post %PostTitle%.', 'wp-security-audit-log' ),
363
+ array(
364
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
365
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
366
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
367
+ ),
368
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
369
  'post',
370
+ 'published',
371
  ),
372
  array(
373
  2002,
374
  WSAL_LOW,
375
+ esc_html__( 'User modified a post', 'wp-security-audit-log' ),
376
+ esc_html__( 'Modified the post %PostTitle%.', 'wp-security-audit-log' ),
377
+ array(
378
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
379
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
380
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
381
+ ),
382
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
383
  'post',
384
+ 'modified',
385
  ),
386
  array(
387
  2008,
388
  WSAL_MEDIUM,
389
+ esc_html__( 'User permanently deleted a post from the trash', 'wp-security-audit-log' ),
390
+ esc_html__( 'Permanently deleted the post %PostTitle%.', 'wp-security-audit-log' ),
391
+ array(
392
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
393
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
394
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
395
+ ),
396
+ array(),
397
  'post',
398
+ 'deleted',
399
  ),
400
  array(
401
  2012,
402
  WSAL_MEDIUM,
403
+ esc_html__( 'User moved a post to the trash', 'wp-security-audit-log' ),
404
+ esc_html__( 'Moved the post %PostTitle% to trash.', 'wp-security-audit-log' ),
405
+ array(
406
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
407
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
408
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
409
+ ),
410
+ wsaldefaults_build_links( array( 'PostUrlIfPublished' ) ),
411
  'post',
412
+ 'deleted',
413
  ),
414
  array(
415
  2014,
416
  WSAL_LOW,
417
+ esc_html__( 'User restored a post from trash', 'wp-security-audit-log' ),
418
+ esc_html__( 'Restored the post %PostTitle% from trash.', 'wp-security-audit-log' ),
419
+ array(
420
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
421
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
422
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
423
+ ),
424
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
425
  'post',
426
+ 'restored',
427
  ),
428
  array(
429
  2017,
430
  WSAL_INFORMATIONAL,
431
+ esc_html__( 'User changed post URL', 'wp-security-audit-log' ),
432
+ esc_html__( 'Changed the URL of the post %PostTitle%.', 'wp-security-audit-log' ),
433
+ array(
434
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
435
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
436
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
437
+ esc_html__( 'Previous URL', 'wp-security-audit-log' ) => '%OldUrl%',
438
+ esc_html__( 'New URL', 'wp-security-audit-log' ) => '%NewUrl%',
439
+ ),
440
+ wsaldefaults_build_links( array( 'EditorLinkPost' ) ),
441
  'post',
442
+ 'modified',
443
  ),
444
  array(
445
  2019,
446
  WSAL_INFORMATIONAL,
447
+ esc_html__( 'User changed post author', 'wp-security-audit-log' ),
448
+ esc_html__( 'Changed the author of the post %PostTitle% to %NewAuthor%.', 'wp-security-audit-log' ),
449
+ array(
450
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
451
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
452
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
453
+ esc_html__( 'Previous author', 'wp-security-audit-log' ) => '%OldAuthor%',
454
+ ),
455
+ wsaldefaults_build_links( array( 'PostUrlIfPublished' ) ),
456
  'post',
457
+ 'modified',
458
  ),
459
  array(
460
  2021,
461
  WSAL_MEDIUM,
462
+ esc_html__( 'User changed post status', 'wp-security-audit-log' ),
463
+ esc_html__( 'Changed the status of the post %PostTitle% to %NewStatus%.', 'wp-security-audit-log' ),
464
+ array(
465
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
466
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
467
+ esc_html__( 'Previous status', 'wp-security-audit-log' ) => '%OldStatus%',
468
+ ),
469
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
470
  'post',
471
+ 'modified',
472
  ),
473
  array(
474
  2025,
475
  WSAL_LOW,
476
+ esc_html__( 'User changed the visibility of a post', 'wp-security-audit-log' ),
477
+ esc_html__( 'Changed the visibility of the post %PostTitle% to %NewVisibility%.', 'wp-security-audit-log' ),
478
+ array(
479
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
480
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
481
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
482
+ esc_html__( 'Previous visibility status', 'wp-security-audit-log' ) => '%OldVisibility%',
483
+ ),
484
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
485
  'post',
486
+ 'modified',
487
  ),
488
  array(
489
  2027,
490
  WSAL_INFORMATIONAL,
491
+ esc_html__( 'User changed the date of a post', 'wp-security-audit-log' ),
492
+ esc_html__( 'Changed the date of the post %PostTitle% to %NewDate%.', 'wp-security-audit-log' ),
493
+ array(
494
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
495
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
496
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
497
+ esc_html__( 'Previous date', 'wp-security-audit-log' ) => '%OldDate%',
498
+ ),
499
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
500
  'post',
501
+ 'modified',
502
  ),
503
  array(
504
  2047,
505
  WSAL_LOW,
506
+ esc_html__( 'User changed the parent of a page', 'wp-security-audit-log' ),
507
+ esc_html__( 'Changed the parent of the post %PostTitle% to %NewParentName%.', 'wp-security-audit-log' ),
508
+ array(
509
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
510
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
511
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
512
+ esc_html__( 'Previous parent', 'wp-security-audit-log' ) => '%OldParentName%',
513
+ ),
514
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
515
  'post',
516
+ 'modified',
517
  ),
518
  array(
519
  2048,
520
  WSAL_LOW,
521
+ esc_html__( 'User changed the template of a page', 'wp-security-audit-log' ),
522
+ esc_html__( 'Changed the template of the post %PostTitle% to %NewTemplate%.', 'wp-security-audit-log' ),
523
+ array(
524
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
525
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
526
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
527
+ esc_html__( 'Previous template', 'wp-security-audit-log' ) => '%OldTemplate%',
528
+ ),
529
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
530
  'post',
531
+ 'modified',
532
  ),
533
  array(
534
  2049,
535
  WSAL_INFORMATIONAL,
536
+ esc_html__( 'User set a post as sticky', 'wp-security-audit-log' ),
537
+ esc_html__( 'Set the post %PostTitle% as sticky.', 'wp-security-audit-log' ),
538
+ array(
539
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
540
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
541
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
542
+ ),
543
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
544
  'post',
545
+ 'modified',
546
  ),
547
  array(
548
  2050,
549
  WSAL_INFORMATIONAL,
550
+ esc_html__( 'User removed post from sticky', 'wp-security-audit-log' ),
551
+ esc_html__( 'Removed the post %PostTitle% from sticky.', 'wp-security-audit-log' ),
552
+ array(
553
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
554
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
555
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
556
+ ),
557
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
558
  'post',
559
+ 'modified',
560
  ),
561
  array(
562
  2065,
563
  WSAL_LOW,
564
+ esc_html__( 'User modified the content of a post', 'wp-security-audit-log' ),
565
+ esc_html__( 'Modified the content of the post %PostTitle%.', 'wp-security-audit-log' ),
566
+ array(
567
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
568
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
569
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
570
+ ),
571
+ wsaldefaults_build_links( array( 'RevisionLink', 'EditorLinkPost', 'PostUrlIfPublished' ) ),
572
  'post',
573
+ 'modified',
574
  ),
575
  array(
576
  2073,
577
  WSAL_INFORMATIONAL,
578
+ esc_html__( 'User submitted a post for review', 'wp-security-audit-log' ),
579
+ esc_html__( 'Submitted the post %PostTitle% for review.', 'wp-security-audit-log' ),
580
+ array(
581
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
582
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
583
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
584
+ ),
585
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
586
  'post',
587
+ 'modified',
588
  ),
589
  array(
590
  2074,
591
  WSAL_LOW,
592
+ esc_html__( 'User scheduled a post', 'wp-security-audit-log' ),
593
+ esc_html__( 'Scheduled the post %PostTitle% to be published on %PublishingDate%.', 'wp-security-audit-log' ),
594
+ array(
595
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
596
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
597
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
598
+ ),
599
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
600
  'post',
601
+ 'modified',
602
  ),
603
  array(
604
  2086,
605
  WSAL_INFORMATIONAL,
606
+ esc_html__( 'User changed title of a post', 'wp-security-audit-log' ),
607
+ esc_html__( 'Changed the title of the post %OldTitle% to %NewTitle%.', 'wp-security-audit-log' ),
608
+ array(
609
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
610
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
611
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
612
+ ),
613
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
614
  'post',
615
+ 'modified',
616
  ),
617
  array(
618
  2100,
619
  WSAL_INFORMATIONAL,
620
+ esc_html__( 'User opened a post in the editor', 'wp-security-audit-log' ),
621
+ esc_html__( 'Opened the post %PostTitle% in the editor.', 'wp-security-audit-log' ),
622
+ array(
623
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
624
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
625
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
626
+ ),
627
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
628
  'post',
629
+ 'opened',
630
  ),
631
  array(
632
  2101,
633
  WSAL_INFORMATIONAL,
634
+ esc_html__( 'User viewed a post', 'wp-security-audit-log' ),
635
+ esc_html__( 'Viewed the post %PostTitle%.', 'wp-security-audit-log' ),
636
+ array(
637
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
638
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
639
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
640
+ ),
641
+ wsaldefaults_build_links( array( 'PostUrl', 'EditorLinkPost' ) ),
642
  'post',
643
+ 'viewed',
644
  ),
645
  array(
646
  2111,
647
  WSAL_LOW,
648
+ esc_html__( 'User enabled/disabled comments in a post', 'wp-security-audit-log' ),
649
+ esc_html__( 'Comments in the post %PostTitle%.', 'wp-security-audit-log' ),
650
+ array(
651
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
652
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
653
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
654
+ ),
655
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
656
  'post',
657
+ 'enabled',
658
  ),
659
  array(
660
  2112,
661
  WSAL_LOW,
662
+ esc_html__( 'User enabled/disabled trackbacks and pingbacks in a post', 'wp-security-audit-log' ),
663
+ esc_html__( 'Pingbacks and Trackbacks in the post %PostTitle%.', 'wp-security-audit-log' ),
664
+ array(
665
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
666
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
667
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
668
+ ),
669
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
670
  'post',
671
+ 'enabled',
672
  ),
673
  array(
674
  2129,
675
  WSAL_INFORMATIONAL,
676
+ esc_html__( 'User updated the excerpt in a post', 'wp-security-audit-log' ),
677
+ esc_html__( 'The excerpt of the post %PostTitle%.', 'wp-security-audit-log' ),
678
+ array(
679
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
680
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
681
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
682
+ esc_html__( 'Previous excerpt entry', 'wp-security-audit-log' ) => '%old_post_excerpt%',
683
+ esc_html__( 'New excerpt entry', 'wp-security-audit-log' ) => '%post_excerpt%',
684
+ ),
685
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
686
  'post',
687
+ 'modified',
688
  ),
689
  array(
690
  2130,
691
  WSAL_INFORMATIONAL,
692
+ esc_html__( 'User updated the featured image in a post', 'wp-security-audit-log' ),
693
+ esc_html__( 'The featured image of the post %PostTitle%.', 'wp-security-audit-log' ),
694
+ array(
695
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
696
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
697
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
698
+ esc_html__( 'Previous image', 'wp-security-audit-log' ) => '%previous_image%',
699
+ esc_html__( 'New image', 'wp-security-audit-log' ) => '%new_image%',
700
+ ),
701
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
702
  'post',
703
+ 'modified',
704
  ),
705
  ),
706
 
707
+ esc_html__( 'Tags', 'wp-security-audit-log' ) => array(
708
  array(
709
  2119,
710
  WSAL_INFORMATIONAL,
711
+ esc_html__( 'User added post tag', 'wp-security-audit-log' ),
712
+ esc_html__( 'Added tag(s) to the post %PostTitle%.', 'wp-security-audit-log' ),
713
+ array(
714
+ esc_html__( 'ID', 'wp-security-audit-log' ) => '%PostID%',
715
+ esc_html__( 'Type', 'wp-security-audit-log' ) => '%PostType%',
716
+ esc_html__( 'Status', 'wp-security-audit-log' ) => '%PostStatus%',
717
+ esc_html__( 'Added tag(s)', 'wp-security-audit-log' ) => '%tag%',
718
+ ),
719
+ wsaldefaults_build_links( array( 'EditorLinkPost' ) ),
720
  'post',
721
+ 'modified',
722
  ),
723
  array(
724
  2120,
725
  WSAL_INFORMATIONAL,
726
+ esc_html__( 'User removed post tag', 'wp-security-audit-log' ),
727
+ esc_html__( 'Removed tag(s) from the post %PostTitle%.', 'wp-security-audit-log' ),
728
+ array(
729
+ esc_html__( 'ID', 'wp-security-audit-log' ) => '%PostID%',
730
+ esc_html__( 'Type', 'wp-security-audit-log' ) => '%PostType%',
731
+ esc_html__( 'Status', 'wp-security-audit-log' ) => '%PostStatus%',
732
+ esc_html__( 'Removed tag(s)', 'wp-security-audit-log' ) => '%tag%',
733
+ ),
734
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
735
  'post',
736
+ 'modified',
737
  ),
738
  array(
739
  2121,
740
  WSAL_INFORMATIONAL,
741
+ esc_html__( 'User created new tag', 'wp-security-audit-log' ),
742
+ esc_html__( 'Created the tag %TagName%.', 'wp-security-audit-log' ),
743
+ array(
744
+ esc_html__( 'Slug', 'wp-security-audit-log' ) => 'Slug',
745
+ ),
746
+ wsaldefaults_build_links( array( 'TagLink' ) ),
747
  'tag',
748
+ 'created',
749
  ),
750
  array(
751
  2122,
752
  WSAL_LOW,
753
+ esc_html__( 'User deleted tag', 'wp-security-audit-log' ),
754
+ esc_html__( 'Deleted the tag %TagName%.', 'wp-security-audit-log' ),
755
+ array(
756
+ esc_html__( 'Slug', 'wp-security-audit-log' ) => 'Slug',
757
+ ),
758
+ array(),
759
  'tag',
760
+ 'deleted',
761
  ),
762
  array(
763
  2123,
764
  WSAL_INFORMATIONAL,
765
+ esc_html__( 'Renamed the tag %old_name% to %new_name%.', 'wp-security-audit-log' ),
766
  '',
767
+ array(
768
+ esc_html__( 'Slug', 'wp-security-audit-log' ) => '%Slug%',
769
+ ),
770
+ wsaldefaults_build_links( array( 'TagLink' ) ),
771
  'tag',
772
+ 'renamed',
773
  ),
774
  array(
775
  2124,
776
  WSAL_INFORMATIONAL,
777
+ esc_html__( 'User changed tag slug', 'wp-security-audit-log' ),
778
+ esc_html__( 'Changed the slug of the tag %tag% to %new_slug%.', 'wp-security-audit-log' ),
779
+ array(
780
+ esc_html__( 'Previous slug', 'wp-security-audit-log' ) => '%old_slug%',
781
+ ),
782
+ wsaldefaults_build_links( array( 'TagLink' ) ),
783
  'tag',
784
+ 'modified',
785
  ),
786
  array(
787
  2125,
788
  WSAL_INFORMATIONAL,
789
+ esc_html__( 'User changed tag description', 'wp-security-audit-log' ),
790
+ esc_html__( 'Changed the description of the tag %tag%.', 'wp-security-audit-log' ),
791
+ array(
792
+ esc_html__( 'Slug', 'wp-security-audit-log' ) => '%Slug%',
793
+ esc_html__( 'Previous description', 'wp-security-audit-log' ) => '%old_desc%',
794
+ esc_html__( 'New description', 'wp-security-audit-log' ) => '%new_desc%',
795
+ ),
796
+ wsaldefaults_build_links( array( 'TagLink' ) ),
797
  'tag',
798
+ 'modified',
799
  ),
800
  ),
801
 
802
+ esc_html__( 'Categories', 'wp-security-audit-log' ) => array(
803
  array(
804
  2016,
805
  WSAL_LOW,
806
+ esc_html__( 'User changed post category', 'wp-security-audit-log' ),
807
+ esc_html__( 'Changed the category(ies) of the post %PostTitle% to %NewCategories%.', 'wp-security-audit-log' ),
808
+ array(
809
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
810
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
811
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
812
+ esc_html__( 'Previous category(ies)', 'wp-security-audit-log' ) => '%OldCategories%',
813
+ ),
814
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
815
  'post',
816
+ 'modified',
817
  ),
818
  array(
819
  2023,
820
  WSAL_MEDIUM,
821
+ esc_html__( 'User created new category', 'wp-security-audit-log' ),
822
+ esc_html__( 'Created the category %CategoryName%.', 'wp-security-audit-log' ),
823
+ array(
824
+ esc_html__( 'Slug', 'wp-security-audit-log' ) => 'Slug',
825
+ ),
826
+ wsaldefaults_build_links( array( 'CategoryLink' ) ),
827
  'category',
828
+ 'created',
829
  ),
830
  array(
831
  2024,
832
  WSAL_MEDIUM,
833
+ esc_html__( 'User deleted category', 'wp-security-audit-log' ),
834
+ esc_html__( 'Deleted the category %CategoryName%.', 'wp-security-audit-log' ),
835
+ array(
836
+ esc_html__( 'Slug', 'wp-security-audit-log' ) => 'Slug',
837
+ ),
838
+ array(),
839
  'category',
840
+ 'deleted',
841
  ),
842
  array(
843
  2052,
844
  WSAL_LOW,
845
+ esc_html__( 'Changed the parent of a category', 'wp-security-audit-log' ),
846
+ esc_html__( 'Changed the parent of the category %CategoryName% to %NewParent%.', 'wp-security-audit-log' ),
847
+ array(
848
+ esc_html__( 'Slug', 'wp-security-audit-log' ) => '%Slug%',
849
+ esc_html__( 'Previous parent', 'wp-security-audit-log' ) => '%OldParent%',
850
+ ),
851
+ wsaldefaults_build_links( array( 'CategoryLink' ) ),
852
  'category',
853
+ 'modified',
854
  ),
855
  array(
856
  2127,
857
  WSAL_LOW,
858
+ esc_html__( 'User changed category name', 'wp-security-audit-log' ),
859
+ esc_html__( 'Renamed the category %old_name% to %new_name%.', 'wp-security-audit-log' ),
860
+ array(
861
+ esc_html__( 'Slug', 'wp-security-audit-log' ) => '%slug%',
862
+ ),
863
+ wsaldefaults_build_links( array( 'cat_link' ) ),
864
  'category',
865
+ 'renamed',
866
  ),
867
  array(
868
  2128,
869
  WSAL_LOW,
870
+ esc_html__( 'User changed category slug', 'wp-security-audit-log' ),
871
+ esc_html__( 'Changed the slug of the category %CategoryName% to %new_slug%.', 'wp-security-audit-log' ),
872
+ array(
873
+ esc_html__( 'Previous slug', 'wp-security-audit-log' ) => '%old_slug%',
874
+ ),
875
+ wsaldefaults_build_links( array( 'cat_link' ) ),
876
  'category',
877
+ 'modified',
878
  ),
879
  ),
880
 
881
+ esc_html__( 'Custom Fields', 'wp-security-audit-log' ) => array(
882
  array(
883
  2053,
884
  WSAL_LOW,
885
+ esc_html__( 'User created a custom field for a post', 'wp-security-audit-log' ),
886
+ esc_html__( 'Created the new custom field %MetaKey% in the post %PostTitle%.', 'wp-security-audit-log' ),
887
+ array(
888
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
889
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
890
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
891
+ esc_html__( 'Custom field value', 'wp-security-audit-log' ) => '%MetaValue%',
892
+ ),
893
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'MetaLink', 'PostUrlIfPublished' ) ),
894
  'post',
895
+ 'modified',
896
  ),
897
  array(
898
  2054,
899
  WSAL_LOW,
900
+ esc_html__( 'User updated a custom field value for a post', 'wp-security-audit-log' ),
901
+ esc_html__( 'Modified the value of the custom field %MetaKey% in the post %PostTitle%.', 'wp-security-audit-log' ),
902
+ array(
903
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
904
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
905
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
906
+ esc_html__( 'Previous custom field value', 'wp-security-audit-log' ) => '%MetaValueOld%',
907
+ esc_html__( 'New custom field value', 'wp-security-audit-log' ) => '%MetaValueNew%',
908
+ ),
909
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'MetaLink', 'PostUrlIfPublished' ) ),
910
  'custom-field',
911
+ 'modified',
912
  ),
913
  array(
914
  2055,
915
  WSAL_MEDIUM,
916
+ esc_html__( 'User deleted a custom field from a post', 'wp-security-audit-log' ),
917
+ esc_html__( 'Deleted the custom field %MetaKey% from the post %PostTitle%.', 'wp-security-audit-log' ),
918
+ array(
919
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
920
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
921
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
922
+ ),
923
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
924
  'custom-field',
925
+ 'deleted',
926
  ),
927
  array(
928
  2062,
929
  WSAL_LOW,
930
+ esc_html__( 'User updated a custom field name for a post', 'wp-security-audit-log' ),
931
+ esc_html__( 'Renamed the custom field %MetaKeyOld% on post %PostTitle% to %MetaKeNew%.', 'wp-security-audit-log' ),
932
+ array(
933
+ esc_html__( 'Post', 'wp-security-audit-log' ) => '%PostTitle%',
934
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
935
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
936
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
937
+ ),
938
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'PostUrlIfPublished' ) ),
939
  'custom-field',
940
+ 'renamed',
941
  ),
942
  ),
943
 
944
+ esc_html__( 'Custom Fields (ACF)', 'wp-security-audit-log' ) => array(
945
  array(
946
  2131,
947
  WSAL_LOW,
948
+ esc_html__( 'User added relationship to a custom field value for a post', 'wp-security-audit-log' ),
949
+ esc_html__( 'Added relationships to the custom field %MetaKey% in the post %PostTitle%.', 'wp-security-audit-log' ),
950
+ array(
951
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
952
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
953
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
954
+ esc_html__( 'New relationships', 'wp-security-audit-log' ) => '%Relationships%',
955
+ ),
956
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'MetaLink' ) ),
957
  'custom-field',
958
+ 'modified',
959
  ),
960
  array(
961
  2132,
962
  WSAL_LOW,
963
+ esc_html__( 'User removed relationship from a custom field value for a post', 'wp-security-audit-log' ),
964
+ esc_html__( 'Removed relationships from the custom field %MetaKey% in the post %PostTitle%.', 'wp-security-audit-log' ),
965
+ array(
966
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
967
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
968
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
969
+ esc_html__( 'Removed relationships', 'wp-security-audit-log' ) => '%Relationships%',
970
+ ),
971
+ wsaldefaults_build_links( array( 'EditorLinkPost', 'MetaLink' ) ),
972
  'custom-field',
973
+ 'modified',
974
  ),
975
  ),
976
 
977
  /**
978
  * Alerts: Comments
979
  */
980
+ esc_html__( 'Comments', 'wp-security-audit-log' ) => array(
981
  array(
982
  2090,
983
  WSAL_INFORMATIONAL,
984
+ esc_html__( 'User approved a comment', 'wp-security-audit-log' ),
985
+ esc_html__( 'Approved the comment posted by %Author% on the post %PostTitle%.', 'wp-security-audit-log' ),
986
+ array(
987
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
988
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
989
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
990
+ esc_html__( 'Comment ID', 'wp-security-audit-log' ) => '%CommentID%',
991
+ ),
992
+ wsaldefaults_build_links( array( 'CommentLink', 'PostUrlIfPublished' ) ),
993
  'comment',
994
+ 'approved',
995
  ),
996
  array(
997
  2091,
998
  WSAL_INFORMATIONAL,
999
+ esc_html__( 'User unapproved a comment', 'wp-security-audit-log' ),
1000
+ esc_html__( 'Unapproved the comment posted by %Author% on the post %PostTitle%.', 'wp-security-audit-log' ),
1001
+ array(
1002
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
1003
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
1004
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
1005
+ esc_html__( 'Comment ID', 'wp-security-audit-log' ) => '%CommentID%',
1006
+ ),
1007
+ wsaldefaults_build_links( array( 'CommentLink', 'PostUrlIfPublished' ) ),
1008
  'comment',
1009
+ 'unapproved',
1010
  ),
1011
  array(
1012
  2092,
1013
  WSAL_INFORMATIONAL,
1014
+ esc_html__( 'User replied to a comment', 'wp-security-audit-log' ),
1015
+ esc_html__( 'Replied to the comment posted by %Author% on the post %PostTitle%.', 'wp-security-audit-log' ),
1016
+ array(
1017
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
1018
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
1019
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
1020
+ esc_html__( 'Comment ID', 'wp-security-audit-log' ) => '%CommentID%',
1021
+ ),
1022
+ wsaldefaults_build_links( array( 'CommentLink', 'PostUrlIfPublished' ) ),
1023
  'comment',
1024
+ 'created',
1025
  ),
1026
  array(
1027
  2093,
1028
  WSAL_LOW,
1029
+ esc_html__( 'User edited a comment', 'wp-security-audit-log' ),
1030
+ esc_html__( 'Edited the comment posted by %Author% on the post %PostTitle%.', 'wp-security-audit-log' ),
1031
+ array(
1032
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
1033
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
1034
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
1035
+ esc_html__( 'Comment ID', 'wp-security-audit-log' ) => '%CommentID%',
1036
+ ),
1037
+ wsaldefaults_build_links( array( 'CommentLink', 'PostUrlIfPublished' ) ),
1038
  'comment',
1039
+ 'modified',
1040
  ),
1041
  array(
1042
  2094,
1043
  WSAL_INFORMATIONAL,
1044
+ esc_html__( 'User marked a comment as Spam', 'wp-security-audit-log' ),
1045
+ esc_html__( 'Marked the comment posted by %Author% on the post %PostTitle% as spam.', 'wp-security-audit-log' ),
1046
+ array(
1047
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
1048
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
1049
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
1050
+ esc_html__( 'Comment ID', 'wp-security-audit-log' ) => '%CommentID%',
1051
+ ),
1052
+ wsaldefaults_build_links( array( 'CommentLink', 'PostUrlIfPublished' ) ),
1053
  'comment',
1054
+ 'unapproved',
1055
  ),
1056
  array(
1057
  2095,
1058
  WSAL_LOW,
1059
+ esc_html__( 'User marked a comment as Not Spam', 'wp-security-audit-log' ),
1060
+ esc_html__( 'Marked the comment posted by %Author% on the post %PostTitle% as not spam.', 'wp-security-audit-log' ),
1061
+ array(
1062
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
1063
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
1064
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
1065
+ esc_html__( 'Comment ID', 'wp-security-audit-log' ) => '%CommentID%',
1066
+ ),
1067
+ wsaldefaults_build_links( array( 'CommentLink', 'PostUrlIfPublished' ) ),
1068
  'comment',
1069
+ 'approved',
1070
  ),
1071
  array(
1072
  2096,
1073
  WSAL_LOW,
1074
+ esc_html__( 'User moved a comment to trash', 'wp-security-audit-log' ),
1075
+ esc_html__( 'Moved the comment posted by %Author% on the post %PostTitle% to trash.', 'wp-security-audit-log' ),
1076
+ array(
1077
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
1078
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
1079
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
1080
+ esc_html__( 'Comment ID', 'wp-security-audit-log' ) => '%CommentID%',
1081
+ ),
1082
+ wsaldefaults_build_links( array( 'CommentLink', 'PostUrlIfPublished' ) ),
1083
  'comment',
1084
+ 'deleted',
1085
  ),
1086
  array(
1087
  2097,
1088
  WSAL_INFORMATIONAL,
1089
+ esc_html__( 'User restored a comment from the trash', 'wp-security-audit-log' ),
1090
+ esc_html__( 'Restored the comment posted by %Author% on the post %PostTitle% from trash.', 'wp-security-audit-log' ),
1091
+ array(
1092
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
1093
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
1094
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
1095
+ esc_html__( 'Comment ID', 'wp-security-audit-log' ) => '%CommentID%',
1096
+ ),
1097
+ wsaldefaults_build_links( array( 'CommentLink', 'PostUrlIfPublished' ) ),
1098
  'comment',
1099
+ 'restored',
1100
  ),
1101
  array(
1102
  2098,
1103
  WSAL_LOW,
1104
+ esc_html__( 'User permanently deleted a comment', 'wp-security-audit-log' ),
1105
+ esc_html__( 'Permanently deleted the comment posted by %Author% on the post %PostTitle%.', 'wp-security-audit-log' ),
1106
+ array(
1107
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
1108
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
1109
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
1110
+ esc_html__( 'Comment ID', 'wp-security-audit-log' ) => '%CommentID%',
1111
+ ),
1112
+ wsaldefaults_build_links( array( 'PostUrlIfPublished' ) ),
1113
  'comment',
1114
+ 'deleted',
1115
  ),
1116
  array(
1117
  2099,
1118
  WSAL_INFORMATIONAL,
1119
+ esc_html__( 'User posted a comment', 'wp-security-audit-log' ),
1120
+ esc_html__( 'Posted a comment on the post %PostTitle%.', 'wp-security-audit-log' ),
1121
+ array(
1122
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
1123
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
1124
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
1125
+ esc_html__( 'Comment ID', 'wp-security-audit-log' ) => '%CommentID%',
1126
+ ),
1127
+ wsaldefaults_build_links( array( 'CommentLink', 'PostUrlIfPublished' ) ),
1128
  'comment',
1129
+ 'created',
1130
  ),
1131
  /**
1132
  * IMPORTANT: This alert is deprecated but should not be
1135
  array(
1136
  2126,
1137
  WSAL_INFORMATIONAL,
1138
+ esc_html__( 'Visitor posted a comment', 'wp-security-audit-log' ),
1139
+ esc_html__( 'Posted a comment on the post %PostTitle%.', 'wp-security-audit-log' ),
1140
+ array(
1141
+ esc_html__( 'Post ID', 'wp-security-audit-log' ) => '%PostID%',
1142
+ esc_html__( 'Post type', 'wp-security-audit-log' ) => '%PostType%',
1143
+ esc_html__( 'Post status', 'wp-security-audit-log' ) => '%PostStatus%',
1144
+ esc_html__( 'Comment ID', 'wp-security-audit-log' ) => '%CommentID%',
1145
+ ),
1146
+ wsaldefaults_build_links( array( 'CommentLink', 'PostUrlIfPublished' ) ),
1147
  'comment',
1148
+ 'created',
1149
  ),
1150
  ),
1151
 
1152
  /**
1153
  * Alerts: Widgets
1154
  */
1155
+ esc_html__( 'Widgets', 'wp-security-audit-log' ) => array(
1156
  array(
1157
  2042,
1158
  WSAL_MEDIUM,
1159
+ esc_html__( 'User added a new widget', 'wp-security-audit-log' ),
1160
+ esc_html__( 'Added a new %WidgetName% widget in %Sidebar%.', 'wp-security-audit-log' ),
1161
+ array(),
1162
+ array(),
1163
  'widget',
1164
+ 'added',
1165
  ),
1166
  array(
1167
  2043,
1168
  WSAL_HIGH,
1169
+ esc_html__( 'User modified a widget', 'wp-security-audit-log' ),
1170
+ esc_html__( 'Modified the %WidgetName% widget in %Sidebar%.', 'wp-security-audit-log' ),
1171
+ array(),
1172
+ array(),
1173
  'widget',
1174
+ 'modified',
1175
  ),
1176
  array(
1177
  2044,
1178
  WSAL_MEDIUM,
1179
+ esc_html__( 'User deleted widget', 'wp-security-audit-log' ),
1180
+ esc_html__( 'Deleted the %WidgetName% widget from %Sidebar%.', 'wp-security-audit-log' ),
1181
+ array(),
1182
+ array(),
1183
  'widget',
1184
+ 'deleted',
1185
  ),
1186
  array(
1187
  2045,
1188
  WSAL_LOW,
1189
+ esc_html__( 'User moved widget', 'wp-security-audit-log' ),
1190
+ esc_html__( 'Moved the %WidgetName% widget.', 'wp-security-audit-log' ),
1191
+ array(
1192
+ esc_html__( 'From', 'wp-security-audit-log' ) => '%OldSidebar%',
1193
+ esc_html__( 'To', 'wp-security-audit-log' ) => '%NewSidebar%',
1194
+ ),
1195
+ array(),
1196
  'widget',
1197
+ 'modified',
1198
  ),
1199
  array(
1200
  2071,
1201
  WSAL_LOW,
1202
+ esc_html__( 'User changed widget position', 'wp-security-audit-log' ),
1203
+ esc_html__( 'Changed the position of the %WidgetName% widget in %Sidebar%.', 'wp-security-audit-log' ),
1204
+ array(),
1205
+ array(),
1206
  'widget',
1207
+ 'modified',
1208
  ),
1209
  ),
1210
 
1211
  /**
1212
  * Alerts: Menus
1213
  */
1214
+ esc_html__( 'Menus', 'wp-security-audit-log' ) => array(
1215
  array(
1216
  2078,
1217
  WSAL_LOW,
1218
+ esc_html__( 'User created new menu', 'wp-security-audit-log' ),
1219
+ esc_html__( 'New menu called %MenuName%.', 'wp-security-audit-log' ),
1220
+ array(),
1221
+ wsaldefaults_build_links( array( 'MenuUrl' ) ),
1222
  'menu',
1223
+ 'created',
1224
  ),
1225
  array(
1226
  2079,
1227
  WSAL_LOW,
1228
+ esc_html__( 'User added content to a menu', 'wp-security-audit-log' ),
1229
+ esc_html__( 'Added the item %ContentName% to the menu %MenuName%.', 'wp-security-audit-log' ),
1230
+ array(
1231
+ esc_html__( 'Item type', 'wp-security-audit-log' ) => '%ContentType%',
1232
+ ),
1233
+ wsaldefaults_build_links( array( 'MenuUrl' ) ),
1234
  'menu',
1235
+ 'modified',
1236
  ),
1237
  array(
1238
  2080,
1239
  WSAL_LOW,
1240
+ esc_html__( 'User removed content from a menu', 'wp-security-audit-log' ),
1241
+ esc_html__( 'Removed the item %ContentName% from the menu %MenuName%.', 'wp-security-audit-log' ),
1242
+ array(
1243
+ esc_html__( 'Item type', 'wp-security-audit-log' ) => '%ContentType%',
1244
+ ),
1245
+ wsaldefaults_build_links( array( 'MenuUrl' ) ),
1246
  'menu',
1247
+ 'modified',
1248
  ),
1249
  array(
1250
  2081,
1251
  WSAL_MEDIUM,
1252
+ esc_html__( 'User deleted menu', 'wp-security-audit-log' ),
1253
+ esc_html__( 'Deleted the menu %MenuName%.', 'wp-security-audit-log' ),
1254
+ array(),
1255
+ array(),
1256
  'menu',
1257
+ 'deleted',
1258
  ),
1259
  array(
1260
  2082,
1261
  WSAL_LOW,
1262
+ esc_html__( 'User changed menu setting', 'wp-security-audit-log' ),
1263
+ esc_html__( 'The setting %MenuSetting% in the menu %MenuName%.', 'wp-security-audit-log' ),
1264
+ array(),
1265
+ wsaldefaults_build_links( array( 'MenuUrl' ) ),
1266
  'menu',
1267
+ 'enabled',
1268
  ),
1269
  array(
1270
  2083,
1271
  WSAL_LOW,
1272
+ esc_html__( 'User modified content in a menu', 'wp-security-audit-log' ),
1273
+ esc_html__( 'Modified the item %ContentName% in the menu %MenuName%.', 'wp-security-audit-log' ),
1274
+ array(
1275
+ esc_html__( 'Item type', 'wp-security-audit-log' ) => '%ContentType%',
1276
+ ),
1277
+ wsaldefaults_build_links( array( 'MenuUrl' ) ),
1278
  'menu',
1279
+ 'modified',
1280
  ),
1281
  array(
1282
  2084,
1283
  WSAL_LOW,
1284
+ esc_html__( 'User changed name of a menu', 'wp-security-audit-log' ),
1285
+ esc_html__( 'Renamed the menu %OldMenuName% to %MenuName%.', 'wp-security-audit-log' ),
1286
+ array(),
1287
+ wsaldefaults_build_links( array( 'MenuUrl' ) ),
1288
  'menu',
1289
+ 'renamed',
1290
  ),
1291
  array(
1292
  2085,
1293
  WSAL_LOW,
1294
+ esc_html__( 'User changed order of the objects in a menu', 'wp-security-audit-log' ),
1295
+ esc_html__( 'Changed the order of the items in the menu %MenuName%.', 'wp-security-audit-log' ),
1296
+ array(),
1297
+ wsaldefaults_build_links( array( 'MenuUrl' ) ),
1298
  'menu',
1299
+ 'modified',
1300
  ),
1301
  array(
1302
  2089,
1303
  WSAL_LOW,
1304
+ esc_html__( 'User moved objects as a sub-item', 'wp-security-audit-log' ),
1305
+ esc_html__( 'Moved items as sub-items in the menu %MenuName%.', 'wp-security-audit-log' ),
1306
+ array(
1307
+ esc_html__( 'Moved item', 'wp-security-audit-log' ) => '%ItemName%',
1308
+ esc_html__( 'as a sub-item of', 'wp-security-audit-log' ) => '%ParentName%',
1309
+ ),
1310
+ wsaldefaults_build_links( array( 'MenuUrl' ) ),
1311
  'menu',
1312
+ 'modified',
1313
  ),
1314
  ),
1315
 
1321
  *
1322
  * @deprecated 3.1.0
1323
  */
1324
+ esc_html__( 'Custom Post Types', 'wp-security-audit-log' ) => array(
1325
  array(
1326
  2003,
1327
  E_NOTICE,
1328
+ esc_html__( 'User modified a draft blog post', 'wp-security-audit-log' ),
1329
+ esc_html__( 'Modified the draft post with the %PostTitle%. %EditorLinkPost%.', 'wp-security-audit-log' ),
1330
  ),
1331
  array(
1332
  2029,
1333
  E_NOTICE,
1334
+ esc_html__( 'User created a new post with custom post type and saved it as draft', 'wp-security-audit-log' ),
1335
+ esc_html__( 'Created a new custom post called %PostTitle% of type %PostType%. %EditorLinkPost%.', 'wp-security-audit-log' ),
1336
  ),
1337
  array(
1338
  2030,
1339
  E_NOTICE,
1340
+ esc_html__( 'User published a post with custom post type', 'wp-security-audit-log' ),
1341
+ esc_html__( 'Published a custom post %PostTitle% of type %PostType%. Post URL is %PostUrl%. %EditorLinkPost%.', 'wp-security-audit-log' ),
1342
  ),
1343
  array(
1344
  2031,
1345
  E_NOTICE,
1346
+ esc_html__( 'User modified a post with custom post type', 'wp-security-audit-log' ),
1347
+ esc_html__( 'Modified the custom post %PostTitle% of type %PostType%. Post URL is %PostUrl%. %EditorLinkPost%.', 'wp-security-audit-log' ),
1348
  ),
1349
  array(
1350
  2032,
1351
  E_NOTICE,
1352
+ esc_html__( 'User modified a draft post with custom post type', 'wp-security-audit-log' ),
1353
+ esc_html__( 'Modified the draft custom post %PostTitle% of type is %PostType%. %EditorLinkPost%.', 'wp-security-audit-log' ),
1354
  ),
1355
  array(
1356
  2033,
1357
  E_WARNING,
1358
+ esc_html__( 'User permanently deleted post with custom post type', 'wp-security-audit-log' ),
1359
+ esc_html__( 'Permanently Deleted the custom post %PostTitle% of type %PostType%.', 'wp-security-audit-log' ),
1360
  ),
1361
  array(
1362
  2034,
1363
  E_WARNING,
1364
+ esc_html__( 'User moved post with custom post type to trash', 'wp-security-audit-log' ),
1365
+ esc_html__( 'Moved the custom post %PostTitle% of type %PostType% to trash. Post URL was %PostUrl%.', 'wp-security-audit-log' ),
1366
  ),
1367
  array(
1368
  2035,
1369
  E_CRITICAL,
1370
+ esc_html__( 'User restored post with custom post type from trash', 'wp-security-audit-log' ),
1371
+ esc_html__( 'The custom post %PostTitle% of type %PostType% has been restored from trash. %EditorLinkPost%.', 'wp-security-audit-log' ),
1372
  ),
1373
  array(
1374
  2036,
1375
  E_NOTICE,
1376
+ esc_html__( 'User changed the category of a post with custom post type', 'wp-security-audit-log' ),
1377
+ esc_html__( 'Changed the category(ies) of the custom post %PostTitle% of type %PostType% from %OldCategories% to %NewCategories%. %EditorLinkPost%.', 'wp-security-audit-log' ),
1378
  ),
1379
  array(
1380
  2037,
1381
  E_NOTICE,
1382
+ esc_html__( 'User changed the URL of a post with custom post type', 'wp-security-audit-log' ),
1383
+ esc_html__( 'Changed the URL of the custom post %PostTitle% of type %PostType% from %OldUrl% to %NewUrl%. %EditorLinkPost%.', 'wp-security-audit-log' ),
1384
  ),
1385
  array(
1386
  2038,
1387
  E_NOTICE,
1388
+ esc_html__( 'User changed the author or post with custom post type', 'wp-security-audit-log' ),
1389
+ esc_html__( 'Changed the author of custom post %PostTitle% of type %PostType% from %OldAuthor% to %NewAuthor%. %EditorLinkPost%.', 'wp-security-audit-log' ),
1390
  ),
1391
  array(
1392
  2039,
1393
  E_NOTICE,
1394
+ esc_html__( 'User changed the status of post with custom post type', 'wp-security-audit-log' ),
1395
+ esc_html__( 'Changed the status of custom post %PostTitle% of type %PostType% from %OldStatus% to %NewStatus%. %EditorLinkPost%.', 'wp-security-audit-log' ),
1396
  ),
1397
  array(
1398
  2040,
1399
  E_WARNING,
1400
+ esc_html__( 'User changed the visibility of a post with custom post type', 'wp-security-audit-log' ),
1401
+ esc_html__( 'Changed the visibility of the custom post %PostTitle% of type %PostType% from %OldVisibility% to %NewVisibility%. %EditorLinkPost%.', 'wp-security-audit-log' ),
1402
  ),
1403
  array(
1404
  2041,
1405
  E_NOTICE,
1406
+ esc_html__( 'User changed the date of post with custom post type', 'wp-security-audit-log' ),
1407
+ esc_html__( 'Changed the date of the custom post %PostTitle% of type %PostType% from %OldDate% to %NewDate%. %EditorLinkPost%.', 'wp-security-audit-log' ),
1408
  ),
1409
  array(
1410
  2056,
1411
  E_CRITICAL,
1412
+ esc_html__( 'User created a custom field for a custom post type', 'wp-security-audit-log' ),
1413
+ esc_html__( 'Created a new custom field %MetaKey% with value %MetaValue% in custom post %PostTitle% of type %PostType%. %EditorLinkPost%.<br>%MetaLink%.', 'wp-security-audit-log' ),
1414
  ),
1415
  array(
1416
  2057,
1417
  E_CRITICAL,
1418
+ esc_html__( 'User updated a custom field for a custom post type', 'wp-security-audit-log' ),
1419
+ esc_html__( 'Modified the value of the custom field %MetaKey% from %MetaValueOld% to %MetaValueNew% in custom post %PostTitle% of type %PostType% %EditorLinkPost%.<br>%MetaLink%.', 'wp-security-audit-log' ),
1420
  ),
1421
  array(
1422
  2058,
1423
  E_CRITICAL,
1424
+ esc_html__( 'User deleted a custom field from a custom post type', 'wp-security-audit-log' ),
1425
+ esc_html__( 'Deleted the custom field %MetaKey% with id %MetaID% from custom post %PostTitle% of type %PostType% %EditorLinkPost%.<br>%MetaLink%.', 'wp-security-audit-log' ),
1426
  ),
1427
  array(
1428
  2063,
1429
  E_CRITICAL,
1430
+ esc_html__( 'User updated a custom field name for a custom post type', 'wp-security-audit-log' ),
1431
+ esc_html__( 'Changed the custom field name from %MetaKeyOld% to %MetaKeyNew% in custom post %PostTitle% of type %PostType% %EditorLinkPost%.<br>%MetaLink%.', 'wp-security-audit-log' ),
1432
  ),
1433
  array(
1434
  2067,
1435
  E_WARNING,
1436
+ esc_html__( 'User modified content for a published custom post type', 'wp-security-audit-log' ),
1437
+ esc_html__( 'Modified the content of the published custom post type %PostTitle%. Post URL is %PostUrl%. %EditorLinkPost%.', 'wp-security-audit-log' ),
1438
  ),
1439
  array(
1440
  2068,
1441
  E_NOTICE,
1442
+ esc_html__( 'User modified content for a draft post', 'wp-security-audit-log' ),
1443
+ esc_html__( 'Modified the content of the draft post %PostTitle%.%RevisionLink% %EditorLinkPost%.', 'wp-security-audit-log' ),
1444
  ),
1445
  array(
1446
  2070,
1447
  E_NOTICE,
1448
+ esc_html__( 'User modified content for a draft custom post type', 'wp-security-audit-log' ),
1449
+ esc_html__( 'Modified the content of the draft custom post type %PostTitle%.%EditorLinkPost%.', 'wp-security-audit-log' ),
1450
  ),
1451
  array(
1452
  2072,
1453
  E_NOTICE,
1454
+ esc_html__( 'User modified content of a post', 'wp-security-audit-log' ),
1455
+ esc_html__( 'Modified the content of post %PostTitle% which is submitted for review.%RevisionLink% %EditorLinkPost%.', 'wp-security-audit-log' ),
1456
  ),
1457
  array(
1458
  2076,
1459
  E_NOTICE,
1460
+ esc_html__( 'User scheduled a custom post type', 'wp-security-audit-log' ),
1461
+ esc_html__( 'Scheduled the custom post type %PostTitle% to be published %PublishingDate%. %EditorLinkPost%.', 'wp-security-audit-log' ),
1462
  ),
1463
  array(
1464
  2088,
1465
  E_NOTICE,
1466
+ esc_html__( 'User changed title of a custom post type', 'wp-security-audit-log' ),
1467
+ esc_html__( 'Changed the title of the custom post %OldTitle% to %NewTitle%. %EditorLinkPost%.', 'wp-security-audit-log' ),
1468
  ),
1469
  array(
1470
  2104,
1471
  E_NOTICE,
1472
+ esc_html__( 'User opened a custom post type in the editor', 'wp-security-audit-log' ),
1473
+ esc_html__( 'Opened the custom post %PostTitle% of type %PostType% in the editor. View the post: %EditorLinkPost%.', 'wp-security-audit-log' ),
1474
  ),
1475
  array(
1476
  2105,
1477
  E_NOTICE,
1478
+ esc_html__( 'User viewed a custom post type', 'wp-security-audit-log' ),
1479
+ esc_html__( 'Viewed the custom post %PostTitle% of type %PostType%. View the post: %PostUrl%.', 'wp-security-audit-log' ),
1480
  ),
1481
  array(
1482
  5021,
1483
  E_CRITICAL,
1484
+ esc_html__( 'A plugin created a custom post', 'wp-security-audit-log' ),
1485
+ esc_html__( 'A plugin automatically created the following custom post: %PostTitle%.', 'wp-security-audit-log' ),
1486
  ),
1487
  array(
1488
  5027,
1489
  E_CRITICAL,
1490
+ esc_html__( 'A plugin deleted a custom post', 'wp-security-audit-log' ),
1491
+ esc_html__( 'A plugin automatically deleted the following custom post: %PostTitle%.', 'wp-security-audit-log' ),
1492
  ),
1493
  array(
1494
  2108,
1495
  E_NOTICE,
1496
+ esc_html__( 'A plugin modified a custom post', 'wp-security-audit-log' ),
1497
+ esc_html__( 'Plugin modified the custom post %PostTitle%. View the post: %EditorLinkPost%.', 'wp-security-audit-log' ),
1498
  ),
1499
  ),
1500
 
1506
  *
1507
  * @deprecated 3.1.0
1508
  */
1509
+ esc_html__( 'Pages', 'wp-security-audit-log' ) => array(
1510
  array(
1511
  2004,
1512
  E_NOTICE,
1513
+ esc_html__( 'User created a new WordPress page and saved it as draft', 'wp-security-audit-log' ),
1514
+ esc_html__( 'Created a new page called %PostTitle% and saved it as draft. %EditorLinkPage%.', 'wp-security-audit-log' ),
1515
  ),
1516
  array(
1517
  2005,
1518
  E_NOTICE,
1519
+ esc_html__( 'User published a WordPress page', 'wp-security-audit-log' ),
1520
+ esc_html__( 'Published a page called %PostTitle%. Page URL is %PostUrl%. %EditorLinkPage%.', 'wp-security-audit-log' ),
1521
  ),
1522
  array(
1523
  2006,
1524
  E_NOTICE,
1525
+ esc_html__( 'User modified a published WordPress page', 'wp-security-audit-log' ),
1526
+ esc_html__( 'Modified the published page %PostTitle%. Page URL is %PostUrl%. %EditorLinkPage%.', 'wp-security-audit-log' ),
1527
  ),
1528
  array(
1529
  2007,
1530
  E_NOTICE,
1531
+ esc_html__( 'User modified a draft WordPress page', 'wp-security-audit-log' ),
1532
+ esc_html__( 'Modified the draft page %PostTitle%. Page ID is %PostID%. %EditorLinkPage%.', 'wp-security-audit-log' ),
1533
  ),
1534
  array(
1535
  2009,
1536
  E_WARNING,
1537
+ esc_html__( 'User permanently deleted a page from the trash', 'wp-security-audit-log' ),
1538
+ esc_html__( 'Permanently deleted the page %PostTitle%.', 'wp-security-audit-log' ),
1539
  ),
1540
  array(
1541
  2013,
1542
  E_WARNING,
1543
+ esc_html__( 'User moved WordPress page to the trash', 'wp-security-audit-log' ),
1544
+ esc_html__( 'Moved the page %PostTitle% to trash. Page URL was %PostUrl%.', 'wp-security-audit-log' ),
1545
  ),
1546
  array(
1547
  2015,
1548
  E_CRITICAL,
1549
+ esc_html__( 'User restored a WordPress page from trash', 'wp-security-audit-log' ),
1550
+ esc_html__( 'Page %PostTitle% has been restored from trash. %EditorLinkPage%.', 'wp-security-audit-log' ),
1551
  ),
1552
  array(
1553
  2018,
1554
  E_NOTICE,
1555
+ esc_html__( 'User changed page URL', 'wp-security-audit-log' ),
1556
+ esc_html__( 'Changed the URL of the page %PostTitle% from %OldUrl% to %NewUrl%. %EditorLinkPage%.', 'wp-security-audit-log' ),
1557
  ),
1558
  array(
1559
  2020,
1560
  E_NOTICE,
1561
+ esc_html__( 'User changed page author', 'wp-security-audit-log' ),
1562
+ esc_html__( 'Changed the author of the page %PostTitle% from %OldAuthor% to %NewAuthor%. %EditorLinkPage%.', 'wp-security-audit-log' ),
1563
  ),
1564
  array(
1565
  2022,
1566
  E_NOTICE,
1567
+ esc_html__( 'User changed page status', 'wp-security-audit-log' ),
1568
+ esc_html__( 'Changed the status of the page %PostTitle% from %OldStatus% to %NewStatus%. %EditorLinkPage%.', 'wp-security-audit-log' ),
1569
  ),
1570
  array(
1571
  2026,
1572
  E_WARNING,
1573
+ esc_html__( 'User changed the visibility of a page post', 'wp-security-audit-log' ),
1574
+ esc_html__( 'Changed the visibility of the page %PostTitle% from %OldVisibility% to %NewVisibility%. %EditorLinkPage%.', 'wp-security-audit-log' ),
1575
  ),
1576
  array(
1577
  2028,
1578
  E_NOTICE,
1579
+ esc_html__( 'User changed the date of a page post', 'wp-security-audit-log' ),
1580
+ esc_html__( 'Changed the date of the page %PostTitle% from %OldDate% to %NewDate%. %EditorLinkPage%.', 'wp-security-audit-log' ),
1581
  ),
1582
  array(
1583
  2059,
1584
  E_CRITICAL,
1585
+ esc_html__( 'User created a custom field for a page', 'wp-security-audit-log' ),
1586
+ esc_html__( 'Created a new custom field called %MetaKey% with value %MetaValue% in the page %PostTitle% %EditorLinkPage%.<br>%MetaLink%.', 'wp-security-audit-log' ),
1587
  ),
1588
  array(
1589
  2060,
1590
  E_CRITICAL,
1591
+ esc_html__( 'User updated a custom field value for a page', 'wp-security-audit-log' ),
1592
+ esc_html__( 'Modified the value of the custom field %MetaKey% from %MetaValueOld% to %MetaValueNew% in the page %PostTitle% %EditorLinkPage%.<br>%MetaLink%.', 'wp-security-audit-log' ),
1593
  ),
1594
  array(
1595
  2061,
1596
  E_CRITICAL,
1597
+ esc_html__( 'User deleted a custom field from a page', 'wp-security-audit-log' ),
1598
+ esc_html__( 'Deleted the custom field %MetaKey% with id %MetaID% from page %PostTitle% %EditorLinkPage%<br>%MetaLink%.', 'wp-security-audit-log' ),
1599
  ),
1600
  array(
1601
  2064,
1602
  E_CRITICAL,
1603
+ esc_html__( 'User updated a custom field name for a page', 'wp-security-audit-log' ),
1604
+ esc_html__( 'Changed the custom field name from %MetaKeyOld% to %MetaKeyNew% in the page %PostTitle% %EditorLinkPage%.<br>%MetaLink%.', 'wp-security-audit-log' ),
1605
  ),
1606
  array(
1607
  2066,
1608
  E_WARNING,
1609
+ esc_html__( 'User modified content for a published page', 'wp-security-audit-log' ),
1610
+ esc_html__( 'Modified the content of the published page %PostTitle%. Page URL is %PostUrl%. %RevisionLink% %EditorLinkPage%.', 'wp-security-audit-log' ),
1611
  ),
1612
  array(
1613
  2069,
1614
  E_NOTICE,
1615
+ esc_html__( 'User modified content for a draft page', 'wp-security-audit-log' ),
1616
+ esc_html__( 'Modified the content of draft page %PostTitle%.%RevisionLink% %EditorLinkPage%.', 'wp-security-audit-log' ),
1617
  ),
1618
  array(
1619
  2075,
1620
  E_NOTICE,
1621
+ esc_html__( 'User scheduled a page', 'wp-security-audit-log'