WP Security Audit Log - Version 3.2.2

Version Description

Download this release

Release Info

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

Code changes from version 3.2.1 to 3.2.2

Files changed (223) hide show
  1. classes/AlertManager.php +44 -2
  2. classes/AuditLogListView.php +5 -2
  3. classes/Loggers/Database.php +112 -61
  4. classes/Sensors/BBPress.php +5 -0
  5. classes/Sensors/Content.php +269 -118
  6. classes/Sensors/Database.php +4 -2
  7. classes/Sensors/FileChanges.php +36 -5
  8. classes/Sensors/MetaData.php +120 -31
  9. classes/Sensors/PluginsThemes.php +426 -14
  10. classes/Sensors/System.php +56 -26
  11. classes/Sensors/UserProfile.php +76 -2
  12. classes/Sensors/WooCommerce.php +246 -151
  13. classes/Sensors/YoastSEO.php +2 -1
  14. classes/Settings.php +39 -1
  15. classes/ViewManager.php +1 -1
  16. classes/Views/AuditLog.php +62 -2
  17. classes/Views/Help.php +442 -127
  18. classes/Views/Settings.php +200 -82
  19. classes/Views/ToggleAlerts.php +104 -15
  20. classes/WidgetManager.php +30 -10
  21. css/extensions.css +29 -5
  22. css/settings.css +19 -6
  23. defaults.php +9 -3
  24. includes/class-wsal-browser.php +1545 -0
  25. {sdk → includes}/freemius/LICENSE.txt +0 -0
  26. {sdk → includes}/freemius/README.md +0 -0
  27. {sdk → includes}/freemius/assets/css/admin/account.css +0 -0
  28. {sdk → includes}/freemius/assets/css/admin/add-ons.css +0 -0
  29. {sdk → includes}/freemius/assets/css/admin/affiliation.css +0 -0
  30. {sdk → includes}/freemius/assets/css/admin/checkout.css +0 -0
  31. {sdk → includes}/freemius/assets/css/admin/common.css +0 -0
  32. {sdk → includes}/freemius/assets/css/admin/connect.css +0 -0
  33. {sdk → includes}/freemius/assets/css/admin/deactivation-feedback.css +0 -0
  34. {sdk → includes}/freemius/assets/css/admin/debug.css +0 -0
  35. {sdk → includes}/freemius/assets/css/admin/dialog-boxes.css +0 -0
  36. {sdk → includes}/freemius/assets/css/admin/gdpr-optin-notice.css +0 -0
  37. {sdk → includes}/freemius/assets/css/admin/index.php +0 -0
  38. {sdk → includes}/freemius/assets/css/admin/license-activation.css +0 -0
  39. {sdk → includes}/freemius/assets/css/customizer.css +0 -0
  40. {sdk → includes}/freemius/assets/css/index.php +0 -0
  41. {sdk → includes}/freemius/assets/img/index.php +0 -0
  42. {sdk → includes}/freemius/assets/img/plugin-icon.png +0 -0
  43. {sdk → includes}/freemius/assets/img/theme-icon.png +0 -0
  44. {sdk → includes}/freemius/assets/img/wp-security-audit-log.png +0 -0
  45. {sdk → includes}/freemius/assets/index.php +0 -0
  46. {sdk → includes}/freemius/assets/js/index.php +0 -0
  47. {sdk → includes}/freemius/assets/js/nojquery.ba-postmessage.js +0 -0
  48. {sdk → includes}/freemius/assets/js/nojquery.ba-postmessage.min.js +0 -0
  49. {sdk → includes}/freemius/assets/js/postmessage.js +0 -0
  50. {sdk → includes}/freemius/assets/scss/_colors.scss +0 -0
  51. {sdk → includes}/freemius/assets/scss/_functions.scss +0 -0
  52. {sdk → includes}/freemius/assets/scss/_load.scss +0 -0
  53. {sdk → includes}/freemius/assets/scss/_mixins.scss +0 -0
  54. {sdk → includes}/freemius/assets/scss/_start.scss +0 -0
  55. {sdk → includes}/freemius/assets/scss/_vars.scss +0 -0
  56. {sdk → includes}/freemius/assets/scss/admin/_ajax-loader.scss +0 -0
  57. {sdk → includes}/freemius/assets/scss/admin/_auto-install.scss +0 -0
  58. {sdk → includes}/freemius/assets/scss/admin/_deactivation-feedback.scss +0 -0
  59. {sdk → includes}/freemius/assets/scss/admin/_gdpr-consent.scss +0 -0
  60. {sdk → includes}/freemius/assets/scss/admin/_license-activation.scss +0 -0
  61. {sdk → includes}/freemius/assets/scss/admin/_license-key-resend.scss +0 -0
  62. {sdk → includes}/freemius/assets/scss/admin/_modal-common.scss +0 -0
  63. {sdk → includes}/freemius/assets/scss/admin/_multisite-options.scss +0 -0
  64. {sdk → includes}/freemius/assets/scss/admin/_themes.scss +0 -0
  65. {sdk → includes}/freemius/assets/scss/admin/_tooltip.scss +0 -0
  66. {sdk → includes}/freemius/assets/scss/admin/account.scss +0 -0
  67. {sdk → includes}/freemius/assets/scss/admin/add-ons.scss +0 -0
  68. {sdk → includes}/freemius/assets/scss/admin/affiliation.scss +0 -0
  69. {sdk → includes}/freemius/assets/scss/admin/checkout.scss +0 -0
  70. {sdk → includes}/freemius/assets/scss/admin/common.scss +0 -0
  71. {sdk → includes}/freemius/assets/scss/admin/connect.scss +0 -0
  72. {sdk → includes}/freemius/assets/scss/admin/debug.scss +0 -0
  73. {sdk → includes}/freemius/assets/scss/admin/dialog-boxes.scss +0 -0
  74. {sdk → includes}/freemius/assets/scss/admin/gdpr-optin-notice.scss +0 -0
  75. {sdk → includes}/freemius/assets/scss/admin/index.php +0 -0
  76. {sdk → includes}/freemius/assets/scss/customizer.scss +0 -0
  77. {sdk → includes}/freemius/assets/scss/index.php +0 -0
  78. {sdk → includes}/freemius/config.php +0 -0
  79. {sdk → includes}/freemius/includes/class-freemius-abstract.php +0 -0
  80. {sdk → includes}/freemius/includes/class-freemius.php +0 -0
  81. {sdk → includes}/freemius/includes/class-fs-admin-notices.php +0 -0
  82. {sdk → includes}/freemius/includes/class-fs-api.php +0 -0
  83. {sdk → includes}/freemius/includes/class-fs-logger.php +0 -0
  84. {sdk → includes}/freemius/includes/class-fs-options.php +0 -0
  85. {sdk → includes}/freemius/includes/class-fs-plugin-updater.php +0 -0
  86. {sdk → includes}/freemius/includes/class-fs-security.php +0 -0
  87. {sdk → includes}/freemius/includes/class-fs-storage.php +0 -0
  88. {sdk → includes}/freemius/includes/class-fs-user-lock.php +0 -0
  89. {sdk → includes}/freemius/includes/customizer/class-fs-customizer-support-section.php +0 -0
  90. {sdk → includes}/freemius/includes/customizer/class-fs-customizer-upsell-control.php +0 -0
  91. {sdk → includes}/freemius/includes/customizer/index.php +0 -0
  92. {sdk → includes}/freemius/includes/debug/class-fs-debug-bar-panel.php +0 -0
  93. {sdk → includes}/freemius/includes/debug/debug-bar-start.php +0 -0
  94. {sdk → includes}/freemius/includes/debug/index.php +0 -0
  95. {sdk → includes}/freemius/includes/entities/class-fs-affiliate-terms.php +0 -0
  96. {sdk → includes}/freemius/includes/entities/class-fs-affiliate.php +0 -0
  97. {sdk → includes}/freemius/includes/entities/class-fs-billing.php +0 -0
  98. {sdk → includes}/freemius/includes/entities/class-fs-entity.php +0 -0
  99. {sdk → includes}/freemius/includes/entities/class-fs-payment.php +0 -0
  100. {sdk → includes}/freemius/includes/entities/class-fs-plugin-info.php +0 -0
  101. {sdk → includes}/freemius/includes/entities/class-fs-plugin-license.php +0 -0
  102. {sdk → includes}/freemius/includes/entities/class-fs-plugin-plan.php +0 -0
  103. {sdk → includes}/freemius/includes/entities/class-fs-plugin-tag.php +0 -0
  104. {sdk → includes}/freemius/includes/entities/class-fs-plugin.php +0 -0
  105. {sdk → includes}/freemius/includes/entities/class-fs-pricing.php +0 -0
  106. {sdk → includes}/freemius/includes/entities/class-fs-scope-entity.php +0 -0
  107. {sdk → includes}/freemius/includes/entities/class-fs-site.php +0 -0
  108. {sdk → includes}/freemius/includes/entities/class-fs-subscription.php +0 -0
  109. {sdk → includes}/freemius/includes/entities/class-fs-user.php +0 -0
  110. {sdk → includes}/freemius/includes/entities/index.php +0 -0
  111. {sdk → includes}/freemius/includes/fs-core-functions.php +0 -0
  112. {sdk → includes}/freemius/includes/fs-essential-functions.php +0 -0
  113. {sdk → includes}/freemius/includes/fs-plugin-info-dialog.php +0 -0
  114. {sdk → includes}/freemius/includes/i18n.php +0 -0
  115. {sdk → includes}/freemius/includes/index.php +0 -0
  116. {sdk → includes}/freemius/includes/l10n.php +0 -0
  117. {sdk → includes}/freemius/includes/managers/class-fs-admin-menu-manager.php +0 -0
  118. {sdk → includes}/freemius/includes/managers/class-fs-admin-notice-manager.php +0 -0
  119. {sdk → includes}/freemius/includes/managers/class-fs-cache-manager.php +0 -0
  120. {sdk → includes}/freemius/includes/managers/class-fs-gdpr-manager.php +0 -0
  121. {sdk → includes}/freemius/includes/managers/class-fs-key-value-storage.php +0 -0
  122. {sdk → includes}/freemius/includes/managers/class-fs-license-manager.php +0 -0
  123. {sdk → includes}/freemius/includes/managers/class-fs-option-manager.php +0 -0
  124. {sdk → includes}/freemius/includes/managers/class-fs-plan-manager.php +0 -0
  125. {sdk → includes}/freemius/includes/managers/class-fs-plugin-manager.php +0 -0
  126. {sdk → includes}/freemius/includes/managers/index.php +0 -0
  127. {sdk → includes}/freemius/includes/sdk/Exceptions/ArgumentNotExistException.php +0 -0
  128. {sdk → includes}/freemius/includes/sdk/Exceptions/EmptyArgumentException.php +0 -0
  129. {sdk → includes}/freemius/includes/sdk/Exceptions/Exception.php +0 -0
  130. {sdk → includes}/freemius/includes/sdk/Exceptions/InvalidArgumentException.php +0 -0
  131. {sdk → includes}/freemius/includes/sdk/Exceptions/OAuthException.php +0 -0
  132. {sdk → includes}/freemius/includes/sdk/Exceptions/index.php +0 -0
  133. {sdk → includes}/freemius/includes/sdk/FreemiusBase.php +0 -0
  134. {sdk → includes}/freemius/includes/sdk/FreemiusWordPress.php +0 -0
  135. {sdk → includes}/freemius/includes/sdk/LICENSE.txt +0 -0
  136. {sdk → includes}/freemius/includes/sdk/index.php +0 -0
  137. {sdk → includes}/freemius/includes/supplements/fs-essential-functions-1.1.7.1.php +0 -0
  138. {sdk → includes}/freemius/includes/supplements/index.php +0 -0
  139. {sdk → includes}/freemius/index.php +0 -0
  140. {sdk → includes}/freemius/languages/freemius-da_DK.mo +0 -0
  141. {sdk → includes}/freemius/languages/freemius-da_DK.po +0 -0
  142. {sdk → includes}/freemius/languages/freemius-en.mo +0 -0
  143. {sdk → includes}/freemius/languages/freemius-en.po +0 -0
  144. {sdk → includes}/freemius/languages/freemius-es_ES.mo +0 -0
  145. {sdk → includes}/freemius/languages/freemius-es_ES.po +0 -0
  146. {sdk → includes}/freemius/languages/freemius-fr_FR.mo +0 -0
  147. {sdk → includes}/freemius/languages/freemius-fr_FR.po +0 -0
  148. {sdk → includes}/freemius/languages/freemius-he_IL.mo +0 -0
  149. {sdk → includes}/freemius/languages/freemius-he_IL.po +0 -0
  150. {sdk → includes}/freemius/languages/freemius-it_IT.mo +0 -0
  151. {sdk → includes}/freemius/languages/freemius-it_IT.po +0 -0
  152. {sdk → includes}/freemius/languages/freemius-ja_JP.mo +0 -0
  153. {sdk → includes}/freemius/languages/freemius-ja_JP.po +0 -0
  154. {sdk → includes}/freemius/languages/freemius-nl_NL.mo +0 -0
  155. {sdk → includes}/freemius/languages/freemius-nl_NL.po +0 -0
  156. {sdk → includes}/freemius/languages/freemius-ru_RU.mo +0 -0
  157. {sdk → includes}/freemius/languages/freemius-ru_RU.po +0 -0
  158. {sdk → includes}/freemius/languages/freemius.pot +0 -0
  159. {sdk → includes}/freemius/languages/index.php +0 -0
  160. {sdk → includes}/freemius/require.php +0 -0
  161. {sdk → includes}/freemius/start.php +0 -0
  162. {sdk → includes}/freemius/templates/account.php +0 -0
  163. {sdk → includes}/freemius/templates/account/billing.php +0 -0
  164. {sdk → includes}/freemius/templates/account/index.php +0 -0
  165. {sdk → includes}/freemius/templates/account/partials/activate-license-button.php +0 -0
  166. {sdk → includes}/freemius/templates/account/partials/addon.php +0 -0
  167. {sdk → includes}/freemius/templates/account/partials/deactivate-license-button.php +0 -0
  168. {sdk → includes}/freemius/templates/account/partials/index.php +0 -0
  169. {sdk → includes}/freemius/templates/account/partials/site.php +0 -0
  170. {sdk → includes}/freemius/templates/account/payments.php +0 -0
  171. {sdk → includes}/freemius/templates/add-ons.php +0 -0
  172. {sdk → includes}/freemius/templates/add-trial-to-pricing.php +0 -0
  173. {sdk → includes}/freemius/templates/admin-notice.php +0 -0
  174. {sdk → includes}/freemius/templates/ajax-loader.php +0 -0
  175. {sdk → includes}/freemius/templates/auto-installation.php +0 -0
  176. {sdk → includes}/freemius/templates/checkout.php +0 -0
  177. {sdk → includes}/freemius/templates/connect.php +0 -0
  178. {sdk → includes}/freemius/templates/contact.php +0 -0
  179. {sdk → includes}/freemius/templates/debug.php +0 -0
  180. {sdk → includes}/freemius/templates/debug/api-calls.php +0 -0
  181. {sdk → includes}/freemius/templates/debug/index.php +0 -0
  182. {sdk → includes}/freemius/templates/debug/logger.php +0 -0
  183. {sdk → includes}/freemius/templates/debug/plugins-themes-sync.php +0 -0
  184. {sdk → includes}/freemius/templates/debug/scheduled-crons.php +0 -0
  185. {sdk → includes}/freemius/templates/email.php +0 -0
  186. {sdk → includes}/freemius/templates/firewall-issues-js.php +0 -0
  187. {sdk → includes}/freemius/templates/forms/affiliation.php +0 -0
  188. {sdk → includes}/freemius/templates/forms/deactivation/contact.php +0 -0
  189. {sdk → includes}/freemius/templates/forms/deactivation/form.php +0 -0
  190. {sdk → includes}/freemius/templates/forms/deactivation/index.php +0 -0
  191. {sdk → includes}/freemius/templates/forms/deactivation/retry-skip.php +0 -0
  192. {sdk → includes}/freemius/templates/forms/index.php +0 -0
  193. {sdk → includes}/freemius/templates/forms/license-activation.php +0 -0
  194. {sdk → includes}/freemius/templates/forms/optout.php +0 -0
  195. {sdk → includes}/freemius/templates/forms/premium-versions-upgrade-handler.php +0 -0
  196. {sdk → includes}/freemius/templates/forms/premium-versions-upgrade-metadata.php +0 -0
  197. {sdk → includes}/freemius/templates/forms/resend-key.php +0 -0
  198. {sdk → includes}/freemius/templates/forms/trial-start.php +0 -0
  199. {sdk → includes}/freemius/templates/gdpr-optin-js.php +0 -0
  200. {sdk → includes}/freemius/templates/index.php +0 -0
  201. {sdk → includes}/freemius/templates/js/index.php +0 -0
  202. {sdk → includes}/freemius/templates/js/jquery.content-change.php +0 -0
  203. {sdk → includes}/freemius/templates/js/open-license-activation.php +0 -0
  204. {sdk → includes}/freemius/templates/js/style-premium-theme.php +0 -0
  205. {sdk → includes}/freemius/templates/partials/network-activation.php +0 -0
  206. {sdk → includes}/freemius/templates/plugin-icon.php +0 -0
  207. {sdk → includes}/freemius/templates/plugin-info/description.php +0 -0
  208. {sdk → includes}/freemius/templates/plugin-info/features.php +0 -0
  209. {sdk → includes}/freemius/templates/plugin-info/index.php +0 -0
  210. {sdk → includes}/freemius/templates/plugin-info/screenshots.php +0 -0
  211. {sdk → includes}/freemius/templates/powered-by.php +0 -0
  212. {sdk → includes}/freemius/templates/pricing.php +0 -0
  213. {sdk → includes}/freemius/templates/secure-https-header.php +0 -0
  214. {sdk → includes}/freemius/templates/sticky-admin-notice-js.php +0 -0
  215. {sdk → includes}/freemius/templates/tabs-capture-js.php +0 -0
  216. {sdk → includes}/freemius/templates/tabs.php +0 -0
  217. {sdk → includes}/wsal-freemius.php +0 -0
  218. js/auditlog.js +60 -0
  219. js/settings.js +64 -36
  220. readme.txt +29 -32
  221. sdk/freemius/templates/all-admin-notice.php +0 -39
  222. sdk/freemius/templates/checkout-legacy.php +0 -242
  223. wp-security-audit-log.php +7 -4
classes/AlertManager.php CHANGED
@@ -42,6 +42,13 @@ final class WSAL_AlertManager {
42
  */
43
  protected $_triggered_types = array();
44
 
 
 
 
 
 
 
 
45
  /**
46
  * Create new AlertManager instance.
47
  *
@@ -54,6 +61,33 @@ final class WSAL_AlertManager {
54
  }
55
 
56
  add_action( 'shutdown', array( $this, '_CommitPipeline' ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  }
58
 
59
  /**
@@ -104,8 +138,13 @@ final class WSAL_AlertManager {
104
  * @param bool $delayed - False if delayed, true if not.
105
  */
106
  public function Trigger( $type, $data = array(), $delayed = false ) {
 
 
 
107
  // Log temporary alerts first.
108
- $this->log_temp_alerts();
 
 
109
 
110
  // Get username.
111
  $username = wp_get_current_user()->user_login;
@@ -535,6 +574,8 @@ final class WSAL_AlertManager {
535
  /**
536
  * Method: Log temporary stored alerts if DB connection
537
  * is back.
 
 
538
  */
539
  public function log_temp_alerts() {
540
  // Get temporary alerts.
@@ -566,12 +607,13 @@ final class WSAL_AlertManager {
566
 
567
  // Loggers.
568
  foreach ( $this->_loggers as $logger ) {
569
- $logger->Log( $alert_id, $alert['alert_data'], $created_on, $site_id, $is_migrated );
570
  }
571
  }
572
 
573
  // Delete temporary alerts.
574
  delete_option( 'wsal_temp_alerts' );
 
575
  }
576
  }
577
  }
42
  */
43
  protected $_triggered_types = array();
44
 
45
+ /**
46
+ * Log events schedule hook name
47
+ *
48
+ * @var string
49
+ */
50
+ private static $log_events_schedule_hook = 'wsal_log_events_ext_db';
51
+
52
  /**
53
  * Create new AlertManager instance.
54
  *
61
  }
62
 
63
  add_action( 'shutdown', array( $this, '_CommitPipeline' ) );
64
+ add_action( 'wsal_init', array( $this, 'schedule_log_events' ) );
65
+ }
66
+
67
+ /**
68
+ * Method: Schedule log events for External DB
69
+ * if buffer is enabled.
70
+ */
71
+ public function schedule_log_events() {
72
+ // Get external buffer option.
73
+ $use_buffer = $this->plugin->GetGlobalOption( 'adapter-use-buffer' );
74
+
75
+ // If external DB buffer is enabled then set the cron.
76
+ if ( $use_buffer ) {
77
+ // Hook scheduled method.
78
+ add_action( self::$log_events_schedule_hook, array( $this, 'log_temp_alerts' ) );
79
+
80
+ // Schedule event if there isn't any already.
81
+ if ( ! wp_next_scheduled( self::$log_events_schedule_hook ) ) {
82
+ wp_schedule_event(
83
+ time(), // Timestamp.
84
+ 'tenminutes', // Frequency.
85
+ self::$log_events_schedule_hook // Scheduled event.
86
+ );
87
+ }
88
+ } elseif ( ! $use_buffer && wp_next_scheduled( self::$log_events_schedule_hook ) ) {
89
+ wp_clear_scheduled_hook( self::$log_events_schedule_hook );
90
+ }
91
  }
92
 
93
  /**
138
  * @param bool $delayed - False if delayed, true if not.
139
  */
140
  public function Trigger( $type, $data = array(), $delayed = false ) {
141
+ // Get buffer use option.
142
+ $use_buffer = $this->plugin->GetGlobalOption( 'adapter-use-buffer' );
143
+
144
  // Log temporary alerts first.
145
+ if ( ! $use_buffer ) {
146
+ $this->log_temp_alerts();
147
+ }
148
 
149
  // Get username.
150
  $username = wp_get_current_user()->user_login;
574
  /**
575
  * Method: Log temporary stored alerts if DB connection
576
  * is back.
577
+ *
578
+ * @return boolean
579
  */
580
  public function log_temp_alerts() {
581
  // Get temporary alerts.
607
 
608
  // Loggers.
609
  foreach ( $this->_loggers as $logger ) {
610
+ $logger->Log( $alert_id, $alert['alert_data'], $created_on, $site_id, $is_migrated, true );
611
  }
612
  }
613
 
614
  // Delete temporary alerts.
615
  delete_option( 'wsal_temp_alerts' );
616
+ return true;
617
  }
618
  }
619
  }
classes/AuditLogListView.php CHANGED
@@ -548,11 +548,14 @@ class WSAL_AuditLogListView extends WP_List_Table {
548
  case '%LinkFile%' === $name:
549
  if ( 'NULL' != $value ) {
550
  $site_id = $this->get_view_site_id(); // Site id for multisite.
551
- return '<a href="javascript:;" onclick="download_404_log( this )" data-log-file="' . esc_attr( $value ) . '" data-site-id="' . esc_attr( $site_id ) . '" data-nonce-404="' . esc_attr( wp_create_nonce( 'wsal-download-404-log-' . $value ) ) . '" title="' . esc_html__( 'Download the log file.', 'wp-security-audit-log' ) . '">' . esc_html__( 'Download the log file.', 'wp-security-audit-log' ) . '</a>';
552
  } else {
553
- return 'Click <a href="' . esc_url( admin_url( 'admin.php?page=wsal-togglealerts#tab-system-activity' ) ) . '">here</a> to log such requests to file.';
554
  }
555
 
 
 
 
556
  case '%LogFileLink%' === $name: // Failed login file link.
557
  return '';
558
 
548
  case '%LinkFile%' === $name:
549
  if ( 'NULL' != $value ) {
550
  $site_id = $this->get_view_site_id(); // Site id for multisite.
551
+ return '<a href="javascript:;" onclick="download_404_log( this )" data-log-file="' . esc_attr( $value ) . '" data-site-id="' . esc_attr( $site_id ) . '" data-nonce-404="' . esc_attr( wp_create_nonce( 'wsal-download-404-log-' . $value ) ) . '" title="' . esc_html__( 'Download the log file', 'wp-security-audit-log' ) . '">' . esc_html__( 'Download the log file', 'wp-security-audit-log' ) . '</a>';
552
  } else {
553
+ return 'Click <a href="' . esc_url( admin_url( 'admin.php?page=wsal-togglealerts#tab-system-activity' ) ) . '">here</a> to log such requests to file';
554
  }
555
 
556
+ case '%URL%' === $name:
557
+ return ' or <a href="javascript:;" data-exclude-url="' . esc_url( $value ) . '" data-exclude-url-nonce="' . wp_create_nonce( 'wsal-exclude-url-' . $value ) . '" onclick="wsal_exclude_url( this )">exclude this URL</a> from being reported.';
558
+
559
  case '%LogFileLink%' === $name: // Failed login file link.
560
  return '';
561
 
classes/Loggers/Database.php CHANGED
@@ -35,62 +35,69 @@ class WSAL_Loggers_Database extends WSAL_AbstractLogger {
35
  }
36
 
37
  /**
38
- * Log alert.
 
 
 
 
 
 
39
  *
40
  * @param integer $type - Alert code.
41
  * @param array $data - Metadata.
42
  * @param integer $date (Optional) - created_on.
43
  * @param integer $siteid (Optional) - site_id.
44
  * @param bool $migrated (Optional) - is_migrated.
 
45
  */
46
- public function Log( $type, $data = array(), $date = null, $siteid = null, $migrated = false ) {
47
  // Is this a php alert, and if so, are we logging such alerts?
48
  if ( $type < 0010 && ! $this->plugin->settings->IsPhpErrorLoggingEnabled() ) {
49
  return;
50
  }
51
 
52
- // Get temporary stored alerts.
53
- $temp_alerts = get_option( 'wsal_temp_alerts', array() );
54
-
55
  // Create new occurrence.
56
- $occ = new WSAL_Models_Occurrence();
57
  $occ->is_migrated = $migrated;
58
- $occ->created_on = is_null( $date ) ? microtime( true ) : $date;
59
- $occ->alert_id = $type;
60
- $occ->site_id = ! is_null( $siteid ) ? $siteid
61
- : (function_exists( 'get_current_blog_id' ) ? get_current_blog_id() : 0);
62
 
63
  // Get DB connector.
64
- $db_config = WSAL_Connector_ConnectorFactory::GetConfig(); // Get DB connector configuration.
65
- $connector = $this->plugin->getConnector( $db_config ); // Get connector for DB.
66
- $wsal_db = $connector->getConnection(); // Get DB connection.
67
- $connection = true;
68
- if ( isset( $wsal_db->dbh->errno ) ) {
69
- $connection = 0 !== (int) $wsal_db->dbh->errno ? false : true; // Database connection error check.
70
- } elseif ( is_wp_error( $wsal_db->error ) ) {
71
- $connection = false;
72
  }
73
 
74
- // Check DB connection.
75
- if ( $connection ) { // If connected then save the alert in DB.
76
- // Save the alert occurrence.
77
- $occ->Save();
 
 
 
 
 
 
 
78
 
79
- // Set up meta data of the alert.
80
- $occ->SetMeta( $data );
81
- } else { // Else store the alerts in temporary option.
82
- // Store current alert in temporary option array.
83
- $temp_alerts[ $occ->created_on ]['alert'] = array(
84
- 'is_migrated' => $occ->is_migrated,
85
- 'created_on' => $occ->created_on,
86
- 'alert_id' => $occ->alert_id,
87
- 'site_id' => $occ->site_id,
88
- );
89
- $temp_alerts[ $occ->created_on ]['alert_data'] = $data;
90
- }
91
 
92
- // Save temporary alerts to options.
93
- update_option( 'wsal_temp_alerts', $temp_alerts );
 
 
 
 
 
 
94
 
95
  // Inject for promoting the paid add-ons.
96
  $type = (int) $type;
@@ -106,29 +113,73 @@ class WSAL_Loggers_Database extends WSAL_AbstractLogger {
106
  do_action( 'wsal_logged_alert', $occ, $type, $data, $date, $siteid, $migrated );
107
  }
108
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
  /**
110
  * Clean Up alerts by date OR by max number.
111
  */
112
  public function CleanUp() {
113
- $now = current_time( 'timestamp' );
114
  $max_sdate = $this->plugin->settings->GetPruningDate();
115
  $max_count = $this->plugin->settings->GetPruningLimit();
116
  $is_date_e = $this->plugin->settings->IsPruningDateEnabled();
117
  $is_limt_e = $this->plugin->settings->IsPruningLimitEnabled();
118
 
 
119
  if ( ! $is_date_e && ! $is_limt_e ) {
120
  return;
121
- } // Pruning disabled.
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) ) {
127
  return;
128
  }
129
 
130
- $max_stamp = $now - (strtotime( $max_sdate ) - $now);
131
- $max_items = (int) max( ($cnt_items - $max_count) + 1, 0 );
132
 
133
  $query = new WSAL_Models_OccurrenceQuery();
134
  $query->addOrderBy( 'created_on', false );
@@ -140,11 +191,11 @@ class WSAL_Loggers_Database extends WSAL_AbstractLogger {
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 ) {
@@ -153,8 +204,8 @@ class WSAL_Loggers_Database extends WSAL_AbstractLogger {
153
  // Keep track of what we're doing.
154
  $this->plugin->alerts->Trigger(
155
  0003, array(
156
- 'Message' => 'Running system cleanup.',
157
- 'Query SQL' => $result['sql'],
158
  'Query Args' => $result['args'],
159
  ), true
160
  );
@@ -171,27 +222,27 @@ class WSAL_Loggers_Database extends WSAL_AbstractLogger {
171
  private function AlertInject( $occurrence ) {
172
  $count = $this->CheckPromoToShow();
173
  if ( $count && $occurrence->getId() != 0 ) {
174
- if ( ($occurrence->getId() % $count) == 0 ) {
175
  $promo_to_send = $this->GetPromoAlert();
176
  if ( ! empty( $promo_to_send ) ) {
177
- $upgrade_link = add_query_arg( 'page', 'wsal-auditlog-pricing', admin_url( 'admin.php' ) );
178
  $more_info_link = add_query_arg(
179
  array(
180
- 'utm_source' => 'alert',
181
- 'utm_medium' => 'page',
182
- 'utm_content' => 'alert+more+info',
183
  'utm_campaign' => 'upgrade+premium',
184
  ),
185
  'https://www.wpsecurityauditlog.com/premium-features/'
186
  );
187
- $upgrade = '<a href="' . $upgrade_link . '">' . __( 'Upgrade to Premium', 'wp-security-audit-log' ) . '</a>';
188
- $more_info = '<a href="' . $more_info_link . '" target="_blank">' . __( 'More Information', 'wp-security-audit-log' ) . '</a>';
189
  $this->Log(
190
  9999, array(
191
- 'ClientIP' => '127.0.0.1',
192
- 'Username' => 'Plugin',
193
  'PromoMessage' => sprintf( $promo_to_send['message'], $upgrade, $more_info ),
194
- 'PromoName' => $promo_to_send['name'],
195
  )
196
  );
197
  }
@@ -208,8 +259,8 @@ class WSAL_Loggers_Database extends WSAL_AbstractLogger {
208
  private function GetPromoAlert() {
209
  $last_promo_sent_id = $this->plugin->GetGlobalOption( 'promo-send-id' );
210
  $last_promo_sent_id = empty( $last_promo_sent_id ) ? 0 : $last_promo_sent_id;
211
- $promo_to_send = null;
212
- $promo_alerts = $this->GetActivePromoText();
213
  if ( ! empty( $promo_alerts ) ) {
214
  $promo_to_send = isset( $promo_alerts[ $last_promo_sent_id ] ) ? $promo_alerts[ $last_promo_sent_id ] : $promo_alerts[0];
215
 
@@ -229,13 +280,13 @@ class WSAL_Loggers_Database extends WSAL_AbstractLogger {
229
  * @return array $promo_alerts - The array of promo.
230
  */
231
  private function GetActivePromoText() {
232
- $promo_alerts = array();
233
  $promo_alerts[] = array(
234
- 'name' => 'Upgrade to Premium',
235
  'message' => 'See who is logged in, create user productivity reports, get notified instantly via email of important changes, add search and much more. <strong>%1$s</strong> | <strong>%2$s</strong>',
236
  );
237
  $promo_alerts[] = array(
238
- 'name' => 'See Who is Logged In, receive Email Alerts, generate User Productivity Reports and more!',
239
  'message' => 'Upgrade to premium and extend the plugin’s features with email alerts, reports tool, free-text based search, user logins and sessions management and more! <strong>%1$s</strong> | <strong>%2$s</strong>',
240
  );
241
  return $promo_alerts;
35
  }
36
 
37
  /**
38
+ * Log an event.
39
+ *
40
+ * 1. If native DB is being used then check DB connection.
41
+ * 1a. If connection is good, then log the event.
42
+ * 1b. If no connection then save the alert in a temp buffer.
43
+ *
44
+ * 2. If external DB is in action then send the event to a temp buffer.
45
  *
46
  * @param integer $type - Alert code.
47
  * @param array $data - Metadata.
48
  * @param integer $date (Optional) - created_on.
49
  * @param integer $siteid (Optional) - site_id.
50
  * @param bool $migrated (Optional) - is_migrated.
51
+ * @param bool $override_buffer (Optional) - Override buffer to log event immediately.
52
  */
53
+ public function Log( $type, $data = array(), $date = null, $siteid = null, $migrated = false, $override_buffer = false ) {
54
  // Is this a php alert, and if so, are we logging such alerts?
55
  if ( $type < 0010 && ! $this->plugin->settings->IsPhpErrorLoggingEnabled() ) {
56
  return;
57
  }
58
 
 
 
 
59
  // Create new occurrence.
60
+ $occ = new WSAL_Models_Occurrence();
61
  $occ->is_migrated = $migrated;
62
+ $occ->created_on = is_null( $date ) ? microtime( true ) : $date;
63
+ $occ->alert_id = $type;
64
+ $occ->site_id = ! is_null( $siteid ) ? $siteid
65
+ : ( function_exists( 'get_current_blog_id' ) ? get_current_blog_id() : 0 );
66
 
67
  // Get DB connector.
68
+ $db_config = WSAL_Connector_ConnectorFactory::GetConfig(); // Get DB connector configuration.
69
+
70
+ // Get external buffer option.
71
+ $use_buffer = $this->plugin->GetGlobalOption( 'adapter-use-buffer' );
72
+ if ( $override_buffer ) {
73
+ $use_buffer = false;
 
 
74
  }
75
 
76
+ // Check external DB.
77
+ if ( null === $db_config || ( is_array( $db_config ) && ! $use_buffer ) ) { // Not external DB.
78
+ // Get connector for DB.
79
+ $connector = $this->plugin->getConnector( $db_config );
80
+ $wsal_db = $connector->getConnection(); // Get DB connection.
81
+ $connection = true;
82
+ if ( isset( $wsal_db->dbh->errno ) ) {
83
+ $connection = 0 !== (int) $wsal_db->dbh->errno ? false : true; // Database connection error check.
84
+ } elseif ( is_wp_error( $wsal_db->error ) ) {
85
+ $connection = false;
86
+ }
87
 
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 { // Else store the alerts in temporary option.
96
+ $this->store_events_in_buffer( $occ, $data );
97
+ }
98
+ } elseif ( is_array( $db_config ) && $use_buffer ) { // External DB.
99
+ $this->store_events_in_buffer( $occ, $data );
100
+ }
101
 
102
  // Inject for promoting the paid add-ons.
103
  $type = (int) $type;
113
  do_action( 'wsal_logged_alert', $occ, $type, $data, $date, $siteid, $migrated );
114
  }
115
 
116
+ /**
117
+ * Method: Store events in temporary buffer.
118
+ *
119
+ * @param WSAL_Models_Occurrence $occ – Event occurrence object.
120
+ * @param array $event_data – Event meta-data.
121
+ * @return boolean
122
+ */
123
+ private function store_events_in_buffer( $occ, $event_data ) {
124
+ // Check event occurrence object.
125
+ if ( ! empty( $occ ) && $occ instanceof WSAL_Models_Occurrence ) {
126
+ // Get temporary stored alerts.
127
+ $temp_alerts = get_option( 'wsal_temp_alerts', array() );
128
+
129
+ // Store current event in a temporary buffer.
130
+ $temp_alerts[ $occ->created_on ]['alert'] = array(
131
+ 'is_migrated' => $occ->is_migrated,
132
+ 'created_on' => $occ->created_on,
133
+ 'alert_id' => $occ->alert_id,
134
+ 'site_id' => $occ->site_id,
135
+ );
136
+ $temp_alerts[ $occ->created_on ]['alert_data'] = $event_data;
137
+
138
+ // Save temporary alerts to options.
139
+ update_option( 'wsal_temp_alerts', $temp_alerts );
140
+ return true;
141
+ }
142
+
143
+ // Something wrong with $occ object.
144
+ return false;
145
+ }
146
+
147
  /**
148
  * Clean Up alerts by date OR by max number.
149
  */
150
  public function CleanUp() {
151
+ $now = current_time( 'timestamp' );
152
  $max_sdate = $this->plugin->settings->GetPruningDate();
153
  $max_count = $this->plugin->settings->GetPruningLimit();
154
  $is_date_e = $this->plugin->settings->IsPruningDateEnabled();
155
  $is_limt_e = $this->plugin->settings->IsPruningLimitEnabled();
156
 
157
+ // Return if retention is disabled.
158
  if ( ! $is_date_e && ! $is_limt_e ) {
159
  return;
160
+ }
161
+
162
+ // Return if archiving cron is running.
163
+ if ( $this->plugin->GetGlobalOption( 'archiving-cron-started', false ) ) {
164
+ return;
165
+ }
166
+
167
+ // If archiving is enabled then events are deleted from the archive database.
168
+ if ( $this->plugin->settings->IsArchivingEnabled() ) {
169
+ // Switch to Archive DB.
170
+ $this->plugin->settings->SwitchToArchiveDB();
171
+ }
172
+
173
+ $occ = new WSAL_Models_Occurrence();
174
  $cnt_items = $occ->Count();
175
 
176
  // Check if there is something to delete.
177
+ if ( $is_limt_e && ( $cnt_items < $max_count ) ) {
178
  return;
179
  }
180
 
181
+ $max_stamp = $now - ( strtotime( $max_sdate ) - $now );
182
+ $max_items = (int) max( ( $cnt_items - $max_count ) + 1, 0 );
183
 
184
  $query = new WSAL_Models_OccurrenceQuery();
185
  $query->addOrderBy( 'created_on', false );
191
  $query->setLimit( $max_items );
192
  }
193
 
194
+ if ( ( $max_items - 1 ) == 0 ) {
195
  return; // Nothing to delete.
196
  }
197
 
198
+ $result = $query->getAdapter()->GetSqlDelete( $query );
199
  $deleted_count = $query->getAdapter()->Delete( $query );
200
 
201
  if ( 0 == $deleted_count ) {
204
  // Keep track of what we're doing.
205
  $this->plugin->alerts->Trigger(
206
  0003, array(
207
+ 'Message' => 'Running system cleanup.',
208
+ 'Query SQL' => $result['sql'],
209
  'Query Args' => $result['args'],
210
  ), true
211
  );
222
  private function AlertInject( $occurrence ) {
223
  $count = $this->CheckPromoToShow();
224
  if ( $count && $occurrence->getId() != 0 ) {
225
+ if ( ( $occurrence->getId() % $count ) == 0 ) {
226
  $promo_to_send = $this->GetPromoAlert();
227
  if ( ! empty( $promo_to_send ) ) {
228
+ $upgrade_link = add_query_arg( 'page', 'wsal-auditlog-pricing', admin_url( 'admin.php' ) );
229
  $more_info_link = add_query_arg(
230
  array(
231
+ 'utm_source' => 'alert',
232
+ 'utm_medium' => 'page',
233
+ 'utm_content' => 'alert+more+info',
234
  'utm_campaign' => 'upgrade+premium',
235
  ),
236
  'https://www.wpsecurityauditlog.com/premium-features/'
237
  );
238
+ $upgrade = '<a href="' . $upgrade_link . '">' . __( 'Upgrade to Premium', 'wp-security-audit-log' ) . '</a>';
239
+ $more_info = '<a href="' . $more_info_link . '" target="_blank">' . __( 'More Information', 'wp-security-audit-log' ) . '</a>';
240
  $this->Log(
241
  9999, array(
242
+ 'ClientIP' => '127.0.0.1',
243
+ 'Username' => 'Plugin',
244
  'PromoMessage' => sprintf( $promo_to_send['message'], $upgrade, $more_info ),
245
+ 'PromoName' => $promo_to_send['name'],
246
  )
247
  );
248
  }
259
  private function GetPromoAlert() {
260
  $last_promo_sent_id = $this->plugin->GetGlobalOption( 'promo-send-id' );
261
  $last_promo_sent_id = empty( $last_promo_sent_id ) ? 0 : $last_promo_sent_id;
262
+ $promo_to_send = null;
263
+ $promo_alerts = $this->GetActivePromoText();
264
  if ( ! empty( $promo_alerts ) ) {
265
  $promo_to_send = isset( $promo_alerts[ $last_promo_sent_id ] ) ? $promo_alerts[ $last_promo_sent_id ] : $promo_alerts[0];
266
 
280
  * @return array $promo_alerts - The array of promo.
281
  */
282
  private function GetActivePromoText() {
283
+ $promo_alerts = array();
284
  $promo_alerts[] = array(
285
+ 'name' => 'Upgrade to Premium',
286
  'message' => 'See who is logged in, create user productivity reports, get notified instantly via email of important changes, add search and much more. <strong>%1$s</strong> | <strong>%2$s</strong>',
287
  );
288
  $promo_alerts[] = array(
289
+ 'name' => 'See Who is Logged In, receive Email Alerts, generate User Productivity Reports and more!',
290
  'message' => 'Upgrade to premium and extend the plugin’s features with email alerts, reports tool, free-text based search, user logins and sessions management and more! <strong>%1$s</strong> | <strong>%2$s</strong>',
291
  );
292
  return $promo_alerts;
classes/Sensors/BBPress.php CHANGED
@@ -52,6 +52,11 @@ class WSAL_Sensors_BBPress extends WSAL_AbstractSensor {
52
  * Listening to events using WP hooks.
53
  */
54
  public function HookEvents() {
 
 
 
 
 
55
  if ( current_user_can( 'edit_posts' ) ) {
56
  add_action( 'admin_init', array( $this, 'EventAdminInit' ) );
57
  }
52
  * Listening to events using WP hooks.
53
  */
54
  public function HookEvents() {
55
+ // Check if BBPress plugin exists.
56
+ if ( ! is_plugin_active( 'bbpress/bbpress.php' ) ) {
57
+ return false;
58
+ }
59
+
60
  if ( current_user_can( 'edit_posts' ) ) {
61
  add_action( 'admin_init', array( $this, 'EventAdminInit' ) );
62
  }
classes/Sensors/Content.php CHANGED
@@ -19,7 +19,6 @@ if ( ! defined( 'ABSPATH' ) ) {
19
  * 2000 User created a new blog post and saved it as draft
20
  * 2001 User published a blog post
21
  * 2002 User modified a published blog post
22
- * 2003 User modified a draft blog post
23
  * 2008 User permanently deleted a blog post from the trash
24
  * 2012 User moved a blog post to the trash
25
  * 2014 User restored a blog post from trash
@@ -31,12 +30,12 @@ if ( ! defined( 'ABSPATH' ) ) {
31
  * 2024 User deleted category
32
  * 2025 User changed the visibility of a blog post
33
  * 2027 User changed the date of a blog post
 
 
34
  * 2049 User set a post as sticky
35
  * 2050 User removed post from sticky
36
  * 2052 User changed generic tables
37
  * 2065 User modified content for a published post
38
- * 2068 User modified content for a draft post
39
- * 2072 User modified content of a post
40
  * 2073 User submitted a post for review
41
  * 2074 User scheduled a post
42
  * 2086 User changed title of a post
@@ -44,51 +43,6 @@ if ( ! defined( 'ABSPATH' ) ) {
44
  * 2101 User viewed a post
45
  * 2111 User disabled Comments/Trackbacks and Pingbacks on a published post
46
  * 2112 User enabled Comments/Trackbacks and Pingbacks on a published post
47
- * 2113 User disabled Comments/Trackbacks and Pingbacks on a draft post
48
- * 2114 User enabled Comments/Trackbacks and Pingbacks on a draft post
49
- * 2004 User created a new WordPress page and saved it as draft
50
- * 2005 User published a WordPress page
51
- * 2006 User modified a published WordPress page
52
- * 2007 User modified a draft WordPress page
53
- * 2009 User permanently deleted a page from the trash
54
- * 2013 User moved WordPress page to the trash
55
- * 2015 User restored a WordPress page from trash
56
- * 2018 User changed page URL
57
- * 2020 User changed page author
58
- * 2022 User changed page status
59
- * 2026 User changed the visibility of a page post
60
- * 2028 User changed the date of a page post
61
- * 2047 User changed the parent of a page
62
- * 2048 User changed the template of a page
63
- * 2066 User modified content for a published page
64
- * 2069 User modified content for a draft page
65
- * 2075 User scheduled a page
66
- * 2087 User changed title of a page
67
- * 2102 User opened a page in the editor
68
- * 2103 User viewed a page
69
- * 2115 User disabled Comments/Trackbacks and Pingbacks on a published page
70
- * 2116 User enabled Comments/Trackbacks and Pingbacks on a published page
71
- * 2117 User disabled Comments/Trackbacks and Pingbacks on a draft page
72
- * 2118 User enabled Comments/Trackbacks and Pingbacks on a draft page
73
- * 2029 User created a new post with custom post type and saved it as draft
74
- * 2030 User published a post with custom post type
75
- * 2031 User modified a post with custom post type
76
- * 2032 User modified a draft post with custom post type
77
- * 2033 User permanently deleted post with custom post type
78
- * 2034 User moved post with custom post type to trash
79
- * 2035 User restored post with custom post type from trash
80
- * 2036 User changed the category of a post with custom post type
81
- * 2037 User changed the URL of a post with custom post type
82
- * 2038 User changed the author or post with custom post type
83
- * 2039 User changed the status of post with custom post type
84
- * 2040 User changed the visibility of a post with custom post type
85
- * 2041 User changed the date of post with custom post type
86
- * 2067 User modified content for a published custom post type
87
- * 2070 User modified content for a draft custom post type
88
- * 2076 User scheduled a custom post type
89
- * 2088 User changed title of a custom post type
90
- * 2104 User opened a custom post type in the editor
91
- * 2105 User viewed a custom post type
92
  * 2119 User added blog post tag
93
  * 2120 User removed blog post tag
94
  * 2121 User created new tag
@@ -166,6 +120,11 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
166
  add_filter( 'post_edit_form_tag', array( $this, 'EditingPost' ), 10, 1 );
167
 
168
  add_filter( 'wp_update_term_data', array( $this, 'event_terms_rename' ), 10, 4 );
 
 
 
 
 
169
  }
170
 
171
  /**
@@ -310,6 +269,33 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
310
  }
311
  }
312
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313
  /**
314
  * Get the template path.
315
  *
@@ -391,24 +377,58 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
391
  'sticky' => FILTER_SANITIZE_STRING,
392
  'action' => FILTER_SANITIZE_STRING,
393
  '_inline_edit' => FILTER_SANITIZE_STRING,
 
 
394
  );
395
 
396
  // Filter $_POST array for security.
397
  $post_array = filter_input_array( INPUT_POST, $filter_input_args );
398
 
 
 
 
 
 
399
  // Verify nonce.
400
- if ( isset( $post_array['_wpnonce'] )
 
401
  && isset( $post_array['post_ID'] )
402
- && wp_verify_nonce( $post_array['_wpnonce'], 'update-post_' . $post_array['post_ID'] ) ) {
 
403
  // Edit Post Screen.
404
  $original = isset( $post_array['original_post_status'] ) ? $post_array['original_post_status'] : '';
405
  $this->trigger_post_change_alerts( $old_status, $new_status, $post, $original, isset( $post_array['sticky'] ) );
406
- } elseif ( isset( $post_array['_inline_edit'] )
 
407
  && 'inline-save' === $post_array['action']
408
- && wp_verify_nonce( $post_array['_inline_edit'], 'inlineeditnonce' ) ) {
 
409
  // Quick Post Edit.
410
  $original = isset( $post_array['original_post_status'] ) ? $post_array['original_post_status'] : '';
411
  $this->trigger_post_change_alerts( $old_status, $new_status, $post, $original, isset( $post_array['sticky'] ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
412
  }
413
  }
414
 
@@ -417,12 +437,13 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
417
  *
418
  * @param string $old_status - Old status.
419
  * @param string $new_status - New status.
420
- * @param stdClass $post - The post.
421
- * @param string $original - Original Post Status.
422
- * @param string $sticky - Sticky post.
 
423
  * @since 1.0.0
424
  */
425
- public function trigger_post_change_alerts( $old_status, $new_status, $post, $original, $sticky ) {
426
  WSAL_Sensors_Request::SetVars(
427
  array(
428
  '$new_status' => $new_status,
@@ -431,7 +452,7 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
431
  )
432
  );
433
  // Run checks.
434
- if ( $this->_old_post ) {
435
  if ( $this->CheckOtherSensors( $this->_old_post ) ) {
436
  return;
437
  }
@@ -453,6 +474,46 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
453
  + $this->CheckPermalinkChange( $this->_old_link, get_permalink( $post->ID ), $post )
454
  + $this->CheckCommentsPings( $this->_old_post, $post );
455
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
456
  $this->CheckModificationChange( $post->ID, $this->_old_post, $post, $changes );
457
  }
458
  }
@@ -474,6 +535,13 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
474
  // Filter $_POST array for security.
475
  $post_array = filter_input_array( INPUT_POST, $filter_input_args );
476
 
 
 
 
 
 
 
 
477
  /**
478
  * Nonce is already verified at this point.
479
  *
@@ -574,17 +642,24 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
574
  return;
575
  }
576
 
 
 
 
 
 
 
 
 
577
  // Verify nonce.
578
  if ( isset( $get_array['_wpnonce'] ) && wp_verify_nonce( $get_array['_wpnonce'], 'delete-post_' . $post_id ) ) {
579
  $wp_actions = array( 'delete' );
580
- if ( isset( $get_array['action'] ) && in_array( $get_array['action'], $wp_actions ) ) {
581
- if ( ! in_array( $post->post_type, array( 'attachment', 'revision', 'nav_menu_item' ) ) ) { // Ignore attachments, revisions and menu items.
582
  $event = 2008;
583
  // Check WordPress backend operations.
584
  if ( $this->CheckAutoDraft( $event, $post->post_title ) ) {
585
  return;
586
  }
587
- $editor_link = $this->GetEditorLink( $post );
588
  $this->plugin->alerts->Trigger(
589
  $event, array(
590
  'PostID' => $post->ID,
@@ -597,6 +672,28 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
597
  );
598
  }
599
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
600
  }
601
  }
602
 
@@ -1065,6 +1162,14 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1065
  return 0; // Return if any Yoast alert has or will trigger.
1066
  }
1067
  }
 
 
 
 
 
 
 
 
1068
  }
1069
 
1070
  $editor_link = $this->GetEditorLink( $oldpost );
@@ -1416,77 +1521,74 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1416
  public function ViewingPost() {
1417
  // Retrieve the current post object.
1418
  $post = get_queried_object();
1419
- if ( is_user_logged_in() ) {
1420
- if ( ! is_admin() ) {
1421
- if ( $this->CheckOtherSensors( $post ) ) {
1422
- return $post->post_title;
1423
- }
1424
 
1425
- // Filter $_SERVER array for security.
1426
- $server_array = filter_input_array( INPUT_SERVER );
1427
 
1428
- $current_path = isset( $server_array['REQUEST_URI'] ) ? $server_array['REQUEST_URI'] : false;
1429
- if ( ! empty( $server_array['HTTP_REFERER'] )
1430
- && ! empty( $current_path )
1431
- && strpos( $server_array['HTTP_REFERER'], $current_path ) !== false ) {
1432
- // Ignore this if we were on the same page so we avoid double audit entries.
1433
- return;
1434
- }
1435
- if ( ! empty( $post->post_title ) ) {
1436
- $editor_link = $this->GetEditorLink( $post );
1437
- $this->plugin->alerts->Trigger(
1438
- 2101, array(
1439
- 'PostID' => $post->ID,
1440
- 'PostType' => $post->post_type,
1441
- 'PostTitle' => $post->post_title,
1442
- 'PostStatus' => $post->post_status,
1443
- 'PostDate' => $post->post_date,
1444
- 'PostUrl' => get_permalink( $post->ID ),
1445
- $editor_link['name'] => $editor_link['value'],
1446
- )
1447
- );
1448
- }
1449
  }
1450
  }
1451
  }
1452
 
1453
  /**
1454
- * Alerts for Editing of Posts, Pages and Custom Posts.
1455
  *
1456
  * @param stdClass $post - Post.
1457
  */
1458
  public function EditingPost( $post ) {
1459
- if ( is_user_logged_in() ) {
1460
- if ( is_admin() ) {
1461
- if ( $this->CheckOtherSensors( $post ) ) {
1462
- return $post;
1463
- }
1464
 
1465
- // Filter $_SERVER array for security.
1466
- $server_array = filter_input_array( INPUT_SERVER );
1467
 
1468
- $current_path = isset( $server_array['SCRIPT_NAME'] ) ? $server_array['SCRIPT_NAME'] . '?post=' . $post->ID : false;
1469
- if ( ! empty( $server_array['HTTP_REFERER'] )
1470
- && strpos( $server_array['HTTP_REFERER'], $current_path ) !== false ) {
1471
- // Ignore this if we were on the same page so we avoid double audit entries.
1472
- return $post;
1473
- }
1474
- if ( ! empty( $post->post_title ) ) {
1475
- $event = 2100;
1476
- if ( ! $this->WasTriggered( $event ) ) {
1477
- $editor_link = $this->GetEditorLink( $post );
1478
- $this->plugin->alerts->Trigger(
1479
- $event, array(
1480
- 'PostID' => $post->ID,
1481
- 'PostType' => $post->post_type,
1482
- 'PostTitle' => $post->post_title,
1483
- 'PostStatus' => $post->post_status,
1484
- 'PostDate' => $post->post_date,
1485
- 'PostUrl' => get_permalink( $post->ID ),
1486
- $editor_link['name'] => $editor_link['value'],
1487
- )
1488
- );
1489
- }
1490
  }
1491
  }
1492
  }
@@ -1616,6 +1718,55 @@ class WSAL_Sensors_Content extends WSAL_AbstractSensor {
1616
  return $event;
1617
  }
1618
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1619
  /**
1620
  * Get editor link.
1621
  *
19
  * 2000 User created a new blog post and saved it as draft
20
  * 2001 User published a blog post
21
  * 2002 User modified a published blog post
 
22
  * 2008 User permanently deleted a blog post from the trash
23
  * 2012 User moved a blog post to the trash
24
  * 2014 User restored a blog post from trash
30
  * 2024 User deleted category
31
  * 2025 User changed the visibility of a blog post
32
  * 2027 User changed the date of a blog post
33
+ * 2047 User changed the parent of a page
34
+ * 2048 User changed the template of a page
35
  * 2049 User set a post as sticky
36
  * 2050 User removed post from sticky
37
  * 2052 User changed generic tables
38
  * 2065 User modified content for a published post
 
 
39
  * 2073 User submitted a post for review
40
  * 2074 User scheduled a post
41
  * 2086 User changed title of a post
43
  * 2101 User viewed a post
44
  * 2111 User disabled Comments/Trackbacks and Pingbacks on a published post
45
  * 2112 User enabled Comments/Trackbacks and Pingbacks on a published post
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  * 2119 User added blog post tag
47
  * 2120 User removed blog post tag
48
  * 2121 User created new tag
120
  add_filter( 'post_edit_form_tag', array( $this, 'EditingPost' ), 10, 1 );
121
 
122
  add_filter( 'wp_update_term_data', array( $this, 'event_terms_rename' ), 10, 4 );
123
+
124
+ // Check if MainWP Child Plugin exists.
125
+ if ( is_plugin_active( 'mainwp-child/mainwp-child.php' ) ) {
126
+ add_action( 'mainwp_before_post_update', array( $this, 'event_mainwp_init' ), 10, 2 );
127
+ }
128
  }
129
 
130
  /**
269
  }
270
  }
271
 
272
+ /**
273
+ * Method: Collect old post data before MainWP Post update event.
274
+ *
275
+ * @param array $new_post - Array of new post data.
276
+ * @param array $post_custom - Array of data related to MainWP.
277
+ */
278
+ public function event_mainwp_init( $new_post, $post_custom ) {
279
+ // Get post id.
280
+ $post_id = isset( $post_custom['_mainwp_edit_post_id'][0] ) ? $post_custom['_mainwp_edit_post_id'][0] : false;
281
+
282
+ // Check if ID exists.
283
+ if ( $post_id ) {
284
+ // Get post.
285
+ $post = get_post( $post_id );
286
+
287
+ // If post exists.
288
+ if ( ! empty( $post ) ) {
289
+ $this->_old_post = $post;
290
+ $this->_old_link = get_permalink( $post_id );
291
+ $this->_old_tmpl = $this->GetPostTemplate( $this->_old_post );
292
+ $this->_old_cats = $this->GetPostCategories( $this->_old_post );
293
+ $this->_old_tags = $this->get_post_tags( $this->_old_post );
294
+ $this->_old_stky = in_array( $post_id, get_option( 'sticky_posts' ) );
295
+ }
296
+ }
297
+ }
298
+
299
  /**
300
  * Get the template path.
301
  *
377
  'sticky' => FILTER_SANITIZE_STRING,
378
  'action' => FILTER_SANITIZE_STRING,
379
  '_inline_edit' => FILTER_SANITIZE_STRING,
380
+ 'mainwpsignature' => FILTER_SANITIZE_STRING,
381
+ 'function' => FILTER_SANITIZE_STRING,
382
  );
383
 
384
  // Filter $_POST array for security.
385
  $post_array = filter_input_array( INPUT_POST, $filter_input_args );
386
 
387
+ // Check MainWP $_POST members.
388
+ $new_post = filter_input( INPUT_POST, 'new_post' );
389
+ $post_custom = filter_input( INPUT_POST, 'post_custom' );
390
+ $post_custom = maybe_unserialize( base64_decode( $post_custom ) );
391
+
392
  // Verify nonce.
393
+ if (
394
+ isset( $post_array['_wpnonce'] )
395
  && isset( $post_array['post_ID'] )
396
+ && wp_verify_nonce( $post_array['_wpnonce'], 'update-post_' . $post_array['post_ID'] )
397
+ ) {
398
  // Edit Post Screen.
399
  $original = isset( $post_array['original_post_status'] ) ? $post_array['original_post_status'] : '';
400
  $this->trigger_post_change_alerts( $old_status, $new_status, $post, $original, isset( $post_array['sticky'] ) );
401
+ } elseif (
402
+ isset( $post_array['_inline_edit'] )
403
  && 'inline-save' === $post_array['action']
404
+ && wp_verify_nonce( $post_array['_inline_edit'], 'inlineeditnonce' )
405
+ ) {
406
  // Quick Post Edit.
407
  $original = isset( $post_array['original_post_status'] ) ? $post_array['original_post_status'] : '';
408
  $this->trigger_post_change_alerts( $old_status, $new_status, $post, $original, isset( $post_array['sticky'] ) );
409
+ } elseif (
410
+ isset( $post_array['mainwpsignature'] )
411
+ && ! empty( $new_post )
412
+ && ! empty( $post_custom )
413
+ ) {
414
+ // Check sticky post.
415
+ $sticky = false;
416
+ if ( isset( $post_custom['_sticky'] ) && is_array( $post_custom['_sticky'] ) ) {
417
+ foreach ( $post_custom['_sticky'] as $key => $meta_value ) {
418
+ if ( 'sticky' === base64_decode( $meta_value ) ) {
419
+ $sticky = true;
420
+ }
421
+ }
422
+ }
423
+ $this->trigger_post_change_alerts( $old_status, $new_status, $post, false, $sticky, 'mainwp' );
424
+ } elseif (
425
+ isset( $post_array['mainwpsignature'] )
426
+ && isset( $post_array['function'] )
427
+ && 'post_action' === $post_array['function']
428
+ && isset( $post_array['action'] )
429
+ && ( 'unpublish' === $post_array['action'] || 'publish' === $post_array['action'] )
430
+ ) {
431
+ $this->check_mainwp_status_change( $post, $old_status, $new_status );
432
  }
433
  }
434
 
437
  *
438
  * @param string $old_status - Old status.
439
  * @param string $new_status - New status.
440
+ * @param stdClass $post - The post.
441
+ * @param string $original - Original Post Status.
442
+ * @param string $sticky - Sticky post.
443
+ * @param string $dashboard - Dashboard from which the change is coming from.
444
  * @since 1.0.0
445
  */
446
+ public function trigger_post_change_alerts( $old_status, $new_status, $post, $original, $sticky, $dashboard = false ) {
447
  WSAL_Sensors_Request::SetVars(
448
  array(
449
  '$new_status' => $new_status,
452
  )
453
  );
454
  // Run checks.
455
+ if ( $this->_old_post && ! $dashboard ) { // Change is coming from WP Dashboard.
456
  if ( $this->CheckOtherSensors( $this->_old_post ) ) {
457
  return;
458
  }
474
  + $this->CheckPermalinkChange( $this->_old_link, get_permalink( $post->ID ), $post )
475
  + $this->CheckCommentsPings( $this->_old_post, $post );
476
 
477
+ $this->CheckModificationChange( $post->ID, $this->_old_post, $post, $changes );
478
+ }
479
+ } elseif ( ! $this->_old_post && 'mainwp' === $dashboard ) {
480
+ if ( $this->CheckOtherSensors( $this->_old_post ) ) {
481
+ return;
482
+ }
483
+ if ( 'auto-draft' === $old_status ) {
484
+ // Handle create post events.
485
+ $this->CheckPostCreation( $this->_old_post, $post );
486
+ }
487
+ } elseif ( $this->_old_post && 'mainwp' === $dashboard ) {
488
+ if ( 'auto-draft' === $old_status ) {
489
+ // Get MainWP $_POST members.
490
+ $new_post = filter_input( INPUT_POST, 'new_post' );
491
+ $new_post = maybe_unserialize( base64_decode( $new_post ) );
492
+ $post_catgs = filter_input( INPUT_POST, 'post_category' );
493
+
494
+ // Post categories.
495
+ $post_categories = rawurldecode( isset( $post_catgs ) ? base64_decode( $post_catgs ) : null );
496
+ $post_categories = explode( ',', $post_categories );
497
+
498
+ // Post tags.
499
+ $post_tags = rawurldecode( isset( $new_post['post_tags'] ) ? $new_post['post_tags'] : null );
500
+ $post_tags = str_replace( ' ', '', $post_tags );
501
+ $post_tags = explode( ',', $post_tags );
502
+
503
+ // Handle update post events.
504
+ $changes = 0;
505
+ $changes = $this->CheckAuthorChange( $this->_old_post, $post )
506
+ + $this->CheckStatusChange( $this->_old_post, $post )
507
+ + $this->CheckParentChange( $this->_old_post, $post )
508
+ + $this->CheckStickyChange( $this->_old_stky, $sticky, $post )
509
+ + $this->CheckVisibilityChange( $this->_old_post, $post, $old_status, $new_status )
510
+ + $this->CheckTemplateChange( $this->_old_tmpl, $this->GetPostTemplate( $post ), $post )
511
+ + $this->CheckCategoriesChange( $this->_old_cats, $post_categories, $post )
512
+ + $this->check_tags_change( $this->_old_tags, $post_tags, $post )
513
+ + $this->CheckDateChange( $this->_old_post, $post )
514
+ + $this->CheckPermalinkChange( $this->_old_link, get_permalink( $post->ID ), $post )
515
+ + $this->CheckCommentsPings( $this->_old_post, $post );
516
+
517
  $this->CheckModificationChange( $post->ID, $this->_old_post, $post, $changes );
518
  }
519
  }
535
  // Filter $_POST array for security.
536
  $post_array = filter_input_array( INPUT_POST, $filter_input_args );
537
 
538
+ // Check if the post is coming from MainWP.
539
+ $mainwp = filter_input( INPUT_POST, 'mainwpsignature', FILTER_SANITIZE_STRING );
540
+
541
+ if ( ! empty( $mainwp ) ) {
542
+ $post_array['action'] = 'editpost';
543
+ }
544
+
545
  /**
546
  * Nonce is already verified at this point.
547
  *
642
  return;
643
  }
644
 
645
+ // Get MainWP $_POST members.
646
+ $filter_post_args = array(
647
+ 'id' => FILTER_VALIDATE_INT,
648
+ 'action' => FILTER_SANITIZE_STRING,
649
+ 'mainwpsignature' => FILTER_SANITIZE_STRING,
650
+ );
651
+ $post_array = filter_input_array( INPUT_POST, $filter_post_args );
652
+
653
  // Verify nonce.
654
  if ( isset( $get_array['_wpnonce'] ) && wp_verify_nonce( $get_array['_wpnonce'], 'delete-post_' . $post_id ) ) {
655
  $wp_actions = array( 'delete' );
656
+ if ( isset( $get_array['action'] ) && in_array( $get_array['action'], $wp_actions, true ) ) {
657
+ if ( ! in_array( $post->post_type, array( 'attachment', 'revision', 'nav_menu_item' ), true ) ) { // Ignore attachments, revisions and menu items.
658
  $event = 2008;
659
  // Check WordPress backend operations.
660
  if ( $this->CheckAutoDraft( $event, $post->post_title ) ) {
661
  return;
662
  }
 
663
  $this->plugin->alerts->Trigger(
664
  $event, array(
665
  'PostID' => $post->ID,
672
  );
673
  }
674
  }
675
+ } elseif (
676
+ isset( $post_array['mainwpsignature'] )
677
+ && isset( $post_array['action'] )
678
+ && 'delete' === $post_array['action']
679
+ && ! empty( $post_array['id'] )
680
+ ) {
681
+ if ( ! in_array( $post->post_type, array( 'attachment', 'revision', 'nav_menu_item' ), true ) ) { // Ignore attachments, revisions and menu items.
682
+ // Check WordPress backend operations.
683
+ if ( $this->CheckAutoDraft( 2008, $post->post_title ) ) {
684
+ return;
685
+ }
686
+ $this->plugin->alerts->Trigger(
687
+ 2008, array(
688
+ 'PostID' => $post->ID,
689
+ 'PostType' => $post->post_type,
690
+ 'PostTitle' => $post->post_title,
691
+ 'PostStatus' => $post->post_status,
692
+ 'PostDate' => $post->post_date,
693
+ 'PostUrl' => get_permalink( $post->ID ),
694
+ )
695
+ );
696
+ }
697
  }
698
  }
699
 
1162
  return 0; // Return if any Yoast alert has or will trigger.
1163
  }
1164
  }
1165
+
1166
+ // Get post meta events.
1167
+ $meta_events = array( 2053, 2054, 2055, 2062 );
1168
+ foreach ( $meta_events as $meta_event ) {
1169
+ if ( $this->plugin->alerts->WillOrHasTriggered( $meta_event ) ) {
1170
+ return 0; // Return if any meta event has or will trigger.
1171
+ }
1172
+ }
1173
  }
1174
 
1175
  $editor_link = $this->GetEditorLink( $oldpost );
1521
  public function ViewingPost() {
1522
  // Retrieve the current post object.
1523
  $post = get_queried_object();
1524
+ if ( is_user_logged_in() && ! is_admin() ) {
1525
+ if ( $this->CheckOtherSensors( $post ) ) {
1526
+ return $post->post_title;
1527
+ }
 
1528
 
1529
+ // Filter $_SERVER array for security.
1530
+ $server_array = filter_input_array( INPUT_SERVER );
1531
 
1532
+ $current_path = isset( $server_array['REQUEST_URI'] ) ? $server_array['REQUEST_URI'] : false;
1533
+ if ( ! empty( $server_array['HTTP_REFERER'] )
1534
+ && ! empty( $current_path )
1535
+ && strpos( $server_array['HTTP_REFERER'], $current_path ) !== false ) {
1536
+ // Ignore this if we were on the same page so we avoid double audit entries.
1537
+ return;
1538
+ }
1539
+ if ( ! empty( $post->post_title ) ) {
1540
+ $editor_link = $this->GetEditorLink( $post );
1541
+ $this->plugin->alerts->Trigger(
1542
+ 2101, array(
1543
+ 'PostID' => $post->ID,
1544
+ 'PostType' => $post->post_type,
1545
+ 'PostTitle' => $post->post_title,
1546
+ 'PostStatus' => $post->post_status,
1547
+ 'PostDate' => $post->post_date,
1548
+ 'PostUrl' => get_permalink( $post->ID ),
1549
+ $editor_link['name'] => $editor_link['value'],
1550
+ )
1551
+ );
 
1552
  }
1553
  }
1554
  }
1555
 
1556
  /**
1557
+ * Alerts for Editing of Posts, Pages and Custom Post Types.
1558
  *
1559
  * @param stdClass $post - Post.
1560
  */
1561
  public function EditingPost( $post ) {
1562
+ if ( is_user_logged_in() && is_admin() ) {
1563
+ // Check ignored post types.
1564
+ if ( $this->CheckOtherSensors( $post ) ) {
1565
+ return $post;
1566
+ }
1567
 
1568
+ // Filter $_SERVER array for security.
1569
+ $server_array = filter_input_array( INPUT_SERVER );
1570
 
1571
+ $current_path = isset( $server_array['SCRIPT_NAME'] ) ? $server_array['SCRIPT_NAME'] . '?post=' . $post->ID : false;
1572
+ if ( ! empty( $server_array['HTTP_REFERER'] )
1573
+ && strpos( $server_array['HTTP_REFERER'], $current_path ) !== false ) {
1574
+ // Ignore this if we were on the same page so we avoid double audit entries.
1575
+ return $post;
1576
+ }
1577
+ if ( ! empty( $post->post_title ) ) {
1578
+ $event = 2100;
1579
+ if ( ! $this->WasTriggered( $event ) ) {
1580
+ $editor_link = $this->GetEditorLink( $post );
1581
+ $this->plugin->alerts->Trigger(
1582
+ $event, array(
1583
+ 'PostID' => $post->ID,
1584
+ 'PostType' => $post->post_type,
1585
+ 'PostTitle' => $post->post_title,
1586
+ 'PostStatus' => $post->post_status,
1587
+ 'PostDate' => $post->post_date,
1588
+ 'PostUrl' => get_permalink( $post->ID ),
1589
+ $editor_link['name'] => $editor_link['value'],
1590
+ )
1591
+ );
 
1592
  }
1593
  }
1594
  }
1718
  return $event;
1719
  }
1720
 
1721
+ /**
1722
+ * Method: Check status change of a post from MainWP Dashboard.
1723
+ *
1724
+ * @param WP_Post $post - WP_Post object.
1725
+ * @param string $old_status - Old post status.
1726
+ * @param string $new_status - New post status.
1727
+ * @since 3.2.2
1728
+ */
1729
+ private function check_mainwp_status_change( $post, $old_status, $new_status ) {
1730
+ // Verify function arguments.
1731
+ if ( empty( $post ) || ! $post instanceof WP_Post || empty( $old_status ) || empty( $new_status ) ) {
1732
+ return;
1733
+ }
1734
+
1735
+ // Check to see if old & new statuses don't match.
1736
+ if ( $old_status !== $new_status ) {
1737
+ if ( 'publish' === $new_status ) {
1738
+ // Special case (publishing a post).
1739
+ $editor_link = $this->GetEditorLink( $post );
1740
+ $this->plugin->alerts->Trigger(
1741
+ 2001, array(
1742
+ 'PostID' => $post->ID,
1743
+ 'PostType' => $post->post_type,
1744
+ 'PostTitle' => $post->post_title,
1745
+ 'PostStatus' => $post->post_status,
1746
+ 'PostDate' => $post->post_date,
1747
+ 'PostUrl' => get_permalink( $post->ID ),
1748
+ $editor_link['name'] => $editor_link['value'],
1749
+ )
1750
+ );
1751
+ } else {
1752
+ $editor_link = $this->GetEditorLink( $post );
1753
+ $this->plugin->alerts->Trigger(
1754
+ 2021, array(
1755
+ 'PostID' => $post->ID,
1756
+ 'PostType' => $post->post_type,
1757
+ 'PostTitle' => $post->post_title,
1758
+ 'PostStatus' => $post->post_status,
1759
+ 'PostDate' => $post->post_date,
1760
+ 'PostUrl' => get_permalink( $post->ID ),
1761
+ 'OldStatus' => $old_status,
1762
+ 'NewStatus' => $new_status,
1763
+ $editor_link['name'] => $editor_link['value'],
1764
+ )
1765
+ );
1766
+ }
1767
+ }
1768
+ }
1769
+
1770
  /**
1771
  * Get editor link.
1772
  *
classes/Sensors/Database.php CHANGED
@@ -176,9 +176,10 @@ class WSAL_Sensors_Database extends WSAL_AbstractSensor {
176
  // Action Plugin Component.
177
  $alert_options = array();
178
  if ( $is_plugins ) {
 
179
  if ( isset( $get_array['plugin'] ) ) {
180
  $plugin_file = $get_array['plugin'];
181
- } else {
182
  $plugin_file = $get_array['checked'][0];
183
  }
184
  $plugin_name = basename( $plugin_file, '.php' );
@@ -189,9 +190,10 @@ class WSAL_Sensors_Database extends WSAL_AbstractSensor {
189
  );
190
  // Action Theme Component.
191
  } elseif ( $is_themes ) {
 
192
  if ( isset( $get_array['theme'] ) ) {
193
  $theme_name = $get_array['theme'];
194
- } else {
195
  $theme_name = $get_array['checked'][0];
196
  }
197
  $theme_name = str_replace( array( '_', '-', ' ' ), ' ', $theme_name );
176
  // Action Plugin Component.
177
  $alert_options = array();
178
  if ( $is_plugins ) {
179
+ $plugin_file = '';
180
  if ( isset( $get_array['plugin'] ) ) {
181
  $plugin_file = $get_array['plugin'];
182
+ } elseif ( isset( $get_array['checked'] ) ) {
183
  $plugin_file = $get_array['checked'][0];
184
  }
185
  $plugin_name = basename( $plugin_file, '.php' );
190
  );
191
  // Action Theme Component.
192
  } elseif ( $is_themes ) {
193
+ $theme_name = '';
194
  if ( isset( $get_array['theme'] ) ) {
195
  $theme_name = $get_array['theme'];
196
+ } elseif ( isset( $get_array['checked'] ) ) {
197
  $theme_name = $get_array['checked'][0];
198
  }
199
  $theme_name = str_replace( array( '_', '-', ' ' ), ' ', $theme_name );
classes/Sensors/FileChanges.php CHANGED
@@ -118,6 +118,11 @@ class WSAL_Sensors_FileChanges extends WSAL_AbstractSensor {
118
  * Listening to events using WP hooks.
119
  */
120
  public function HookEvents() {
 
 
 
 
 
121
  // Filter stored and scanned files to balance scan file exclusion.
122
  add_filter( 'wsal_file_scan_stored_files', array( $this, 'filter_scan_files' ), 10, 2 );
123
  add_filter( 'wsal_file_scan_scanned_files', array( $this, 'filter_scan_files' ), 10, 2 );
@@ -155,6 +160,7 @@ class WSAL_Sensors_FileChanges extends WSAL_AbstractSensor {
155
  'scan_day' => $this->plugin->GetGlobalOption( 'scan-day', '1' ),
156
  'scan_date' => $this->plugin->GetGlobalOption( 'scan-date', '10' ),
157
  'scan_directories' => $this->plugin->GetGlobalOption( 'scan-directories', $default_scan_dirs ),
 
158
  'excluded_extensions' => $this->plugin->GetGlobalOption( 'scan-excluded-extensions', array( 'jpg', 'jpeg', 'png', 'bmp', 'pdf', 'txt', 'log', 'mo', 'po', 'mp3', 'wav' ) ),
159
  'excluded_files' => $this->plugin->GetGlobalOption( 'scan_excluded_files', array() ),
160
  'last_scanned' => $this->plugin->GetGlobalOption( 'last-scanned', false ),
@@ -378,6 +384,17 @@ class WSAL_Sensors_FileChanges extends WSAL_AbstractSensor {
378
 
379
  // Log the alert.
380
  foreach ( $files_added as $file => $file_hash ) {
 
 
 
 
 
 
 
 
 
 
 
381
  // Get filename from file path.
382
  $filename = basename( $file );
383
 
@@ -410,6 +427,14 @@ class WSAL_Sensors_FileChanges extends WSAL_AbstractSensor {
410
  if ( count( $files_removed ) > 0 ) {
411
  // Log the alert.
412
  foreach ( $files_removed as $file => $file_hash ) {
 
 
 
 
 
 
 
 
413
  // Get filename from file path.
414
  $filename = basename( $file );
415
 
@@ -565,6 +590,11 @@ class WSAL_Sensors_FileChanges extends WSAL_AbstractSensor {
565
  continue;
566
  }
567
 
 
 
 
 
 
568
  // If not multisite then simply scan.
569
  if ( ! $is_multisite ) {
570
  $files = array_merge( $files, $this->scan_path( $relative_name ) );
@@ -615,8 +645,8 @@ class WSAL_Sensors_FileChanges extends WSAL_AbstractSensor {
615
  break; // And break the loop.
616
  }
617
 
618
- // 2MB = 2097152 bytes.
619
- if ( filesize( $absolute_name ) < 2097152 ) { // Check if file size is less than 2MB.
620
  $this->scan_file_count = $this->scan_file_count + 1;
621
  // File data.
622
  $files[ $absolute_name ] = @md5_file( $absolute_name ); // File hash.
@@ -997,9 +1027,10 @@ class WSAL_Sensors_FileChanges extends WSAL_AbstractSensor {
997
 
998
  // Check if the option is instance of stdClass.
999
  if ( false !== $site_content && $site_content instanceof stdClass ) {
1000
- $site_content->skip_core = false; // Reset skip core after the scan is complete.
1001
- $site_content->skip_files = array(); // Empty the skip files at the end of the scan.
1002
- $site_content->skip_extensions = array(); // Empty the skip extensions at the end of the scan.
 
1003
  $this->plugin->SetGlobalOption( 'site_content', $site_content ); // Save the option.
1004
  }
1005
  }
118
  * Listening to events using WP hooks.
119
  */
120
  public function HookEvents() {
121
+ // Disable the sensor if file changes is disabled.
122
+ if ( isset( $this->scan_settings['scan_file_changes'] ) && 'enable' !== $this->scan_settings['scan_file_changes'] ) {
123
+ return;
124
+ }
125
+
126
  // Filter stored and scanned files to balance scan file exclusion.
127
  add_filter( 'wsal_file_scan_stored_files', array( $this, 'filter_scan_files' ), 10, 2 );
128
  add_filter( 'wsal_file_scan_scanned_files', array( $this, 'filter_scan_files' ), 10, 2 );
160
  'scan_day' => $this->plugin->GetGlobalOption( 'scan-day', '1' ),
161
  'scan_date' => $this->plugin->GetGlobalOption( 'scan-date', '10' ),
162
  'scan_directories' => $this->plugin->GetGlobalOption( 'scan-directories', $default_scan_dirs ),
163
+ 'excluded_dirs' => $this->plugin->GetGlobalOption( 'scan-excluded-directories', array() ),
164
  'excluded_extensions' => $this->plugin->GetGlobalOption( 'scan-excluded-extensions', array( 'jpg', 'jpeg', 'png', 'bmp', 'pdf', 'txt', 'log', 'mo', 'po', 'mp3', 'wav' ) ),
165
  'excluded_files' => $this->plugin->GetGlobalOption( 'scan_excluded_files', array() ),
166
  'last_scanned' => $this->plugin->GetGlobalOption( 'last-scanned', false ),
384
 
385
  // Log the alert.
386
  foreach ( $files_added as $file => $file_hash ) {
387
+ // Get directory name.
388
+ $directory_name = dirname( $file );
389
+
390
+ // Check if the directory is in excluded directories list.
391
+ if (
392
+ ! empty( $site_content->skip_directories )
393
+ && in_array( $directory_name, $site_content->skip_directories, true )
394
+ ) {
395
+ continue; // If true, then skip the loop.
396
+ }
397
+
398
  // Get filename from file path.
399
  $filename = basename( $file );
400
 
427
  if ( count( $files_removed ) > 0 ) {
428
  // Log the alert.
429
  foreach ( $files_removed as $file => $file_hash ) {
430
+ // Get directory name.
431
+ $directory_name = dirname( $file );
432
+
433
+ // Check if directory is in excluded directories list.
434
+ if ( in_array( $directory_name, $this->scan_settings['excluded_dirs'], true ) ) {
435
+ continue; // If true, then skip the loop.
436
+ }
437
+
438
  // Get filename from file path.
439
  $filename = basename( $file );
440
 
590
  continue;
591
  }
592
 
593
+ // Check if the directory is in excluded directories list.
594
+ if ( in_array( $absolute_name, $this->scan_settings['excluded_dirs'], true ) ) {
595
+ continue; // Skip the directory.
596
+ }
597
+
598
  // If not multisite then simply scan.
599
  if ( ! $is_multisite ) {
600
  $files = array_merge( $files, $this->scan_path( $relative_name ) );
645
  break; // And break the loop.
646
  }
647
 
648
+ // 5MB = 5242880 bytes.
649
+ if ( filesize( $absolute_name ) < 5242880 ) { // Check if file size is less than 5MB.
650
  $this->scan_file_count = $this->scan_file_count + 1;
651
  // File data.
652
  $files[ $absolute_name ] = @md5_file( $absolute_name ); // File hash.
1027
 
1028
  // Check if the option is instance of stdClass.
1029
  if ( false !== $site_content && $site_content instanceof stdClass ) {
1030
+ $site_content->skip_core = false; // Reset skip core after the scan is complete.
1031
+ $site_content->skip_files = array(); // Empty the skip files at the end of the scan.
1032
+ $site_content->skip_extensions = array(); // Empty the skip extensions at the end of the scan.
1033
+ $site_content->skip_directories = array(); // Empty the skip directories at the end of the scan.
1034
  $this->plugin->SetGlobalOption( 'site_content', $site_content ); // Save the option.
1035
  }
1036
  }
classes/Sensors/MetaData.php CHANGED
@@ -132,12 +132,15 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
132
  * @param mix $meta_value - Meta value.
133
  */
134
  public function EventPostMetaCreated( $object_id, $meta_key, $meta_value ) {
135
- $post = get_post( $object_id );
136
  if ( ! $this->CanLogMetaKey( $object_id, $meta_key ) || is_array( $meta_value ) ) {
137
  return;
138
  }
139
 
140
- if ( 'revision' == $post->post_type ) {
 
 
 
 
141
  return;
142
  }
143
 
@@ -157,9 +160,29 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
157
  return false;
158
  }
159
 
 
160
  $wp_action = array( 'add-meta' );
161
 
162
- if ( isset( $post_array['action'] ) && ( 'editpost' == $post_array['action'] || in_array( $post_array['action'], $wp_action ) ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  $editor_link = $this->GetEditorLink( $post );
164
  $this->plugin->alerts->Trigger(
165
  2053, array(
@@ -202,15 +225,36 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
202
  * @param mix $meta_value - Meta value.
203
  */
204
  public function EventPostMetaUpdated( $meta_id, $object_id, $meta_key, $meta_value ) {
205
- $post = get_post( $object_id );
206
  if ( ! $this->CanLogMetaKey( $object_id, $meta_key ) || is_array( $meta_value ) ) {
207
  return;
208
  }
209
 
210
- if ( 'revision' == $post->post_type ) {
 
 
 
 
211
  return;
212
  }
213
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  // Filter $_POST global array for security.
215
  $post_array = filter_input_array( INPUT_POST );
216
 
@@ -221,9 +265,29 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
221
  return false;
222
  }
223
 
 
224
  $wp_action = array( 'add-meta' );
225
 
226
- if ( isset( $post_array['action'] ) && ( 'editpost' == $post_array['action'] || in_array( $post_array['action'], $wp_action ) ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
227
  $editor_link = $this->GetEditorLink( $post );
228
  if ( isset( $this->old_meta[ $meta_id ] ) ) {
229
  // Check change in meta key.
@@ -278,14 +342,19 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
278
  * @param mix $meta_value - Meta value.
279
  */
280
  public function EventPostMetaDeleted( $meta_ids, $object_id, $meta_key, $meta_value ) {
281
-
282
  // If meta key starts with "_" then return.
283
  if ( '_' == substr( $meta_key, 0, 1 ) ) {
284
  return;
285
  }
286
 
 
287
  $post = get_post( $object_id );
288
 
 
 
 
 
 
289
  // Filter $_POST global array for security.
290
  $post_array = filter_input_array( INPUT_POST );
291
 
@@ -296,9 +365,26 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
296
  return false;
297
  }
298
 
 
299
  $wp_action = array( 'delete-meta' );
300
 
301
- if ( isset( $post_array['action'] ) && in_array( $post_array['action'], $wp_action ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
302
  $editor_link = $this->GetEditorLink( $post );
303
  foreach ( $meta_ids as $meta_id ) {
304
  if ( ! $this->CanLogMetaKey( $object_id, $meta_key ) ) {
@@ -356,7 +442,6 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
356
  * @param mix $meta_value - Meta value.
357
  */
358
  public function event_user_meta_created( $object_id, $meta_key, $meta_value ) {
359
-
360
  // Get user.
361
  $user = get_user_by( 'ID', $object_id );
362
 
@@ -415,7 +500,6 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
415
  * @param mix $meta_value - Meta value.
416
  */
417
  public function event_user_meta_updated( $meta_id, $object_id, $meta_key, $meta_value ) {
418
-
419
  // Get user.
420
  $user = get_user_by( 'ID', $object_id );
421
 
@@ -431,25 +515,31 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
431
  $post_array = filter_input_array( INPUT_POST );
432
 
433
  // If update action is set then trigger the alert.
434
- if ( ( isset( $post_array['_wpnonce'] ) // WP Dashboard Support.
435
- && wp_verify_nonce( $post_array['_wpnonce'], 'update-user_' . $user->ID )
436
- && isset( $post_array['action'] )
437
- && 'update' == $post_array['action'] )
438
- ||
439
- ( isset( $post_array['_um_account'] ) // Ultimate Member Plugin support.
440
- && '1' === $post_array['_um_account']
441
- && isset( $post_array['_um_account_tab'] )
442
- && 'general' === $post_array['_um_account_tab'] )
443
- ) {
 
 
 
 
 
 
444
  if ( isset( $this->old_meta[ $meta_id ] ) && ! in_array( $meta_key, $username_meta, true ) ) {
445
  // Check change in meta value.
446
  if ( $this->old_meta[ $meta_id ]->val != $meta_value ) {
447
  $this->plugin->alerts->Trigger(
448
  4015, array(
449
- 'TargetUsername' => $user->user_login,
450
  'custom_field_name' => $meta_key,
451
- 'new_value' => $meta_value,
452
- 'old_value' => $this->old_meta[ $meta_id ]->val,
453
  'ReportText' => $this->old_meta[ $meta_id ]->val . '|' . $meta_value,
454
  )
455
  );
@@ -464,8 +554,8 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
464
  $this->plugin->alerts->Trigger(
465
  4017, array(
466
  'TargetUsername' => $user->user_login,
467
- 'new_firstname' => $meta_value,
468
- 'old_firstname' => $this->old_meta[ $meta_id ]->val,
469
  )
470
  );
471
  }
@@ -476,8 +566,8 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
476
  $this->plugin->alerts->Trigger(
477
  4018, array(
478
  'TargetUsername' => $user->user_login,
479
- 'new_lastname' => $meta_value,
480
- 'old_lastname' => $this->old_meta[ $meta_id ]->val,
481
  )
482
  );
483
  }
@@ -488,8 +578,8 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
488
  $this->plugin->alerts->Trigger(
489
  4019, array(
490
  'TargetUsername' => $user->user_login,
491
- 'new_nickname' => $meta_value,
492
- 'old_nickname' => $this->old_meta[ $meta_id ]->val,
493
  )
494
  );
495
  }
@@ -510,7 +600,6 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
510
  * @since 2.6.9
511
  */
512
  public function event_userdata_updated( $user_id, $old_user_data ) {
513
-
514
  // Get user display name.
515
  $old_display_name = $old_user_data->display_name;
516
 
@@ -522,7 +611,7 @@ class WSAL_Sensors_MetaData extends WSAL_AbstractSensor {
522
  if ( $old_display_name !== $new_display_name ) {
523
  $this->plugin->alerts->Trigger(
524
  4020, array(
525
- 'TargetUsername' => $new_userdata->user_login,
526
  'new_displayname' => $new_display_name,
527
  'old_displayname' => $old_display_name,
528
  )
132
  * @param mix $meta_value - Meta value.
133
  */
134
  public function EventPostMetaCreated( $object_id, $meta_key, $meta_value ) {
 
135
  if ( ! $this->CanLogMetaKey( $object_id, $meta_key ) || is_array( $meta_value ) ) {
136
  return;
137
  }
138
 
139
+ // Get post object.
140
+ $post = get_post( $object_id );
141
+
142
+ // Return if the post object is null or the post type is revision.
143
+ if ( null === $post || 'revision' === $post->post_type ) {
144
  return;
145
  }
146
 
160
  return false;
161
  }
162
 
163
+ // WP Dashboard action.
164
  $wp_action = array( 'add-meta' );
165
 
166
+ // Check MainWP $_POST members.
167
+ $new_post = filter_input( INPUT_POST, 'new_post' );
168
+ $post_custom = filter_input( INPUT_POST, 'post_custom' );
169
+
170
+ // Check if the post is coming from MainWP.
171
+ $mainwp = filter_input( INPUT_POST, 'mainwpsignature', FILTER_SANITIZE_STRING );
172
+
173
+ if (
174
+ ( // Either coming from WP admin panel.
175
+ isset( $post_array['action'] )
176
+ && (
177
+ 'editpost' === $post_array['action']
178
+ || in_array( $post_array['action'], $wp_action, true )
179
+ )
180
+ ) || ( // OR from MainWP dashboard.
181
+ ! empty( $new_post )
182
+ && ! empty( $post_custom )
183
+ && ! empty( $mainwp )
184
+ )
185
+ ) {
186
  $editor_link = $this->GetEditorLink( $post );
187
  $this->plugin->alerts->Trigger(
188
  2053, array(
225
  * @param mix $meta_value - Meta value.
226
  */
227
  public function EventPostMetaUpdated( $meta_id, $object_id, $meta_key, $meta_value ) {
 
228
  if ( ! $this->CanLogMetaKey( $object_id, $meta_key ) || is_array( $meta_value ) ) {
229
  return;
230
  }
231
 
232
+ // Get post object.
233
+ $post = get_post( $object_id );
234
+
235
+ // Return if the post object is null or the post type is revision.
236
+ if ( null === $post || 'revision' === $post->post_type ) {
237
  return;
238
  }
239
 
240
+ /**
241
+ * WSAL Action Hook.
242
+ *
243
+ * Runs before logging events for post meta updated i.e. 2062 or 2054.
244
+ *
245
+ * This hook can be used to log events for updated post meta on the
246
+ * front-end since the plugin only supports events for updating post
247
+ * meta via wp admin panel.
248
+ *
249
+ * @param int $meta_id - Meta ID.
250
+ * @param int $object_id - Post ID.
251
+ * @param array $this->old_meta - Array of meta data holding keys & values of old meta data before updating the current post.
252
+ * @param string $meta_key - Meta key.
253
+ * @param mixed $meta_value - Meta value.
254
+ * @since 3.2.2
255
+ */
256
+ do_action( 'wsal_post_meta_updated', $meta_id, $object_id, $this->old_meta, $meta_key, $meta_value );
257
+
258
  // Filter $_POST global array for security.
259
  $post_array = filter_input_array( INPUT_POST );
260
 
265
  return false;
266
  }
267
 
268
+ // WP Dashboard action.
269
  $wp_action = array( 'add-meta' );
270
 
271
+ // Check MainWP $_POST members.
272
+ $new_post = filter_input( INPUT_POST, 'new_post' );
273
+ $post_custom = filter_input( INPUT_POST, 'post_custom' );
274
+
275
+ // Check if the post is coming from MainWP.
276
+ $mainwp = filter_input( INPUT_POST, 'mainwpsignature', FILTER_SANITIZE_STRING );
277
+
278
+ if (
279
+ (
280
+ isset( $post_array['action'] )
281
+ && (
282
+ 'editpost' === $post_array['action']
283
+ || in_array( $post_array['action'], $wp_action, true )
284
+ )
285
+ ) || (
286
+ ! empty( $new_post )
287
+ && ! empty( $post_custom )
288
+ && ! empty( $mainwp )
289
+ )
290
+ ) {
291
  $editor_link = $this->GetEditorLink( $post );
292
  if ( isset( $this->old_meta[ $meta_id ] ) ) {
293
  // Check change in meta key.
342
  * @param mix $meta_value - Meta value.
343
  */
344
  public function EventPostMetaDeleted( $meta_ids, $object_id, $meta_key, $meta_value ) {
 
345
  // If meta key starts with "_" then return.
346
  if ( '_' == substr( $meta_key, 0, 1 ) ) {
347
  return;
348
  }
349
 
350
+ // Get post object.
351
  $post = get_post( $object_id );
352
 
353
+ // Return if the post object is null.
354
+ if ( null === $post ) {
355
+ return;
356
+ }
357
+
358
  // Filter $_POST global array for security.
359
  $post_array = filter_input_array( INPUT_POST );
360
 
365
  return false;
366
  }
367
 
368
+ // WP Dashboard action.
369
  $wp_action = array( 'delete-meta' );
370
 
371
+ // Check MainWP $_POST members.
372
+ $new_post = filter_input( INPUT_POST, 'new_post' );
373
+ $post_custom = filter_input( INPUT_POST, 'post_custom' );
374
+
375
+ // Check if the post is coming from MainWP.
376
+ $mainwp = filter_input( INPUT_POST, 'mainwpsignature', FILTER_SANITIZE_STRING );
377
+
378
+ if (
379
+ (
380
+ isset( $post_array['action'] )
381
+ && in_array( $post_array['action'], $wp_action, true )
382
+ ) || (
383
+ ! empty( $new_post )
384
+ && ! empty( $post_custom )
385
+ && ! empty( $mainwp )
386
+ )
387
+ ) {
388
  $editor_link = $this->GetEditorLink( $post );
389
  foreach ( $meta_ids as $meta_id ) {
390
  if ( ! $this->CanLogMetaKey( $object_id, $meta_key ) ) {
442
  * @param mix $meta_value - Meta value.
443
  */
444
  public function event_user_meta_created( $object_id, $meta_key, $meta_value ) {
 
445
  // Get user.
446
  $user = get_user_by( 'ID', $object_id );
447
 
500
  * @param mix $meta_value - Meta value.
501
  */
502
  public function event_user_meta_updated( $meta_id, $object_id, $meta_key, $meta_value ) {
 
503
  // Get user.
504
  $user = get_user_by( 'ID', $object_id );
505
 
515
  $post_array = filter_input_array( INPUT_POST );
516
 
517
  // If update action is set then trigger the alert.
518
+ if (
519
+ (
520
+ isset( $post_array['_wpnonce'] ) // WP Dashboard Support.
521
+ && wp_verify_nonce( $post_array['_wpnonce'], 'update-user_' . $user->ID )
522
+ && isset( $post_array['action'] )
523
+ && 'update' == $post_array['action']
524
+ ) || (
525
+ isset( $post_array['_um_account'] ) // Ultimate Member Plugin support.
526
+ && '1' === $post_array['_um_account']
527
+ && isset( $post_array['_um_account_tab'] )
528
+ && 'general' === $post_array['_um_account_tab']
529
+ ) || (
530
+ isset( $post_array['action'] ) && 'update_user' === $post_array['action'] // MainWP action.
531
+ && isset( $post_array['mainwpsignature'] ) && ! empty( $post_array['mainwpsignature'] ) // MainWP Signature.
532
+ )
533
+ ) {
534
  if ( isset( $this->old_meta[ $meta_id ] ) && ! in_array( $meta_key, $username_meta, true ) ) {
535
  // Check change in meta value.
536
  if ( $this->old_meta[ $meta_id ]->val != $meta_value ) {
537
  $this->plugin->alerts->Trigger(
538
  4015, array(
539
+ 'TargetUsername' => $user->user_login,
540
  'custom_field_name' => $meta_key,
541
+ 'new_value' => $meta_value,
542
+ 'old_value' => $this->old_meta[ $meta_id ]->val,
543
  'ReportText' => $this->old_meta[ $meta_id ]->val . '|' . $meta_value,
544
  )
545
  );
554
  $this->plugin->alerts->Trigger(
555
  4017, array(
556
  'TargetUsername' => $user->user_login,
557
+ 'new_firstname' => $meta_value,
558
+ 'old_firstname' => $this->old_meta[ $meta_id ]->val,
559
  )
560
  );
561
  }
566
  $this->plugin->alerts->Trigger(
567
  4018, array(
568
  'TargetUsername' => $user->user_login,
569
+ 'new_lastname' => $meta_value,
570
+ 'old_lastname' => $this->old_meta[ $meta_id ]->val,
571
  )
572
  );
573
  }
578
  $this->plugin->alerts->Trigger(
579
  4019, array(
580
  'TargetUsername' => $user->user_login,
581
+ 'new_nickname' => $meta_value,
582
+ 'old_nickname' => $this->old_meta[ $meta_id ]->val,
583
  )
584
  );
585
  }
600
  * @since 2.6.9
601
  */
602
  public function event_userdata_updated( $user_id, $old_user_data ) {
 
603
  // Get user display name.
604
  $old_display_name = $old_user_data->display_name;
605
 
611
  if ( $old_display_name !== $new_display_name ) {
612
  $this->plugin->alerts->Trigger(
613
  4020, array(
614
+ 'TargetUsername' => $new_userdata->user_login,
615
  'new_displayname' => $new_display_name,
616
  'old_displayname' => $old_display_name,
617
  )
classes/Sensors/PluginsThemes.php CHANGED
@@ -66,15 +66,6 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
66
  */
67
  private $site_content;
68
 
69
- /**
70
- * Method: Constructor.
71
- *
72
- * @param WpSecurityAuditLog $wsal – Instance of WpSecurityAuditLog.
73
- */
74
- public function __construct( WpSecurityAuditLog $wsal ) {
75
- parent::__construct( $wsal );
76
- }
77
-
78
  /**
79
  * Listening to events using WP hooks.
80
  */
@@ -97,16 +88,64 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
97
 
98
  // Set site content.
99
  $this->set_site_themes();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  }
101
 
102
  /**
103
  * Triggered when a user accesses the admin area.
104
  */
105
  public function EventAdminInit() {
106
- $this->old_themes = wp_get_themes();
107
  $this->old_plugins = get_plugins();
108
  }
109
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  /**
111
  * Install, uninstall, activate, deactivate, upgrade and update.
112
  */
@@ -543,8 +582,10 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
543
  }
544
 
545
  if ( isset( $post_array['action'] ) && ! in_array( $post_array['action'], $wp_actions ) ) {
546
- if ( ! in_array( $post->post_type, array( 'attachment', 'revision', 'nav_menu_item', 'customize_changeset', 'custom_css' ) )
547
- || ! empty( $post->post_title ) ) {
 
 
548
  // If the plugin modify the post.
549
  if ( false !== strpos( $post_array['action'], 'edit' ) ) {
550
  $event = $this->GetEventTypeForPostType( $post, 2106, 2107, 2108 );
@@ -558,10 +599,14 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
558
  )
559
  );
560
  } elseif (
561
- isset( $post_array['page'] ) // If page index is set in post array.
562
- && 'woocommerce-bulk-stock-management' === $post_array['page']
 
 
 
563
  ) {
564
  // Ignore WooCommerce Bulk Stock Management page.
 
565
  } else {
566
  $event = $this->GetEventTypeForPostType( $post, 5019, 5020, 5021 );
567
  $this->plugin->alerts->Trigger(
@@ -633,6 +678,321 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
633
  return array_values( $result );
634
  }
635
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
636
  /**
637
  * Get event code by post type.
638
  *
@@ -921,4 +1281,56 @@ class WSAL_Sensors_PluginsThemes extends WSAL_AbstractSensor {
921
  }
922
  return $plugin;
923
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
924
  }
66
  */
67
  private $site_content;
68
 
 
 
 
 
 
 
 
 
 
69
  /**
70
  * Listening to events using WP hooks.
71
  */
88
 
89
  // Set site content.
90
  $this->set_site_themes();
91
+
92
+ // Check if MainWP Child Plugin exists.
93
+ if ( is_plugin_active( 'mainwp-child/mainwp-child.php' ) ) {
94
+ $this->mainwp_child_init();
95
+
96
+ // Handle plugin/theme installation event via MainWP dashboard.
97
+ add_action( 'mainwp_child_installPluginTheme', array( $this, 'mainwp_child_install_assets' ), 10, 1 );
98
+
99
+ // Activate/Deactivate plugin event.
100
+ add_action( 'activated_plugin', array( $this, 'mainwp_child_plugin_events' ), 10, 1 );
101
+ add_action( 'deactivated_plugin', array( $this, 'mainwp_child_plugin_events' ), 10, 1 );
102
+
103
+ // Uninstall plugin from MainWP dashboard.
104
+ add_action( 'mainwp_child_plugin_action', array( $this, 'mainwp_child_uninstall_plugin' ), 10, 1 );
105
+
106
+ // Uninstall theme from MainWP dashboard.
107
+ add_action( 'mainwp_child_theme_action', array( $this, 'mainwp_child_uninstall_theme' ), 10, 1 );
108
+
109
+ // Update theme/plugin from MainWP dashboard.
110
+ add_action( 'mainwp_child_upgradePluginTheme', array( $this, 'mainwp_child_update_assets' ), 10, 1 );
111
+ }
112
  }
113
 
114
  /**
115
  * Triggered when a user accesses the admin area.
116
  */
117
  public function EventAdminInit() {
118
+ $this->old_themes = wp_get_themes();
119
  $this->old_plugins = get_plugins();
120
  }
121
 
122
+ /**
123
+ * Method: Check and initialize class members for MainWP.
124
+ */
125
+ public function mainwp_child_init() {
126
+ // $_POST array arguments.
127
+ $post_array_args = array(
128
+ 'function' => FILTER_SANITIZE_STRING,
129
+ 'action' => FILTER_SANITIZE_STRING,
130
+ 'theme' => FILTER_SANITIZE_STRING,
131
+ 'mainwpsignature' => FILTER_SANITIZE_STRING,
132
+ );
133
+
134
+ // Get $_POST array.
135
+ $post_array = filter_input_array( INPUT_POST, $post_array_args );
136
+
137
+ if (
138
+ isset( $post_array['function'] ) && 'theme_action' === $post_array['function']
139
+ && isset( $post_array['action'] ) && 'delete' === $post_array['action']
140
+ && isset( $post_array['theme'] ) && ! empty( $post_array['theme'] )
141
+ && isset( $post_array['mainwpsignature'] ) && ! empty( $post_array['mainwpsignature'] )
142
+ ) {
143
+ if ( empty( $this->old_themes ) ) {
144
+ $this->old_themes = wp_get_themes();
145
+ }
146
+ }
147
+ }
148
+
149
  /**
150
  * Install, uninstall, activate, deactivate, upgrade and update.
151
  */
582
  }
583
 
584
  if ( isset( $post_array['action'] ) && ! in_array( $post_array['action'], $wp_actions ) ) {
585
+ if (
586
+ ! in_array( $post->post_type, array( 'attachment', 'revision', 'nav_menu_item', 'customize_changeset', 'custom_css' ) )
587
+ || ! empty( $post->post_title )
588
+ ) {
589
  // If the plugin modify the post.
590
  if ( false !== strpos( $post_array['action'], 'edit' ) ) {
591
  $event = $this->GetEventTypeForPostType( $post, 2106, 2107, 2108 );
599
  )
600
  );
601
  } elseif (
602
+ ( isset( $post_array['page'] ) && 'woocommerce-bulk-stock-management' === $post_array['page'] ) // If page index is set in post array then ignore.
603
+ || (
604
+ isset( $post_array['mainwpsignature'] )
605
+ && ( 'restore' === $post_array['action'] || 'unpublish' === $post_array['action'] || 'publish' === $post_array['action'] )
606
+ ) // OR If the request is coming from MainWP then ignore.
607
  ) {
608
  // Ignore WooCommerce Bulk Stock Management page.
609
+ // OR MainWP plugin requests.
610
  } else {
611
  $event = $this->GetEventTypeForPostType( $post, 5019, 5020, 5021 );
612
  $this->plugin->alerts->Trigger(
678
  return array_values( $result );
679
  }
680
 
681
+ /**
682
+ * Method: Handle plugin/theme install event
683
+ * from MainWP dashboard on child site.
684
+ *
685
+ * @param array $args - Array of arguments related to asset installed.
686
+ * @since 3.2.2
687
+ */
688
+ public function mainwp_child_install_assets( $args ) {
689
+ if ( empty( $args ) || ! is_array( $args ) ) {
690
+ return;
691
+ }
692
+
693
+ // Verify the action from MainWP.
694
+ if (
695
+ isset( $args['action'] ) && 'install' === $args['action']
696
+ && isset( $args['success'] ) && ! empty( $args['success'] )
697
+ ) {
698
+ if ( isset( $args['type'] ) && 'theme' === $args['type'] ) { // Installing theme.
699
+ // Get theme name & object.
700
+ $theme_slug = isset( $args['slug'] ) ? $args['slug'] : false;
701
+ $theme_obj = wp_get_theme( $theme_slug );
702
+
703
+ // Check if theme exists.
704
+ if ( $theme_obj->exists() ) {
705
+ $this->plugin->alerts->Trigger(
706
+ 5005, array(
707
+ 'Theme' => (object) array(
708
+ 'Name' => $theme_obj->Name,
709
+ 'ThemeURI' => $theme_obj->ThemeURI,
710
+ 'Description' => $theme_obj->Description,
711
+ 'Author' => $theme_obj->Author,
712
+ 'Version' => $theme_obj->Version,
713
+ 'get_template_directory' => $theme_obj->get_template_directory(),
714
+ ),
715
+ )
716
+ );
717
+ // Add theme to site themes list.
718
+ $this->set_site_themes( $theme_slug );
719
+ }
720
+ } elseif ( isset( $args['type'] ) && 'plugin' === $args['type'] ) {
721
+ // Get plugin slug.
722
+ $plugin_slug = isset( $args['slug'] ) ? $args['slug'] : false;
723
+
724
+ $plugins = get_plugins(); // Get all plugins.
725
+ $plugin = $plugins[ $plugin_slug ]; // Take out the plugin being installed.
726
+
727
+ // Get plugin directory name.
728
+ $plugin_dir = $this->get_plugin_dir( $plugin_slug );
729
+
730
+ // Add plugin to site plugins list.
731
+ $this->set_site_plugins( $plugin_dir );
732
+
733
+ $plugin_path = plugin_dir_path( WP_PLUGIN_DIR . '/' . $plugin_slug );
734
+ $this->plugin->alerts->Trigger(
735
+ 5000, array(
736
+ 'Plugin' => (object) array(
737
+ 'Name' => $plugin['Name'],
738
+ 'PluginURI' => $plugin['PluginURI'],
739
+ 'Version' => $plugin['Version'],
740
+ 'Author' => $plugin['Author'],
741
+ 'Network' => $plugin['Network'] ? 'True' : 'False',
742
+ 'plugin_dir_path' => $plugin_path,
743
+ ),
744
+ )
745
+ );
746
+ }
747
+ }
748
+ }
749
+
750
+ /**
751
+ * Method: Handle plugin uninstall event
752
+ * from MainWP dashboard on child site.
753
+ *
754
+ * @param array $args - Array of arguments related to asset uninstalled.
755
+ * @since 3.2.2
756
+ */
757
+ public function mainwp_child_uninstall_plugin( $args ) {
758
+ if ( empty( $args ) || ! is_array( $args ) ) {
759
+ return;
760
+ }
761
+
762
+ // Get MainWP post data.
763
+ $post_array = filter_input_array( INPUT_POST );
764
+
765
+ // Get plugins from MainWP.
766
+ if ( isset( $post_array['plugin'] ) && ! empty( $post_array['plugin'] ) ) {
767
+ $wp_plugins = explode( '||', $post_array['plugin'] );
768
+ }
769
+
770
+ // Verify actions from MainWP.
771
+ if (
772
+ isset( $args['action'] ) && 'delete' === $args['action']
773
+ && isset( $args['Name'] ) && ! empty( $args['Name'] )
774
+ && isset( $post_array['mainwpsignature'] ) && ! empty( $post_array['mainwpsignature'] )
775
+ ) {
776
+ // Get plugin name.
777
+ $plugin_name = $args['Name'];
778
+
779
+ // Get plugin filename.
780
+ $plugin_filename = $this->get_plugin_file_name( $plugin_name );
781
+
782
+ if ( ! empty( $plugin_filename ) && in_array( $plugin_filename, $wp_plugins, true ) ) {
783
+ $this->plugin->alerts->Trigger(
784
+ 5003, array(
785
+ 'PluginFile' => $plugin_filename,
786
+ 'PluginData' => (object) array(
787
+ 'Name' => $plugin_name,
788
+ ),
789
+ )
790
+ );
791
+
792
+ // Get plugin directory name.
793
+ $plugin_dir = $this->get_plugin_dir( $plugin_filename );
794
+
795
+ // Set plugin to skip file changes alert.
796
+ $this->skip_plugin_change_alerts( $plugin_dir );
797
+
798
+ // Remove it from the list.
799
+ $this->remove_site_plugin( $plugin_dir );
800
+ }
801
+ }
802
+ }
803
+
804
+ /**
805
+ * Method: Handle theme uninstall event
806
+ * from MainWP dashboard on child site.
807
+ *
808
+ * @param array $args - Array of arguments related to asset uninstalled.
809
+ * @since 3.2.2
810
+ */
811
+ public function mainwp_child_uninstall_theme( $args ) {
812
+ if ( empty( $args ) || ! is_array( $args ) ) {
813
+ return;
814
+ }
815
+
816
+ // Get MainWP post data.
817
+ $post_array = filter_input_array( INPUT_POST );
818
+
819
+ // Get themes from MainWP.
820
+ if ( isset( $post_array['theme'] ) && ! empty( $post_array['theme'] ) ) {
821
+ $wp_themes = explode( '||', $post_array['theme'] );
822
+ }
823
+
824
+ // Verify actions from MainWP.
825
+ if (
826
+ isset( $args['action'] ) && 'delete' === $args['action']
827
+ && isset( $args['Name'] ) && ! empty( $args['Name'] )
828
+ && isset( $post_array['mainwpsignature'] ) && ! empty( $post_array['mainwpsignature'] )
829
+ ) {
830
+ // Get theme object.
831
+ $themes = $this->GetRemovedThemes();
832
+
833
+ if ( ! empty( $themes ) ) {
834
+ foreach ( $themes as $index => $theme ) {
835
+ if ( ! empty( $theme ) && $theme instanceof WP_Theme && in_array( $theme->Name, $wp_themes, true ) ) {
836
+ $this->plugin->alerts->Trigger(
837
+ 5007, array(
838
+ 'Theme' => (object) array(
839
+ 'Name' => $theme->Name,
840
+ 'ThemeURI' => $theme->ThemeURI,
841
+ 'Description' => $theme->Description,
842
+ 'Author' => $theme->Author,
843
+ 'Version' => $theme->Version,
844
+ 'get_template_directory' => $theme->get_template_directory(),
845
+ ),
846
+ )
847
+ );
848
+
849
+ // Set theme to skip file changes alert.
850
+ $this->skip_theme_change_alerts( $theme->stylesheet );
851
+
852
+ // Remove it from the list.
853
+ $this->remove_site_theme( $theme->stylesheet );
854
+ }
855
+ }
856
+ }
857
+ }
858
+ }
859
+
860
+ /**
861
+ * Method: Handle plugin activation event
862
+ * from MainWP dashboard on a child site.
863
+ *
864
+ * @param string $plugin - Plugin slug.
865
+ * @since 3.2.2
866
+ */
867
+ public function mainwp_child_plugin_events( $plugin ) {
868
+ // Check parameter.
869
+ if ( empty( $plugin ) ) {
870
+ return;
871
+ }
872
+
873
+ // Get MainWP post data.
874
+ $post_array = filter_input_array( INPUT_POST );
875
+
876
+ // Get plugins from MainWP.
877
+ if ( isset( $post_array['plugin'] ) && ! empty( $post_array['plugin'] ) ) {
878
+ $wp_plugins = explode( '||', $post_array['plugin'] );
879
+ }
880
+
881
+ if (
882
+ isset( $post_array['mainwpsignature'] ) // Check MainWP signature.
883
+ && isset( $post_array['action'] ) // Check if action is set.
884
+ && in_array( $plugin, $wp_plugins, true ) // Check if plugin being activate/deactivate is in the list of plugins from MainWP.
885
+ ) {
886
+ if ( 'activate' === $post_array['action'] ) {
887
+ $event = 5001;
888
+ } elseif ( 'deactivate' === $post_array['action'] ) {
889
+ $event = 5002;
890
+ }
891
+
892
+ $plugin = WP_PLUGIN_DIR . '/' . $plugin;
893
+ $plugin_data = get_plugin_data( $plugin, false, true );
894
+ $this->plugin->alerts->Trigger(
895
+ $event, array(
896
+ 'PluginFile' => $plugin,
897
+ 'PluginData' => (object) array(
898
+ 'Name' => $plugin_data['Name'],
899
+ 'PluginURI' => $plugin_data['PluginURI'],
900
+ 'Version' => $plugin_data['Version'],
901
+ 'Author' => $plugin_data['Author'],
902
+ 'Network' => $plugin_data['Network'] ? 'True' : 'False',
903
+ ),
904
+ )
905
+ );
906
+ }
907
+ }
908
+
909
+ /**
910
+ * Method: Handle plugin/theme update event
911
+ * from MainWP dashboard on child site.
912
+ *
913
+ * @param array $args - Array of arguments related to asset updated.
914
+ * @since 3.2.2
915
+ */
916
+ public function mainwp_child_update_assets( $args ) {
917
+ if ( empty( $args ) || ! is_array( $args ) ) {
918
+ return;
919
+ }
920
+
921
+ // Get MainWP post data.
922
+ $post_array = filter_input_array( INPUT_POST );
923
+
924
+ // Check type.
925
+ if (
926
+ isset( $post_array['function'] ) && 'upgradeplugintheme' === $post_array['function']
927
+ && isset( $post_array['mainwpsignature'] ) && ! empty( $post_array['mainwpsignature'] )
928
+ && isset( $post_array['list'] ) && ! empty( $post_array['list'] )
929
+ && isset( $args['type'] ) && ! empty( $args['type'] )
930
+ && isset( $args['name'] ) && ! empty( $args['name'] )
931
+ ) {
932
+ if ( 'theme' === $args['type'] ) {
933
+ // Site themes updated.
934
+ $site_themes = explode( ',', $post_array['list'] );
935
+
936
+ // Theme name.
937
+ $theme_name = $args['name'];
938
+
939
+ // Get theme object.
940
+ $theme = $this->get_theme_by_name( $theme_name );
941
+
942
+ if ( ! empty( $theme ) && $theme instanceof WP_Theme && in_array( $theme->stylesheet, $site_themes, true ) ) {
943
+ $this->plugin->alerts->Trigger(
944
+ 5031, array(
945
+ 'Theme' => (object) array(
946
+ 'Name' => $theme->Name,
947
+ 'ThemeURI' => $theme->ThemeURI,
948
+ 'Description' => $theme->Description,
949
+ 'Author' => $theme->Author,
950
+ 'Version' => $theme->Version,
951
+ 'get_template_directory' => $theme->get_template_directory(),
952
+ ),
953
+ )
954
+ );
955
+
956
+ // Set theme to skip file changes alert.
957
+ $this->skip_theme_change_alerts( $theme->stylesheet );
958
+ }
959
+ } elseif ( 'plugin' === $args['type'] ) {
960
+ // Plugin name.
961
+ $plugin_name = $args['name'];
962
+
963
+ // Get plugin filename.
964
+ $plugin_file = $this->get_plugin_file_name( $plugin_name );
965
+
966
+ // If plugin file is empty then return.
967
+ if ( empty( $plugin_file ) ) {
968
+ return;
969
+ }
970
+
971
+ // Get plugin directory name.
972
+ $plugin_dir = $this->get_plugin_dir( $plugin_file );
973
+
974
+ // Set plugin to skip file changes alert.
975
+ $this->skip_plugin_change_alerts( $plugin_dir );
976
+
977
+ $plugin_file = WP_PLUGIN_DIR . '/' . $plugin_file;
978
+ $plugin_data = get_plugin_data( $plugin_file, false, true );
979
+
980
+ $this->plugin->alerts->Trigger(
981
+ 5004, array(
982
+ 'PluginFile' => $plugin_file,
983
+ 'PluginData' => (object) array(
984
+ 'Name' => $plugin_data['Name'],
985
+ 'PluginURI' => $plugin_data['PluginURI'],
986
+ 'Version' => $plugin_data['Version'],
987
+ 'Author' => $plugin_data['Author'],
988
+ 'Network' => $plugin_data['Network'] ? 'True' : 'False',
989
+ ),
990
+ )
991
+ );
992
+ }
993
+ }
994
+ }
995
+
996
  /**
997
  * Get event code by post type.
998
  *
1281
  }
1282
  return $plugin;
1283
  }
1284
+
1285
+ /**
1286
+ * Method: Return plugin file name.
1287
+ *
1288
+ * @param string $plugin_name - Plugin name.
1289
+ * @return string
1290
+ */
1291
+ public function get_plugin_file_name( $plugin_name ) {
1292
+ // Verify parameter.
1293
+ if ( empty( $plugin_name ) ) {
1294
+ return;
1295
+ }
1296
+
1297
+ // Get all plugins.
1298
+ $all_plugins = get_plugins();
1299
+
1300
+ $plugin_filename = '';
1301
+ if ( ! empty( $all_plugins ) && is_array( $all_plugins ) ) {
1302
+ foreach ( $all_plugins as $plugin_file => $plugin_data ) {
1303
+ if ( $plugin_name === $plugin_data['Name'] ) {
1304
+ $plugin_filename = $plugin_file;
1305
+ }
1306
+ }
1307
+ }
1308
+ return $plugin_filename;
1309
+ }
1310
+
1311
+ /**
1312
+ * Method: Search and return theme object by name.
1313
+ *
1314
+ * @param string $theme_name - Theme name.
1315
+ * @return WP_Theme
1316
+ */
1317
+ public function get_theme_by_name( $theme_name ) {
1318
+ // Check if $theme_name is empty.
1319
+ if ( empty( $theme_name ) ) {
1320
+ return;
1321
+ }
1322
+
1323
+ // Get all themes.
1324
+ $all_themes = wp_get_themes();
1325
+
1326
+ $theme = '';
1327
+ if ( ! empty( $all_themes ) ) {
1328
+ foreach ( $all_themes as $stylesheet => $theme_obj ) {
1329
+ if ( $theme_name === $theme_obj->Name ) {
1330
+ $theme = $theme_obj;
1331
+ }
1332
+ }
1333
+ }
1334
+ return $theme;
1335
+ }
1336
  }
classes/Sensors/System.php CHANGED
@@ -281,6 +281,22 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
281
  $username = wp_get_current_user()->user_login;
282
  }
283
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
  if ( 'Website Visitor' !== $username ) {
285
  // Check if the alert is disabled from the "Enable/Disable Alerts" section.
286
  if ( ! $this->plugin->alerts->IsEnabled( 6007 ) ) {
@@ -315,23 +331,25 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
315
  $msg .= ' This could possible be a scan, therefore keep an eye on the activity from this IP Address';
316
  }
317
 
318
- $link_file = $this->WriteLog( $new, $ip, $username );
319
 
320
  $occ->UpdateMetaValue( 'Attempts', $new );
321
  $occ->UpdateMetaValue( 'Username', $username );
322
  $occ->UpdateMetaValue( 'Msg', $msg );
 
323
  if ( ! empty( $link_file ) ) {
324
  $occ->UpdateMetaValue( 'LinkFile', $link_file );
325
  }
326
  $occ->created_on = null;
327
  $occ->Save();
328
  } else {
329
- $link_file = $this->WriteLog( 1, $ip, $username );
330
  // Create a new record.
331
  $fields = array(
332
  'Attempts' => 1,
333
  'Username' => $username,
334
- 'Msg' => $msg,
 
335
  );
336
  if ( ! empty( $link_file ) ) {
337
  $fields['LinkFile'] = $link_file;
@@ -372,23 +390,25 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
372
  $msg .= ' This could possible be a scan, therefore keep an eye on the activity from this IP Address';
373
  }
374
 
375
- $link_file = $this->WriteLog( $new, $ip, $username, false );
376
 
377
  $occ->UpdateMetaValue( 'Attempts', $new );
378
  $occ->UpdateMetaValue( 'Username', $username );
379
  $occ->UpdateMetaValue( 'Msg', $msg );
 
380
  if ( ! empty( $link_file ) ) {
381
  $occ->UpdateMetaValue( 'LinkFile', $link_file );
382
  }
383
  $occ->created_on = null;
384
  $occ->Save();
385
  } else {
386
- $link_file = $this->WriteLog( 1, $ip, $username, false );
387
  // Create a new record.
388
  $fields = array(
389
  'Attempts' => 1,
390
  'Username' => $username,
391
  'Msg' => $msg,
 
392
  );
393
  if ( ! empty( $link_file ) ) {
394
  $fields['LinkFile'] = $link_file;
@@ -398,6 +418,23 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
398
  }
399
  }
400
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
401
  /**
402
  * Triggered when a user accesses the admin area.
403
  */
@@ -825,19 +862,13 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
825
  * @param string $ip - IP address.
826
  * @param string $username - Username.
827
  * @param bool $logged_in - True if logged in.
 
828
  */
829
- private function WriteLog( $attempts, $ip, $username = '', $logged_in = true ) {
830
  $name_file = null;
831
 
832
  if ( $logged_in ) {
833
  if ( 'on' === $this->plugin->GetGlobalOption( 'log-404', 'off' ) ) {
834
- // Filter global arrays for security.
835
- $server_array = filter_input_array( INPUT_SERVER );
836
-
837
- // Request URL.
838
- $request_uri = filter_input( INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_URL );
839
- $url = home_url() . $request_uri;
840
-
841
  // Get option to log referrer.
842
  $log_referrer = $this->plugin->GetGlobalOption( 'log-404-referrer' );
843
 
@@ -848,7 +879,10 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
848
 
849
  if ( 'on' === $log_referrer ) {
850
  // Get the referer.
851
- $referrer = ( isset( $server_array['HTTP_REFERER'] ) ) ? $server_array['HTTP_REFERER'] : false;
 
 
 
852
 
853
  // Data to write.
854
  $data = '';
@@ -875,9 +909,9 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
875
  $username = $username . '_';
876
  }
877
 
878
- $upload_dir = wp_upload_dir();
879
- $uploads_dir_path = trailingslashit( $upload_dir['basedir'] ) . 'wp-security-audit-log/404s/';
880
  $uploads_url = trailingslashit( $upload_dir['baseurl'] ) . 'wp-security-audit-log/404s/';
 
881
 
882
  // Check directory.
883
  if ( $this->CheckDirectory( $uploads_dir_path ) ) {
@@ -911,13 +945,6 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
911
  }
912
  } else {
913
  if ( 'on' === $this->plugin->GetGlobalOption( 'log-visitor-404', 'off' ) ) {
914
- // Filter global arrays for security.
915
- $server_array = filter_input_array( INPUT_SERVER );
916
-
917
- // Request URL.
918
- $request_uri = filter_input( INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_URL );
919
- $url = home_url() . $request_uri;
920
-
921
  // Get option to log referrer.
922
  $log_referrer = $this->plugin->GetGlobalOption( 'log-visitor-404-referrer' );
923
 
@@ -928,7 +955,10 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
928
 
929
  if ( 'on' === $log_referrer ) {
930
  // Get the referer.
931
- $referrer = ( isset( $server_array['HTTP_REFERER'] ) ) ? $server_array['HTTP_REFERER'] : false;
 
 
 
932
 
933
  // Data to write.
934
  $data = '';
@@ -950,9 +980,9 @@ class WSAL_Sensors_System extends WSAL_AbstractSensor {
950
  }
951
 
952
  $username = '';
953
- $upload_dir = wp_upload_dir();
 
954
  $uploads_dir_path = trailingslashit( $upload_dir['basedir'] ) . 'wp-security-audit-log/404s/';
955
- $uploads_url = trailingslashit( $upload_dir['baseurl'] ) . 'wp-security-audit-log/404s/';
956
 
957
  // Check directory.
958
  if ( $this->CheckDirectory( $uploads_dir_path ) ) {
281
  $username = wp_get_current_user()->user_login;
282
  }
283
 
284
+ // Request URL.
285
+ $request_uri = filter_input( INPUT_SERVER, 'REQUEST_URI', FILTER_SANITIZE_STRING );
286
+ if ( ! empty( $request_uri ) ) {
287
+ $url_404 = home_url() . $request_uri;
288
+ } elseif ( isset( $_SERVER['REQUEST_URI'] ) && ! empty( $_SERVER['REQUEST_URI'] ) ) {
289
+ $url_404 = home_url() . sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) );
290
+ }
291
+
292
+ // Remove forward slash from the URL.
293
+ $url_404 = untrailingslashit( $url_404 );
294
+
295
+ // Check for excluded 404 URls.
296
+ if ( $this->is_excluded_url( $url_404 ) ) {
297
+ return;
298
+ }
299
+
300
  if ( 'Website Visitor' !== $username ) {
301
  // Check if the alert is disabled from the "Enable/Disable Alerts" section.
302
  if ( ! $this->plugin->alerts->IsEnabled( 6007 ) ) {
331
  $msg .= ' This could possible be a scan, therefore keep an eye on the activity from this IP Address';
332
  }
333
 
334
+ $link_file = $this->WriteLog( $new, $ip, $username, true, $url_404 );
335
 
336
  $occ->UpdateMetaValue( 'Attempts', $new );
337
  $occ->UpdateMetaValue( 'Username', $username );
338
  $occ->UpdateMetaValue( 'Msg', $msg );
339
+ $occ->UpdateMetaValue( 'URL', $url_404 );
340
  if ( ! empty( $link_file ) ) {
341
  $occ->UpdateMetaValue( 'LinkFile', $link_file );
342
  }
343
  $occ->created_on = null;
344
  $occ->Save();
345
  } else {
346
+ $link_file = $this->WriteLog( 1, $ip, $username, true, $url_404 );
347
  // Create a new record.
348
  $fields = array(
349
  'Attempts' => 1,
350
  'Username' => $username,
351
+ 'Msg' => $msg,
352
+ 'URL' => $url_404,
353
  );
354
  if ( ! empty( $link_file ) ) {
355
  $fields['LinkFile'] = $link_file;
390
  $msg .= ' This could possible be a scan, therefore keep an eye on the activity from this IP Address';
391
  }
392
 
393
+ $link_file = $this->WriteLog( $new, $ip, $username, false, $url_404 );
394
 
395
  $occ->UpdateMetaValue( 'Attempts', $new );
396
  $occ->UpdateMetaValue( 'Username', $username );
397
  $occ->UpdateMetaValue( 'Msg', $msg );
398
+ $occ->UpdateMetaValue( 'URL', $url_404 );
399
  if ( ! empty( $link_file ) ) {
400
  $occ->UpdateMetaValue( 'LinkFile', $link_file );
401
  }
402
  $occ->created_on = null;
403
  $occ->Save();
404
  } else {
405
+ $link_file = $this->WriteLog( 1, $ip, $username, false, $url_404 );
406
  // Create a new record.
407
  $fields = array(
408
  'Attempts' => 1,
409
  'Username' => $username,
410
  'Msg' => $msg,
411
+ 'URL' => $url_404,
412
  );
413
  if ( ! empty( $link_file ) ) {
414
  $fields['LinkFile'] = $link_file;
418
  }
419
  }
420
 
421
+ /**
422
+ * Method: Return true if URL is excluded otherwise false.
423
+ *
424
+ * @param string $url - 404 URL.
425
+ * @return boolean
426
+ * @since 3.2.2
427
+ */
428
+ public function is_excluded_url( $url ) {
429
+ if ( empty( $url ) ) {
430
+ return false;
431
+ }
432
+
433
+ if ( in_array( $url, $this->plugin->settings->get_excluded_urls() ) ) {
434
+ return true;
435
+ }
436
+ }
437
+
438
  /**
439
  * Triggered when a user accesses the admin area.
440
  */
862
  * @param string $ip - IP address.
863
  * @param string $username - Username.
864
  * @param bool $logged_in - True if logged in.
865
+ * @param string $url - 404 URL.
866
  */
867
+ private function WriteLog( $attempts, $ip, $username = '', $logged_in = true, $url ) {
868
  $name_file = null;
869
 
870
  if ( $logged_in ) {
871
  if ( 'on' === $this->plugin->GetGlobalOption( 'log-404', 'off' ) ) {
 
 
 
 
 
 
 
872
  // Get option to log referrer.
873
  $log_referrer = $this->plugin->GetGlobalOption( 'log-404-referrer' );
874
 
879
 
880
  if ( 'on' === $log_referrer ) {
881
  // Get the referer.
882
+ $referrer = filter_input( INPUT_SERVER, 'HTTP_REFERER', FILTER_SANITIZE_STRING );
883
+ if ( empty( $referrer ) && isset( $_SERVER['HTTP_REFERER'] ) && ! empty( $_SERVER['HTTP_REFERER'] ) ) {
884
+ $referrer = sanitize_text_field( wp_unslash( $_SERVER['HTTP_REFERER'] ) );
885
+ }
886
 
887
  // Data to write.
888
  $data = '';
909
  $username = $username . '_';
910
  }
911
 
912
+ $upload_dir = wp_upload_dir();
 
913
  $uploads_url = trailingslashit( $upload_dir['baseurl'] ) . 'wp-security-audit-log/404s/';
914
+ $uploads_dir_path = trailingslashit( $upload_dir['basedir'] ) . 'wp-security-audit-log/404s/';
915
 
916
  // Check directory.
917
  if ( $this->CheckDirectory( $uploads_dir_path ) ) {
945
  }
946
  } else {
947
  if ( 'on' === $this->plugin->GetGlobalOption( 'log-visitor-404', 'off' ) ) {
 
 
 
 
 
 
 
948
  // Get option to log referrer.
949
  $log_referrer = $this->plugin->GetGlobalOption( 'log-visitor-404-referrer' );
950
 
955
 
956
  if ( 'on' === $log_referrer ) {
957
  // Get the referer.
958
+ $referrer = filter_input( INPUT_SERVER, 'HTTP_REFERER', FILTER_SANITIZE_STRING );
959
+ if ( empty( $referrer ) && isset( $_SERVER['HTTP_REFERER'] ) && ! empty( $_SERVER['HTTP_REFERER'] ) ) {
960
+ $referrer = sanitize_text_field( wp_unslash( $_SERVER['HTTP_REFERER'] ) );
961
+ }
962
 
963
  // Data to write.
964
  $data = '';
980
  }
981
 
982
  $username = '';
983
+ $upload_dir = wp_upload_dir();
984
+ $uploads_url = trailingslashit( $upload_dir['baseurl'] ) . 'wp-security-audit-log/404s/';
985
  $uploads_dir_path = trailingslashit( $upload_dir['basedir'] ) . 'wp-security-audit-log/404s/';
 
986
 
987
  // Check directory.
988
  if ( $this->CheckDirectory( $uploads_dir_path ) ) {
classes/Sensors/UserProfile.php CHANGED
@@ -47,6 +47,11 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
47
  add_action( 'set_user_role', array( $this, 'EventUserRoleChanged' ), 10, 3 );
48
  add_action( 'edit_user_profile', array( $this, 'EventOpenProfile' ), 10, 1 );
49
  add_action( 'profile_update', array( $this, 'event_email_changed' ), 10, 2 );
 
 
 
 
 
50
  }
51
 
52
  /**
@@ -312,9 +317,11 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
312
  // Get $_POST global array.
313
  $post_array = filter_input_array( INPUT_POST );
314
 
315
- if ( isset( $post_array['_um_account_tab'] ) // Check for UM tab.
 
316
  && 'general' === $post_array['_um_account_tab'] // Verify `General` UM tab.
317
- && ! empty( $post_array['user_email'] ) ) { // Check if user email is set.
 
318
  $old_email = $old_userdata->user_email; // Old email.
319
  $new_email = trim( $post_array['user_email'] ); // New email.
320
  if ( $old_email !== $new_email ) { // If both emails don't match then log alert.
@@ -330,4 +337,71 @@ class WSAL_Sensors_UserProfile extends WSAL_AbstractSensor {
330
  }
331
  }
332
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
333
  }
47
  add_action( 'set_user_role', array( $this, 'EventUserRoleChanged' ), 10, 3 );
48
  add_action( 'edit_user_profile', array( $this, 'EventOpenProfile' ), 10, 1 );
49
  add_action( 'profile_update', array( $this, 'event_email_changed' ), 10, 2 );
50
+
51
+ // Check if MainWP Child Plugin exists.
52
+ if ( is_plugin_active( 'mainwp-child/mainwp-child.php' ) ) {
53
+ add_action( 'profile_update', array( $this, 'mainwp_child_user_update' ), 20, 2 );
54
+ }
55
  }
56
 
57
  /**
317
  // Get $_POST global array.
318
  $post_array = filter_input_array( INPUT_POST );
319
 
320
+ if (
321
+ isset( $post_array['_um_account_tab'] ) // Check for UM tab.
322
  && 'general' === $post_array['_um_account_tab'] // Verify `General` UM tab.
323
+ && ! empty( $post_array['user_email'] ) // Check if user email is set.
324
+ ) {
325
  $old_email = $old_userdata->user_email; // Old email.
326
  $new_email = trim( $post_array['user_email'] ); // New email.
327
  if ( $old_email !== $new_email ) { // If both emails don't match then log alert.
337
  }
338
  }
339
  }
340
+
341
+ /**
342
+ * Method: Support for user profile changes via MainWP dashboard.
343
+ *
344
+ * @param int $user_id - User ID.
345
+ * @param WP_User $old_userdata - Old WP_User object.
346
+ */
347
+ public function mainwp_child_user_update( $user_id, $old_userdata ) {
348
+ // Check parameters.
349
+ if ( empty( $user_id ) || empty( $old_userdata ) ) {
350
+ return;
351
+ }
352
+
353
+ // Get MainWP post data.
354
+ $post_array = filter_input_array( INPUT_POST );
355
+
356
+ if (
357
+ isset( $post_array['action'] ) && 'update_user' === $post_array['action']
358
+ && isset( $post_array['mainwpsignature'] ) && ! empty( $post_array['mainwpsignature'] )
359
+ ) {
360
+ // Get the user by id.
361
+ $user = get_user_by( 'id', $user_id );
362
+
363
+ // If user exists then continue.
364
+ if ( ! empty( $user ) && $user instanceof WP_User ) {
365
+ // Email changed.
366
+ if ( ! empty( $post_array['extra']['email'] ) ) {
367
+ $old_email = $old_userdata->user_email; // Old email address.
368
+ $new_email = trim( $post_array['extra']['email'] ); // New email address.
369
+ $new_email = sanitize_text_field( wp_unslash( $new_email ) ); // Filter data for security.
370
+
371
+ // If old email does not matches the new email then log the event.
372
+ if ( $old_email !== $new_email ) {
373
+ $event = get_current_user_id() === $user_id ? 4005 : 4006;
374
+ $this->plugin->alerts->Trigger(
375
+ $event, array(
376
+ 'TargetUserID' => $user_id,
377
+ 'TargetUsername' => $user->user_login,
378
+ 'OldEmail' => $old_email,
379
+ 'NewEmail' => $new_email,
380
+ )
381
+ );
382
+ }
383
+ }
384
+
385
+ // Password changed.
386
+ if ( ! empty( $post_array['extra']['pass1'] ) && ! empty( $post_array['extra']['pass2'] ) ) {
387
+ $pass1 = trim( $post_array['extra']['pass1'] );
388
+ $pass2 = trim( $post_array['extra']['pass2'] );
389
+ $match = wp_check_password( $pass1, $old_userdata->user_pass, $user_id ); // Check if current pass matches the old one.
390
+
391
+ if ( $pass1 === $pass2 && ! $match ) {
392
+ $event = get_current_user_id() === $user_id ? 4003 : 4004;
393
+ $this->plugin->alerts->Trigger(
394
+ $event, array(
395
+ 'TargetUserID' => $user_id,
396
+ 'TargetUserData' => (object) array(
397
+ 'Username' => $user->user_login,
398
+ 'Roles' => is_array( $user->roles ) ? implode( ', ', $user->roles ) : $user->roles,
399
+ ),
400
+ )
401
+ );
402
+ }
403
+ }
404
+ }
405
+ }
406
+ }
407
  }
classes/Sensors/WooCommerce.php CHANGED
@@ -115,6 +115,11 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
115
  * Listening to events using WP hooks.
116
  */
117
  public function HookEvents() {
 
 
 
 
 
118
  if ( current_user_can( 'edit_posts' ) ) {
119
  add_action( 'admin_init', array( $this, 'EventAdminInit' ) );
120
  }
@@ -124,11 +129,13 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
124
  add_action( 'untrash_post', array( $this, 'EventUntrashed' ) );
125
 
126
  add_action( 'create_product_cat', array( $this, 'EventCategoryCreation' ), 10, 1 );
127
- /* add_action('edit_product_cat', array($this, 'EventCategoryChanged'), 10, 1); */
128
 
129
  // Detect live change in stock.
130
  add_filter( 'woocommerce_order_item_quantity', array( $this, 'set_old_stock' ), 10, 3 );
131
  add_action( 'woocommerce_product_set_stock', array( $this, 'product_stock_changed' ), 10, 1 );
 
 
 
132
  }
133
 
134
  /**
@@ -150,7 +157,7 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
150
  $product_with_stock = wc_get_product( $product_id_with_stock );
151
 
152
  // Set stock attributes of the product.
153
- $this->_old_stock = $product_with_stock->get_stock_quantity();
154
  $this->_old_stock_status = $product_with_stock->get_stock_status();
155
 
156
  // Return original stock quantity.
@@ -198,16 +205,16 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
198
  $old_stock_status = '';
199
  }
200
  } else {
201
- $old_stock = $this->_old_stock; // Get old stock quantity.
202
  $old_stock_status = $this->_old_stock_status; // Get old stock status.
203
  }
204
 
205
- $new_stock = $product->get_stock_quantity(); // Get new stock quantity.
206
  $new_stock_status = $product->get_stock_status(); // Get new stock status.
207
- $product_title = $product->get_title(); // Get product title.
208
 
209
  // Set post object.
210
- $post = new stdClass();
211
  $post->ID = $product_id;
212
 
213
  // Set username.
@@ -223,24 +230,26 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
223
  $editor_link = $this->GetEditorLink( $post );
224
  $this->plugin->alerts->Trigger(
225
  9018, array(
226
- 'ProductTitle' => $product_title,
227
- 'OldStatus' => $this->GetStockStatusName( $old_stock_status ),
228
- 'NewStatus' => $this->GetStockStatusName( $new_stock_status ),
229
- 'Username' => $username,
230
  $editor_link['name'] => $editor_link['value'],
231
  )
232
  );
233
  }
234
 
 
 
235
  // If stock has changed then trigger the alert.
236
- if ( $old_stock !== $new_stock ) {
237
  $editor_link = $this->GetEditorLink( $post );
238
  $this->plugin->alerts->Trigger(
239
  9019, array(
240
- 'ProductTitle' => $product_title,
241
- 'OldValue' => ( ! empty( $old_stock ) ? $old_stock : 0 ),
242
- 'NewValue' => $new_stock,
243
- 'Username' => $username,
244
  $editor_link['name'] => $editor_link['value'],
245
  )
246
  );
@@ -272,18 +281,18 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
272
  }
273
 
274
  if ( isset( $post_array ) && isset( $post_array['post_ID'] )
275
- && ! (defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE)
276
- && ! (isset( $post_array['action'] ) && 'autosave' == $post_array['action'] )
277
  ) {
278
- $post_id = intval( $post_array['post_ID'] );
279
- $this->_old_post = get_post( $post_id );
280
- $this->_old_link = get_post_permalink( $post_id, false, true );
281
- $this->_old_cats = $this->GetProductCategories( $this->_old_post );
282
- $this->_old_data = $this->GetProductData( $this->_old_post );
283
- $this->_old_stock = get_post_meta( $post_id, '_stock', true );
284
  $this->_old_stock_status = get_post_meta( $post_id, '_stock_status', true );
285
 
286
- $old_downloadable_files = get_post_meta( $post_id, '_downloadable_files', true );
287
  if ( ! empty( $old_downloadable_files ) ) {
288
  foreach ( $old_downloadable_files as $file ) {
289
  array_push( $this->_old_file_names, $file['name'] );
@@ -368,7 +377,7 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
368
  if ( 'draft' == $new_post->post_status ) {
369
  $this->plugin->alerts->Trigger(
370
  9000, array(
371
- 'ProductTitle' => $new_post->post_title,
372
  $editor_link['name'] => $editor_link['value'],
373
  )
374
  );
@@ -376,8 +385,8 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
376
  } elseif ( 'publish' == $new_post->post_status ) {
377
  $this->plugin->alerts->Trigger(
378
  9001, array(
379
- 'ProductTitle' => $new_post->post_title,
380
- 'ProductUrl' => get_post_permalink( $new_post->ID ),
381
  $editor_link['name'] => $editor_link['value'],
382
  )
383
  );
@@ -399,25 +408,12 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
399
  $this->plugin->alerts->Trigger(
400
  9002, array(
401
  'CategoryName' => $term->name,
402
- 'Slug' => $term->slug,
403
  )
404
  );
405
  }
406
  }
407
 
408
- /**
409
- * Not implemented
410
- *
411
- * @param int|WP_Term $term_id - Term ID.
412
- */
413
- /**
414
- public function EventCategoryChanged( $term_id = null ) {
415
- $old_term = get_term( $term_id );
416
- if ( isset( $_POST['taxonomy'] ) ) {
417
- // new $term in $_POST
418
- }
419
- } */
420
-
421
  /**
422
  * Trigger events 9003
423
  *
@@ -437,9 +433,9 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
437
  $editor_link = $this->GetEditorLink( $newpost );
438
  $this->plugin->alerts->Trigger(
439
  9003, array(
440
- 'ProductTitle' => $newpost->post_title,
441
- 'OldCategories' => $old_cats ? $old_cats : 'no categories',
442
- 'NewCategories' => $new_cats ? $new_cats : 'no categories',
443
  $editor_link['name'] => $editor_link['value'],
444
  )
445
  );
@@ -463,9 +459,9 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
463
  $editor_link = $this->GetEditorLink( $oldpost );
464
  $this->plugin->alerts->Trigger(
465
  9004, array(
466
- 'ProductTitle' => $oldpost->post_title,
467
- 'OldDescription' => $oldpost->post_excerpt,
468
- 'NewDescription' => $newpost->post_excerpt,
469
  $editor_link['name'] => $editor_link['value'],
470
  )
471
  );
@@ -489,7 +485,7 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
489
  $editor_link = $this->GetEditorLink( $oldpost );
490
  $this->plugin->alerts->Trigger(
491
  9005, array(
492
- 'ProductTitle' => $oldpost->post_title,
493
  $editor_link['name'] => $editor_link['value'],
494
  )
495
  );
@@ -507,15 +503,15 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
507
  * @return int
508
  */
509
  protected function CheckPermalinkChange( $old_link, $new_link, $post ) {
510
- if ( ($old_link && $new_link) && ($old_link != $new_link) ) {
511
  $editor_link = $this->GetEditorLink( $post );
512
  $this->plugin->alerts->Trigger(
513
  9006, array(
514
- 'ProductTitle' => $post->post_title,
515
- 'OldUrl' => $old_link,
516
- 'NewUrl' => $new_link,
517
  $editor_link['name'] => $editor_link['value'],
518
- 'ReportText' => '"' . $old_link . '"|"' . $new_link . '"',
519
  )
520
  );
521
  return 1;
@@ -547,7 +543,7 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
547
  $editor_link = $this->GetEditorLink( $post );
548
  $this->plugin->alerts->Trigger(
549
  9007, array(
550
- 'ProductTitle' => $post->post_title,
551
  $editor_link['name'] => $editor_link['value'],
552
  )
553
  );
@@ -569,14 +565,14 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
569
  return 0;
570
  }
571
  $from = strtotime( $oldpost->post_date );
572
- $to = strtotime( $newpost->post_date );
573
  if ( $from != $to ) {
574
  $editor_link = $this->GetEditorLink( $oldpost );
575
  $this->plugin->alerts->Trigger(
576
  9008, array(
577
- 'ProductTitle' => $oldpost->post_title,
578
- 'OldDate' => $oldpost->post_date,
579
- 'NewDate' => $newpost->post_date,
580
  $editor_link['name'] => $editor_link['value'],
581
  )
582
  );
@@ -616,13 +612,13 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
616
  $new_visibility = ucfirst( $new_visibility );
617
  }
618
 
619
- if ( ($old_visibility && $new_visibility) && ($old_visibility != $new_visibility) ) {
620
  $editor_link = $this->GetEditorLink( $oldpost );
621
  $this->plugin->alerts->Trigger(
622
  9009, array(
623
- 'ProductTitle' => $oldpost->post_title,
624
- 'OldVisibility' => $old_visibility,
625
- 'NewVisibility' => $new_visibility,
626
  $editor_link['name'] => $editor_link['value'],
627
  )
628
  );
@@ -657,15 +653,15 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
657
  if ( 'publish' == $oldpost->post_status ) {
658
  $this->plugin->alerts->Trigger(
659
  9010, array(
660
- 'ProductTitle' => $oldpost->post_title,
661
- 'ProductUrl' => get_post_permalink( $oldpost->ID ),
662
  $editor_link['name'] => $editor_link['value'],
663
  )
664
  );
665
  } elseif ( 'draft' == $oldpost->post_status ) {
666
  $this->plugin->alerts->Trigger(
667
  9011, array(
668
- 'ProductTitle' => $oldpost->post_title,
669
  $editor_link['name'] => $editor_link['value'],
670
  )
671
  );
@@ -683,7 +679,7 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
683
  $this->plugin->alerts->Trigger(
684
  9012, array(
685
  'ProductTitle' => $post->post_title,
686
- 'ProductUrl' => get_post_permalink( $post->ID ),
687
  )
688
  );
689
  }
@@ -716,7 +712,7 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
716
  $editor_link = $this->GetEditorLink( $post );
717
  $this->plugin->alerts->Trigger(
718
  9014, array(
719
- 'ProductTitle' => $post->post_title,
720
  $editor_link['name'] => $editor_link['value'],
721
  )
722
  );
@@ -739,9 +735,9 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
739
  $editor_link = $this->GetEditorLink( $oldpost );
740
  $this->plugin->alerts->Trigger(
741
  9015, array(
742
- 'ProductTitle' => $oldpost->post_title,
743
- 'OldStatus' => $oldpost->post_status,
744
- 'NewStatus' => $newpost->post_status,
745
  $editor_link['name'] => $editor_link['value'],
746
  )
747
  );
@@ -767,16 +763,16 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
767
  return false;
768
  }
769
 
770
- $result = 0;
771
- $old_price = get_post_meta( $oldpost->ID, '_regular_price', true );
772
  $old_sale_price = get_post_meta( $oldpost->ID, '_sale_price', true );
773
- $new_price = isset( $post_array['_regular_price'] ) ? $post_array['_regular_price'] : null;
774
  $new_sale_price = isset( $post_array['_sale_price'] ) ? $post_array['_sale_price'] : null;
775
 
776
- if ( ($new_price) && ($old_price != $new_price) ) {
777
  $result = $this->EventPrice( $oldpost, 'Regular price', $old_price, $new_price );
778
  }
779
- if ( ($new_sale_price) && ($old_sale_price != $new_sale_price) ) {
780
  $result = $this->EventPrice( $oldpost, 'Sale price', $old_sale_price, $new_sale_price );
781
  }
782
  return $result;
@@ -792,14 +788,14 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
792
  * @return int
793
  */
794
  private function EventPrice( $oldpost, $type, $old_price, $new_price ) {
795
- $currency = $this->GetCurrencySymbol( $this->GetConfig( 'currency' ) );
796
  $editor_link = $this->GetEditorLink( $oldpost );
797
  $this->plugin->alerts->Trigger(
798
  9016, array(
799
- 'ProductTitle' => $oldpost->post_title,
800
- 'PriceType' => $type,
801
- 'OldPrice' => ( ! empty( $old_price ) ? $currency . $old_price : 0),
802
- 'NewPrice' => $currency . $new_price,
803
  $editor_link['name'] => $editor_link['value'],
804
  )
805
  );
@@ -825,13 +821,13 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
825
  $old_sku = get_post_meta( $oldpost->ID, '_sku', true );
826
  $new_sku = isset( $post_array['_sku'] ) ? $post_array['_sku'] : null;
827
 
828
- if ( ($new_sku) && ($old_sku != $new_sku) ) {
829
  $editor_link = $this->GetEditorLink( $oldpost );
830
  $this->plugin->alerts->Trigger(
831
  9017, array(
832
- 'ProductTitle' => $oldpost->post_title,
833
- 'OldSku' => ( ! empty( $old_sku ) ? $old_sku : 0),
834
- 'NewSku' => $new_sku,
835
  $editor_link['name'] => $editor_link['value'],
836
  )
837
  );
@@ -859,13 +855,13 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
859
  $old_status = $this->_old_stock_status;
860
  $new_status = isset( $post_array['_stock_status'] ) ? $post_array['_stock_status'] : null;
861
 
862
- if ( ($old_status && $new_status) && ($old_status != $new_status) ) {
863
  $editor_link = $this->GetEditorLink( $oldpost );
864
  $this->plugin->alerts->Trigger(
865
  9018, array(
866
- 'ProductTitle' => $oldpost->post_title,
867
- 'OldStatus' => $this->GetStockStatusName( $old_status ),
868
- 'NewStatus' => $this->GetStockStatusName( $new_status ),
869
  $editor_link['name'] => $editor_link['value'],
870
  )
871
  );
@@ -884,26 +880,26 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
884
  // Filter POST global array.
885
  $post_array = filter_input_array( INPUT_POST );
886
 
887
- if ( isset( $post_array['post_ID'] )
 
888
  && isset( $post_array['_wpnonce'] )
889
- && ! wp_verify_nonce( $post_array['_wpnonce'], 'update-post_' . $post_array['post_ID'] ) ) {
890
- return false;
891
- }
892
-
893
- $old_value = get_post_meta( $oldpost->ID, '_stock', true );
894
- $new_value = isset( $post_array['_stock'] ) ? $post_array['_stock'] : null;
895
 
896
- if ( ($new_value) && ($old_value != $new_value) ) {
897
- $editor_link = $this->GetEditorLink( $oldpost );
898
- $this->plugin->alerts->Trigger(
899
- 9019, array(
900
- 'ProductTitle' => $oldpost->post_title,
901
- 'OldValue' => ( ! empty( $old_value ) ? $old_value : 0),
902
- 'NewValue' => $new_value,
903
- $editor_link['name'] => $editor_link['value'],
904
- )
905
- );
906
- return 1;
 
907
  }
908
  return 0;
909
  }
@@ -927,17 +923,17 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
927
 
928
  $result = 0;
929
  if ( 'trash' != $oldpost->post_status && 'trash' != $newpost->post_status ) {
930
- $old_virtual = get_post_meta( $oldpost->ID, '_virtual', true );
931
- $new_virtual = isset( $post_array['_virtual'] ) ? 'yes' : 'no';
932
- $old_downloadable = get_post_meta( $oldpost->ID, '_downloadable', true );
933
  $new_downloadable = isset( $post_array['_downloadable'] ) ? 'yes' : 'no';
934
 
935
- if ( ($old_virtual && $new_virtual) && ($old_virtual != $new_virtual) ) {
936
- $type = ( 'no' == $new_virtual ) ? 'Non Virtual' : 'Virtual';
937
  $result = $this->EventType( $oldpost, $type );
938
  }
939
- if ( ($old_downloadable && $new_downloadable) && ($old_downloadable != $new_downloadable) ) {
940
- $type = ( 'no' == $new_downloadable ) ? 'Non Downloadable' : 'Downloadable';
941
  $result = $this->EventType( $oldpost, $type );
942
  }
943
  }
@@ -955,8 +951,8 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
955
  $editor_link = $this->GetEditorLink( $oldpost );
956
  $this->plugin->alerts->Trigger(
957
  9020, array(
958
- 'ProductTitle' => $oldpost->post_title,
959
- 'Type' => $type,
960
  $editor_link['name'] => $editor_link['value'],
961
  )
962
  );
@@ -982,13 +978,13 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
982
  $old_weight = get_post_meta( $oldpost->ID, '_weight', true );
983
  $new_weight = isset( $post_array['_weight'] ) ? $post_array['_weight'] : null;
984
 
985
- if ( ($new_weight) && ($old_weight != $new_weight) ) {
986
  $editor_link = $this->GetEditorLink( $oldpost );
987
  $this->plugin->alerts->Trigger(
988
  9021, array(
989
- 'ProductTitle' => $oldpost->post_title,
990
- 'OldWeight' => ( ! empty( $old_weight ) ? $old_weight : 0),
991
- 'NewWeight' => $new_weight,
992
  $editor_link['name'] => $editor_link['value'],
993
  )
994
  );
@@ -1013,7 +1009,7 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
1013
  return false;
1014
  }
1015
 
1016
- $result = 0;
1017
  $old_length = get_post_meta( $oldpost->ID, '_length', true );
1018
  $new_length = isset( $post_array['_length'] ) ? $post_array['_length'] : null;
1019
  $old_width = get_post_meta( $oldpost->ID, '_width', true );
@@ -1021,13 +1017,13 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
1021
  $old_height = get_post_meta( $oldpost->ID, '_height', true );
1022
  $new_height = isset( $post_array['_height'] ) ? $post_array['_height'] : null;
1023
 
1024
- if ( ($new_length) && ($old_length != $new_length) ) {
1025
  $result = $this->EventDimension( $oldpost, 'Length', $old_length, $new_length );
1026
  }
1027
- if ( ($new_width) && ($old_width != $new_width) ) {
1028
  $result = $this->EventDimension( $oldpost, 'Width', $old_width, $new_width );
1029
  }
1030
- if ( ($new_height) && ($old_height != $new_height) ) {
1031
  $result = $this->EventDimension( $oldpost, 'Height', $old_height, $new_height );
1032
  }
1033
  return $result;
@@ -1044,13 +1040,13 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
1044
  */
1045
  private function EventDimension( $oldpost, $type, $old_dimension, $new_dimension ) {
1046
  $dimension_unit = $this->GetConfig( 'dimension_unit' );
1047
- $editor_link = $this->GetEditorLink( $oldpost );
1048
  $this->plugin->alerts->Trigger(
1049
  9022, array(
1050
- 'ProductTitle' => $oldpost->post_title,
1051
- 'DimensionType' => $type,
1052
- 'OldDimension' => ( ! empty( $old_dimension ) ? $dimension_unit . ' ' . $old_dimension : 0),
1053
- 'NewDimension' => $dimension_unit . ' ' . $new_dimension,
1054
  $editor_link['name'] => $editor_link['value'],
1055
  )
1056
  );
@@ -1073,13 +1069,13 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
1073
  return false;
1074
  }
1075
 
1076
- $result = 0;
1077
- $is_url_changed = false;
1078
  $is_name_changed = false;
1079
- $new_file_names = ! empty( $post_array['_wc_file_names'] ) ? $post_array['_wc_file_names'] : array();
1080
- $new_file_urls = ! empty( $post_array['_wc_file_urls'] ) ? $post_array['_wc_file_urls'] : array();
1081
- $editor_link = $this->GetEditorLink( $oldpost );
1082
- $added_urls = array_diff( $new_file_urls, $this->_old_file_urls );
1083
 
1084
  // Added files to the product.
1085
  if ( count( $added_urls ) > 0 ) {
@@ -1090,9 +1086,9 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
1090
  foreach ( $added_urls as $key => $url ) {
1091
  $this->plugin->alerts->Trigger(
1092
  9023, array(
1093
- 'ProductTitle' => $oldpost->post_title,
1094
- 'FileName' => $new_file_names[ $key ],
1095
- 'FileUrl' => $url,
1096
  $editor_link['name'] => $editor_link['value'],
1097
  )
1098
  );
@@ -1111,9 +1107,9 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
1111
  foreach ( $removed_urls as $key => $url ) {
1112
  $this->plugin->alerts->Trigger(
1113
  9024, array(
1114
- 'ProductTitle' => $oldpost->post_title,
1115
- 'FileName' => $this->_old_file_names[ $key ],
1116
- 'FileUrl' => $url,
1117
  $editor_link['name'] => $editor_link['value'],
1118
  )
1119
  );
@@ -1129,9 +1125,9 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
1129
  foreach ( $added_names as $key => $name ) {
1130
  $this->plugin->alerts->Trigger(
1131
  9025, array(
1132
- 'ProductTitle' => $oldpost->post_title,
1133
- 'OldName' => $this->_old_file_names[ $key ],
1134
- 'NewName' => $name,
1135
  $editor_link['name'] => $editor_link['value'],
1136
  )
1137
  );
@@ -1144,10 +1140,10 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
1144
  foreach ( $added_urls as $key => $url ) {
1145
  $this->plugin->alerts->Trigger(
1146
  9026, array(
1147
- 'ProductTitle' => $oldpost->post_title,
1148
- 'FileName' => $new_file_names[ $key ],
1149
- 'OldUrl' => $removed_urls[ $key ],
1150
- 'NewUrl' => $url,
1151
  $editor_link['name'] => $editor_link['value'],
1152
  )
1153
  );
@@ -1163,7 +1159,7 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
1163
  protected function CheckSettingsChange() {
1164
  // Filter POST and GET global arrays.
1165
  $post_array = filter_input_array( INPUT_POST );
1166
- $get_array = filter_input_array( INPUT_GET );
1167
 
1168
  if ( isset( $post_array['_wpnonce'] )
1169
  && ! wp_verify_nonce( $post_array['_wpnonce'], 'woocommerce-settings' ) ) {
@@ -1354,7 +1350,7 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
1354
  // If the URL is not empty then set values.
1355
  if ( ! empty( $value ) ) {
1356
  $editor_link = array(
1357
- 'name' => $name, // Meta key.
1358
  'value' => $value, // Meta value.
1359
  );
1360
  } else {
@@ -1382,7 +1378,7 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
1382
  }
1383
 
1384
  $editor_link = array(
1385
- 'name' => $name, // Meta key.
1386
  'value' => $link, // Meta value.
1387
  );
1388
  }
@@ -1390,6 +1386,105 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
1390
  return $editor_link;
1391
  }
1392
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1393
  /**
1394
  * Get Currency symbol.
1395
  *
@@ -1397,7 +1492,7 @@ class WSAL_Sensors_WooCommerce extends WSAL_AbstractSensor {
1397
  * @return string
1398
  */
1399
  private function GetCurrencySymbol( $currency = '' ) {
1400
- $symbols = array(
1401
  'AED' => '&#x62f;.&#x625;',
1402
  'AFN' => '&#x60b;',
1403
  'ALL' => 'L',
115
  * Listening to events using WP hooks.
116
  */
117
  public function HookEvents() {
118
+ // Check if WooCommerce plugin exists.
119
+ if ( ! is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
120
+ return false;
121
+ }
122
+
123
  if ( current_user_can( 'edit_posts' ) ) {
124
  add_action( 'admin_init', array( $this, 'EventAdminInit' ) );
125
  }
129
  add_action( 'untrash_post', array( $this, 'EventUntrashed' ) );
130
 
131
  add_action( 'create_product_cat', array( $this, 'EventCategoryCreation' ), 10, 1 );
 
132
 
133
  // Detect live change in stock.
134
  add_filter( 'woocommerce_order_item_quantity', array( $this, 'set_old_stock' ), 10, 3 );
135
  add_action( 'woocommerce_product_set_stock', array( $this, 'product_stock_changed' ), 10, 1 );
136
+
137
+ add_action( 'wp_head', array( $this, 'viewing_product' ), 10 );
138
+ add_filter( 'post_edit_form_tag', array( $this, 'editing_product' ), 10, 1 );
139
  }
140
 
141
  /**
157
  $product_with_stock = wc_get_product( $product_id_with_stock );
158
 
159
  // Set stock attributes of the product.
160
+ $this->_old_stock = $product_with_stock->get_stock_quantity();
161
  $this->_old_stock_status = $product_with_stock->get_stock_status();
162
 
163
  // Return original stock quantity.
205
  $old_stock_status = '';
206
  }
207
  } else {
208
+ $old_stock = $this->_old_stock; // Get old stock quantity.
209
  $old_stock_status = $this->_old_stock_status; // Get old stock status.
210
  }
211
 
212
+ $new_stock = $product->get_stock_quantity(); // Get new stock quantity.
213
  $new_stock_status = $product->get_stock_status(); // Get new stock status.
214
+ $product_title = $product->get_title(); // Get product title.
215
 
216
  // Set post object.
217
+ $post = new stdClass();
218
  $post->ID = $product_id;
219
 
220
  // Set username.
230
  $editor_link = $this->GetEditorLink( $post );
231
  $this->plugin->alerts->Trigger(
232
  9018, array(
233
+ 'ProductTitle' => $product_title,
234
+ 'OldStatus' => $this->GetStockStatusName( $old_stock_status ),
235
+ 'NewStatus' => $this->GetStockStatusName( $new_stock_status ),
236
+ 'Username' => $username,
237
  $editor_link['name'] => $editor_link['value'],
238
  )
239
  );
240
  }
241
 
242
+ $wc_all_stock_changes = $this->plugin->GetGlobalOption( 'wc-all-stock-changes', 'on' );
243
+
244
  // If stock has changed then trigger the alert.
245
+ if ( ( $old_stock !== $new_stock ) && ( 'on' === $wc_all_stock_changes ) ) {
246
  $editor_link = $this->GetEditorLink( $post );
247
  $this->plugin->alerts->Trigger(
248
  9019, array(
249
+ 'ProductTitle' => $product_title,
250
+ 'OldValue' => ( ! empty( $old_stock ) ? $old_stock : 0 ),
251
+ 'NewValue' => $new_stock,
252
+ 'Username' => $username,
253
  $editor_link['name'] => $editor_link['value'],
254
  )
255
  );
281
  }
282
 
283
  if ( isset( $post_array ) && isset( $post_array['post_ID'] )
284
+ && ! ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
285
+ && ! ( isset( $post_array['action'] ) && 'autosave' == $post_array['action'] )
286
  ) {
287
+ $post_id = intval( $post_array['post_ID'] );
288
+ $this->_old_post = get_post( $post_id );
289
+ $this->_old_link = get_post_permalink( $post_id, false, true );
290
+ $this->_old_cats = $this->GetProductCategories( $this->_old_post );
291
+ $this->_old_data = $this->GetProductData( $this->_old_post );
292
+ $this->_old_stock = get_post_meta( $post_id, '_stock', true );
293
  $this->_old_stock_status = get_post_meta( $post_id, '_stock_status', true );
294
 
295
+ $old_downloadable_files = get_post_meta( $post_id, '_downloadable_files', true );
296
  if ( ! empty( $old_downloadable_files ) ) {
297
  foreach ( $old_downloadable_files as $file ) {
298
  array_push( $this->_old_file_names, $file['name'] );
377
  if ( 'draft' == $new_post->post_status ) {
378
  $this->plugin->alerts->Trigger(
379
  9000, array(
380
+ 'ProductTitle' => $new_post->post_title,
381
  $editor_link['name'] => $editor_link['value'],
382
  )
383
  );
385
  } elseif ( 'publish' == $new_post->post_status ) {
386
  $this->plugin->alerts->Trigger(
387
  9001, array(
388
+ 'ProductTitle' => $new_post->post_title,
389
+ 'ProductUrl' => get_post_permalink( $new_post->ID ),
390
  $editor_link['name'] => $editor_link['value'],
391
  )
392
  );
408
  $this->plugin->alerts->Trigger(
409
  9002, array(
410
  'CategoryName' => $term->name,
411
+ 'Slug' => $term->slug,
412
  )
413
  );
414
  }
415
  }
416
 
 
 
 
 
 
 
 
 
 
 
 
 
 
417
  /**
418
  * Trigger events 9003
419
  *
433
  $editor_link = $this->GetEditorLink( $newpost );
434
  $this->plugin->alerts->Trigger(
435
  9003, array(
436
+ 'ProductTitle' => $newpost->post_title,
437
+ 'OldCategories' => $old_cats ? $old_cats : 'no categories',
438
+ 'NewCategories' => $new_cats ? $new_cats : 'no categories',
439
  $editor_link['name'] => $editor_link['value'],
440
  )
441
  );
459
  $editor_link = $this->GetEditorLink( $oldpost );
460
  $this->plugin->alerts->Trigger(
461
  9004, array(
462
+ 'ProductTitle' => $oldpost->post_title,
463
+ 'OldDescription' => $oldpost->post_excerpt,
464
+ 'NewDescription' => $newpost->post_excerpt,
465
  $editor_link['name'] => $editor_link['value'],
466
  )
467
  );
485
  $editor_link = $this->GetEditorLink( $oldpost );
486
  $this->plugin->alerts->Trigger(
487
  9005, array(
488
+ 'ProductTitle' => $oldpost->post_title,
489
  $editor_link['name'] => $editor_link['value'],
490
  )
491
  );
503
  * @return int
504
  */
505
  protected function CheckPermalinkChange( $old_link, $new_link, $post ) {
506
+ if ( ( $old_link && $new_link ) && ( $old_link != $new_link ) ) {
507
  $editor_link = $this->GetEditorLink( $post );
508
  $this->plugin->alerts->Trigger(
509
  9006, array(
510
+ 'ProductTitle' => $post->post_title,
511
+ 'OldUrl' => $old_link,
512
+ 'NewUrl' => $new_link,
513
  $editor_link['name'] => $editor_link['value'],
514
+ 'ReportText' => '"' . $old_link . '"|"' . $new_link . '"',
515
  )
516
  );
517
  return 1;
543
  $editor_link = $this->GetEditorLink( $post );
544
  $this->plugin->alerts->Trigger(
545
  9007, array(
546
+ 'ProductTitle' => $post->post_title,
547
  $editor_link['name'] => $editor_link['value'],
548
  )
549
  );
565
  return 0;
566
  }
567
  $from = strtotime( $oldpost->post_date );
568
+ $to = strtotime( $newpost->post_date );
569
  if ( $from != $to ) {
570
  $editor_link = $this->GetEditorLink( $oldpost );
571
  $this->plugin->alerts->Trigger(
572
  9008, array(
573
+ 'ProductTitle' => $oldpost->post_title,
574
+ 'OldDate' => $oldpost->post_date,
575
+ 'NewDate' => $newpost->post_date,
576
  $editor_link['name'] => $editor_link['value'],
577
  )
578
  );
612
  $new_visibility = ucfirst( $new_visibility );
613
  }
614
 
615
+ if ( ( $old_visibility && $new_visibility ) && ( $old_visibility != $new_visibility ) ) {
616
  $editor_link = $this->GetEditorLink( $oldpost );
617
  $this->plugin->alerts->Trigger(
618
  9009, array(
619
+ 'ProductTitle' => $oldpost->post_title,
620
+ 'OldVisibility' => $old_visibility,
621
+ 'NewVisibility' => $new_visibility,
622
  $editor_link['name'] => $editor_link['value'],
623
  )
624
  );
653
  if ( 'publish' == $oldpost->post_status ) {
654
  $this->plugin->alerts->Trigger(
655
  9010, array(
656
+ 'ProductTitle' => $oldpost->post_title,
657
+ 'ProductUrl' => get_post_permalink( $oldpost->ID ),
658
  $editor_link['name'] => $editor_link['value'],
659
  )
660
  );
661
  } elseif ( 'draft' == $oldpost->post_status ) {
662
  $this->plugin->alerts->Trigger(
663
  9011, array(
664
+ 'ProductTitle' => $oldpost->post_title,
665
  $editor_link['name'] => $editor_link['value'],
666
  )
667
  );
679
  $this->plugin->alerts->Trigger(
680
  9012, array(
681
  'ProductTitle' => $post->post_title,
682
+ 'ProductUrl' => get_post_permalink( $post->ID ),
683
  )
684
  );
685
  }
712
  $editor_link = $this->GetEditorLink( $post );
713
  $this->plugin->alerts->Trigger(
714
  9014, array(
715
+ 'ProductTitle' => $post->post_title,
716
  $editor_link['name'] => $editor_link['value'],
717
  )
718
  );
735
  $editor_link = $this->GetEditorLink( $oldpost );
736
  $this->plugin->alerts->Trigger(
737
  9015, array(
738
+ 'ProductTitle' => $oldpost->post_title,
739
+ 'OldStatus' => $oldpost->post_status,
740
+ 'NewStatus' => $newpost->post_status,
741
  $editor_link['name'] => $editor_link['value'],
742
  )
743
  );
763
  return false;
764
  }
765
 
766
+ $result = 0;
767
+ $old_price = get_post_meta( $oldpost->ID, '_regular_price', true );
768
  $old_sale_price = get_post_meta( $oldpost->ID, '_sale_price', true );
769
+ $new_price = isset( $post_array['_regular_price'] ) ? $post_array['_regular_price'] : null;
770
  $new_sale_price = isset( $post_array['_sale_price'] ) ? $post_array['_sale_price'] : null;
771
 
772
+ if ( ( $new_price ) && ( $old_price != $new_price ) ) {
773
  $result = $this->EventPrice( $oldpost, 'Regular price', $old_price, $new_price );
774
  }
775
+ if ( ( $new_sale_price ) && ( $old_sale_price != $new_sale_price ) ) {
776
  $result = $this->EventPrice( $oldpost, 'Sale price', $old_sale_price, $new_sale_price );
777
  }
778
  return $result;
788
  * @return int
789
  */
790
  private function EventPrice( $oldpost, $type, $old_price, $new_price ) {
791
+ $currency = $this->GetCurrencySymbol( $this->GetConfig( 'currency' ) );
792
  $editor_link = $this->GetEditorLink( $oldpost );
793
  $this->plugin->alerts->Trigger(
794
  9016, array(
795
+ 'ProductTitle' => $oldpost->post_title,
796
+ 'PriceType' => $type,
797
+ 'OldPrice' => ( ! empty( $old_price ) ? $currency . $old_price : 0 ),
798
+ 'NewPrice' => $currency . $new_price,
799
  $editor_link['name'] => $editor_link['value'],
800
  )
801
  );
821
  $old_sku = get_post_meta( $oldpost->ID, '_sku', true );
822
  $new_sku = isset( $post_array['_sku'] ) ? $post_array['_sku'] : null;
823
 
824
+ if ( ( $new_sku ) && ( $old_sku != $new_sku ) ) {
825
  $editor_link = $this->GetEditorLink( $oldpost );
826
  $this->plugin->alerts->Trigger(
827
  9017, array(
828
+ 'ProductTitle' => $oldpost->post_title,
829
+ 'OldSku' => ( ! empty( $old_sku ) ? $old_sku : 0 ),
830
+ 'NewSku' => $new_sku,
831
  $editor_link['name'] => $editor_link['value'],
832
  )
833
  );
855
  $old_status = $this->_old_stock_status;
856
  $new_status = isset( $post_array['_stock_status'] ) ? $post_array['_stock_status'] : null;
857
 
858
+ if ( ( $old_status && $new_status ) && ( $old_status != $new_status ) ) {
859
  $editor_link = $this->GetEditorLink( $oldpost );
860
  $this->plugin->alerts->Trigger(
861
  9018, array(
862
+ 'ProductTitle' => $oldpost->post_title,
863
+ 'OldStatus' => $this->GetStockStatusName( $old_status ),
864
+ 'NewStatus' => $this->GetStockStatusName( $new_status ),
865
  $editor_link['name'] => $editor_link['value'],
866
  )
867
  );
880
  // Filter POST global array.
881
  $post_array = filter_input_array( INPUT_POST );
882
 
883
+ if (
884
+ isset( $post_array['post_ID'] )
885
  && isset( $post_array['_wpnonce'] )
886
+ && wp_verify_nonce( $post_array['_wpnonce'], 'update-post_' . $post_array['post_ID'] )
887
+ ) {
888
+ $old_value = (int) get_post_meta( $oldpost->ID, '_stock', true );
889
+ $new_value = isset( $post_array['_stock'] ) ? (int) $post_array['_stock'] : null;
 
 
890
 
891
+ if ( $new_value && ( $old_value !== $new_value ) ) {
892
+ $editor_link = $this->GetEditorLink( $oldpost );
893
+ $this->plugin->alerts->Trigger(
894
+ 9019, array(
895
+ 'ProductTitle' => $oldpost->post_title,
896
+ 'OldValue' => ( ! empty( $old_value ) ? $old_value : 0 ),
897
+ 'NewValue' => $new_value,
898
+ $editor_link['name'] => $editor_link['value'],
899
+ )
900
+ );
901
+ return 1;
902
+ }
903
  }
904
  return 0;
905
  }
923
 
924
  $result = 0;
925
  if ( 'trash' != $oldpost->post_status && 'trash' != $newpost->post_status ) {
926
+ $old_virtual = get_post_meta( $oldpost->ID, '_virtual', true );
927
+ $new_virtual = isset( $post_array['_virtual'] ) ? 'yes' : 'no';
928
+ $old_downloadable = get_post_meta( $oldpost->ID, '_downloadable', true );
929
  $new_downloadable = isset( $post_array['_downloadable'] ) ? 'yes' : 'no';
930
 
931
+ if ( ( $old_virtual && $new_virtual ) && ( $old_virtual != $new_virtual ) ) {
932
+ $type = ( 'no' == $new_virtual ) ? 'Non Virtual' : 'Virtual';
933
  $result = $this->EventType( $oldpost, $type );
934
  }
935
+ if ( ( $old_downloadable && $new_downloadable ) && ( $old_downloadable != $new_downloadable ) ) {
936
+ $type = ( 'no' == $new_downloadable ) ? 'Non Downloadable' : 'Downloadable';
937
  $result = $this->EventType( $oldpost, $type );
938
  }
939
  }
951
  $editor_link = $this->GetEditorLink( $oldpost );
952
  $this->plugin->alerts->Trigger(
953
  9020, array(
954
+ 'ProductTitle' => $oldpost->post_title,
955
+ 'Type' => $type,
956
  $editor_link['name'] => $editor_link['value'],
957
  )
958
  );
978
  $old_weight = get_post_meta( $oldpost->ID, '_weight', true );
979
  $new_weight = isset( $post_array['_weight'] ) ? $post_array['_weight'] : null;
980
 
981
+ if ( ( $new_weight ) && ( $old_weight != $new_weight ) ) {
982
  $editor_link = $this->GetEditorLink( $oldpost );
983
  $this->plugin->alerts->Trigger(
984
  9021, array(
985
+ 'ProductTitle' => $oldpost->post_title,
986
+ 'OldWeight' => ( ! empty( $old_weight ) ? $old_weight : 0 ),
987
+ 'NewWeight' => $new_weight,
988
  $editor_link['name'] => $editor_link['value'],
989
  )
990
  );
1009
  return false;
1010
  }
1011
 
1012
+ $result = 0;
1013
  $old_length = get_post_meta( $oldpost->ID, '_length', true );
1014
  $new_length = isset( $post_array['_length'] ) ? $post_array['_length'] : null;
1015
  $old_width = get_post_meta( $oldpost->ID, '_width', true );
1017
  $old_height = get_post_meta( $oldpost->ID, '_height', true );
1018
  $new_height = isset( $post_array['_height'] ) ? $post_array['_height'] : null;
1019
 
1020
+ if ( ( $new_length ) && ( $old_length != $new_length ) ) {
1021
  $result = $this->EventDimension( $oldpost, 'Length', $old_length, $new_length );
1022
  }
1023
+ if ( ( $new_width ) && ( $old_width != $new_width ) ) {
1024
  $result = $this->EventDimension( $oldpost, 'Width', $old_width, $new_width );
1025
  }
1026
+ if ( ( $new_height ) && ( $old_height != $new_height ) ) {
1027
  $result = $this->EventDimension( $oldpost, 'Height', $old_height, $new_height );
1028
  }
1029
  return $result;
1040
  */
1041
  private function EventDimension( $oldpost, $type, $old_dimension, $new_dimension ) {
1042
  $dimension_unit = $this->GetConfig( 'dimension_unit' );
1043
+ $editor_link = $this->GetEditorLink( $oldpost );
1044
  $this->plugin->alerts->Trigger(
1045
  9022, array(
1046
+ 'ProductTitle' => $oldpost->post_title,
1047
+ 'DimensionType' => $type,
1048
+ 'OldDimension' => ( ! empty( $old_dimension ) ? $dimension_unit . ' ' . $old_dimension : 0 ),
1049
+ 'NewDimension' => $dimension_unit . ' ' . $new_dimension,
1050
  $editor_link['name'] => $editor_link['value'],
1051
  )
1052
  );
1069
  return false;
1070
  }
1071
 
1072
+ $result = 0;
1073
+ $is_url_changed = false;
1074
  $is_name_changed = false;
1075
+ $new_file_names = ! empty( $post_array['_wc_file_names'] ) ? $post_array['_wc_file_names'] : array();
1076
+ $new_file_urls = ! empty( $post_array['_wc_file_urls'] ) ? $post_array['_wc_file_urls'] : array();
1077
+ $editor_link = $this->GetEditorLink( $oldpost );
1078
+ $added_urls = array_diff( $new_file_urls, $this->_old_file_urls );
1079
 
1080
  // Added files to the product.
1081
  if ( count( $added_urls ) > 0 ) {
1086
  foreach ( $added_urls as $key => $url ) {
1087
  $this->plugin->alerts->Trigger(
1088
  9023, array(
1089
+ 'ProductTitle' => $oldpost->post_title,
1090
+ 'FileName' => $new_file_names[ $key ],
1091
+ 'FileUrl' => $url,
1092
  $editor_link['name'] => $editor_link['value'],
1093
  )
1094
  );
1107
  foreach ( $removed_urls as $key => $url ) {
1108
  $this->plugin->alerts->Trigger(
1109
  9024, array(
1110
+ 'ProductTitle' => $oldpost->post_title,
1111
+ 'FileName' => $this->_old_file_names[ $key ],
1112
+ 'FileUrl' => $url,
1113
  $editor_link['name'] => $editor_link['value'],
1114
  )
1115
  );
1125
  foreach ( $added_names as $key => $name ) {
1126
  $this->plugin->alerts->Trigger(
1127
  9025, array(
1128
+ 'ProductTitle' => $oldpost->post_title,
1129
+ 'OldName' => $this->_old_file_names[ $key ],
1130
+ 'NewName' => $name,
1131
  $editor_link['name'] => $editor_link['value'],
1132
  )
1133
  );
1140
  foreach ( $added_urls as $key => $url ) {
1141
  $this->plugin->alerts->Trigger(
1142
  9026, array(
1143
+ 'ProductTitle' => $oldpost->post_title,
1144
+ 'FileName' => $new_file_names[ $key ],
1145
+ 'OldUrl' => $removed_urls[ $key ],
1146
+ 'NewUrl' => $url,
1147
  $editor_link['name'] => $editor_link['value'],
1148
  )
1149
  );
1159
  protected function CheckSettingsChange() {
1160
  // Filter POST and GET global arrays.
1161
  $post_array = filter_input_array( INPUT_POST );
1162
+ $get_array = filter_input_array( INPUT_GET );
1163
 
1164
  if ( isset( $post_array['_wpnonce'] )
1165
  && ! wp_verify_nonce( $post_array['_wpnonce'], 'woocommerce-settings' ) ) {
1350
  // If the URL is not empty then set values.
1351
  if ( ! empty( $value ) ) {
1352
  $editor_link = array(
1353
+ 'name' => $name, // Meta key.
1354
  'value' => $value, // Meta value.
1355
  );
1356
  } else {
1378
  }
1379
 
1380
  $editor_link = array(
1381
+ 'name' => $name, // Meta key.
1382
  'value' => $link, // Meta value.
1383
  );
1384
  }
1386
  return $editor_link;
1387
  }
1388
 
1389
+ /**
1390
+ * Alerts for viewing of product post type for WooCommerce.
1391
+ */
1392
+ public function viewing_product() {
1393
+ // Retrieve the current post object.
1394
+ $product = get_queried_object();
1395
+
1396
+ // Check product post type.
1397
+ if ( ! empty( $product ) && $product instanceof WP_Post && 'product' !== $product->post_type ) {
1398
+ return $product;
1399
+ }
1400
+
1401
+ if ( is_user_logged_in() && ! is_admin() ) {
1402
+ // Filter $_SERVER array for security.
1403
+ $server_array = filter_input_array( INPUT_SERVER );
1404
+
1405
+ $current_path = isset( $server_array['REQUEST_URI'] ) ? $server_array['REQUEST_URI'] : false;
1406
+ if ( ! empty( $server_array['HTTP_REFERER'] )
1407
+ && ! empty( $current_path )
1408
+ && strpos( $server_array['HTTP_REFERER'], $current_path ) !== false ) {
1409
+ // Ignore this if we were on the same page so we avoid double audit entries.
1410
+ return;
1411
+ }
1412
+ if ( ! empty( $product->post_title ) ) {
1413
+ $editor_link = $this->GetEditorLink( $product );
1414
+ $this->plugin->alerts->Trigger(
1415
+ 9073, array(
1416
+ 'PostID' => $product->ID,
1417
+ 'PostType' => $product->post_type,
1418
+ 'ProductStatus' => $product->post_status,
1419
+ 'ProductTitle' => $product->post_title,
1420
+ 'ProductUrl' => get_permalink( $product->ID ),
1421
+ $editor_link['name'] => $editor_link['value'],
1422
+ )
1423
+ );
1424
+ }
1425
+ }
1426
+ }
1427
+
1428
+ /**
1429
+ * Alerts for editing of product post type for WooCommerce.
1430
+ *
1431
+ * @param WP_Post $product - Product post type.
1432
+ */
1433
+ public function editing_product( $product ) {
1434
+ // Check product post type.
1435
+ if ( 'product' !== $product->post_type ) {
1436
+ return $product;
1437
+ }
1438
+
1439
+ if ( is_user_logged_in() && is_admin() ) {
1440
+ // Filter $_SERVER array for security.
1441
+ $server_array = filter_input_array( INPUT_SERVER );
1442
+
1443
+ $current_path = isset( $server_array['SCRIPT_NAME'] ) ? $server_array['SCRIPT_NAME'] . '?post=' . $product->ID : false;
1444
+ if ( ! empty( $server_array['HTTP_REFERER'] )
1445
+ && strpos( $server_array['HTTP_REFERER'], $current_path ) !== false ) {
1446
+ // Ignore this if we were on the same page so we avoid double audit entries.
1447
+ return $product;
1448
+ }
1449
+ if ( ! empty( $product->post_title ) ) {
1450
+ $event = 9072;
1451
+ if ( ! $this->WasTriggered( $event ) ) {
1452
+ $editor_link = $this->GetEditorLink( $product );
1453
+ $this->plugin->alerts->Trigger(
1454
+ $event, array(
1455
+ 'PostID' => $product->ID,
1456
+ 'PostType' => $product->post_type,
1457
+ 'ProductStatus' => $product->post_status,
1458
+ 'ProductTitle' => $product->post_title,
1459
+ 'ProductUrl' => get_permalink( $product->ID ),
1460
+ $editor_link['name'] => $editor_link['value'],
1461
+ )
1462
+ );
1463
+ }
1464
+ }
1465
+ }
1466
+ return $product;
1467
+ }
1468
+
1469
+ /**
1470
+ * Check if the alert was triggered.
1471
+ *
1472
+ * @param integer $alert_id - Alert code.
1473
+ * @return boolean
1474
+ */
1475
+ private function WasTriggered( $alert_id ) {
1476
+ $query = new WSAL_Models_OccurrenceQuery();
1477
+ $query->addOrderBy( 'created_on', true );
1478
+ $query->setLimit( 1 );
1479
+ $last_occurence = $query->getAdapter()->Execute( $query );
1480
+ if ( ! empty( $last_occurence ) ) {
1481
+ if ( $last_occurence[0]->alert_id === $alert_id ) {
1482
+ return true;
1483
+ }
1484
+ }
1485
+ return false;
1486
+ }
1487
+
1488
  /**
1489
  * Get Currency symbol.
1490
  *
1492
  * @return string
1493
  */
1494
  private function GetCurrencySymbol( $currency = '' ) {
1495
+ $symbols = array(
1496
  'AED' => '&#x62f;.&#x625;',
1497
  'AFN' => '&#x60b;',
1498
  'ALL' => 'L',
classes/Sensors/YoastSEO.php CHANGED
@@ -55,7 +55,7 @@ class WSAL_Sensors_YoastSEO extends WSAL_AbstractSensor {
55
  * Listening to events using hooks.
56
  */
57
  public function HookEvents() {
58
- // Check if Yoast SEO file exists.
59
  if ( ! is_plugin_active( 'wordpress-seo/wp-seo.php' ) ) {
60
  return false;
61
  }
@@ -799,3 +799,4 @@ class WSAL_Sensors_YoastSEO extends WSAL_AbstractSensor {
799
  }
800
  }
801
  }
 
55
  * Listening to events using hooks.
56
  */
57
  public function HookEvents() {
58
+ // Check if Yoast SEO plugin exists.
59
  if ( ! is_plugin_active( 'wordpress-seo/wp-seo.php' ) ) {
60
  return false;
61
  }
799
  }
800
  }
801
  }
802
+
classes/Settings.php CHANGED
@@ -110,6 +110,14 @@ class WSAL_Settings {
110
  */
111
  protected $_excluded_ip = array();
112
 
 
 
 
 
 
 
 
 
113
  /**
114
  * Method: Constructor.
115
  *
@@ -793,13 +801,43 @@ class WSAL_Settings {
793
  }
794
 
795
  /**
796
- * Roles excluded from monitoring.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
797
  */
798
  public function SetExcludedMonitoringRoles( $roles ) {
799
  $this->_excluded_roles = $roles;
800
  $this->_plugin->SetGlobalOption( 'excluded-roles', esc_html( implode( ',', $this->_excluded_roles ) ) );
801
  }
802
 
 
 
 
803
  public function GetExcludedMonitoringRoles() {
804
  if ( empty( $this->_excluded_roles ) ) {
805
  $this->_excluded_roles = array_unique( array_filter( explode( ',', $this->_plugin->GetGlobalOption( 'excluded-roles' ) ) ) );
110
  */
111
  protected $_excluded_ip = array();
112
 
113
+ /**
114
+ * URLs excluded from monitoring.
115
+ *
116
+ * @var array
117
+ * @since 3.2.2
118
+ */
119
+ protected $excluded_urls = array();
120
+
121
  /**
122
  * Method: Constructor.
123
  *
801
  }
802
 
803
  /**
804
+ * Set URLs excluded from monitoring.
805
+ *
806
+ * @param array $urls - Array of URLs.
807
+ * @since 3.2.2
808
+ */
809
+ public function set_excluded_urls( $urls ) {
810
+ $urls = array_map( 'untrailingslashit', $urls );
811
+ $urls = array_unique( $urls );
812
+ $this->excluded_urls = $urls;
813
+ $this->_plugin->SetGlobalOption( 'excluded-urls', esc_html( implode( ',', $this->excluded_urls ) ) );
814
+ }
815
+
816
+ /**
817
+ * Get URLs excluded from monitoring.
818
+ *
819
+ * @since 3.2.2
820
+ */
821
+ public function get_excluded_urls() {
822
+ if ( empty( $this->excluded_urls ) ) {
823
+ $this->excluded_urls = array_unique( array_filter( explode( ',', $this->_plugin->GetGlobalOption( 'excluded-urls' ) ) ) );
824
+ }
825
+ return $this->excluded_urls;
826
+ }
827
+
828
+ /**
829
+ * Set roles excluded from monitoring.
830
+ *
831
+ * @param array $roles - Array of roles.
832
  */
833
  public function SetExcludedMonitoringRoles( $roles ) {
834
  $this->_excluded_roles = $roles;
835
  $this->_plugin->SetGlobalOption( 'excluded-roles', esc_html( implode( ',', $this->_excluded_roles ) ) );
836
  }
837
 
838
+ /**
839
+ * Get roles excluded from monitoring.
840
+ */
841
  public function GetExcludedMonitoringRoles() {
842
  if ( empty( $this->_excluded_roles ) ) {
843
  $this->_excluded_roles = array_unique( array_filter( explode( ',', $this->_plugin->GetGlobalOption( 'excluded-roles' ) ) ) );
classes/ViewManager.php CHANGED
@@ -43,7 +43,7 @@ class WSAL_ViewManager {
43
  $skip_views = array();
44
 
45
  // Array of views to skip for premium version.
46
- if ( wsal_freemius()->is_plan__premium_only( 'starter' ) ) {
47
  $skip_views[] = dirname( __FILE__ ) . '/Views/EmailNotifications.php';
48
  $skip_views[] = dirname( __FILE__ ) . '/Views/ExternalDB.php';
49
  $skip_views[] = dirname( __FILE__ ) . '/Views/Licensing.php';
43
  $skip_views = array();
44
 
45
  // Array of views to skip for premium version.
46
+ if ( wsal_freemius()->can_use_premium_code() || wsal_freemius()->is_plan__premium_only( 'starter' ) ) {
47
  $skip_views[] = dirname( __FILE__ ) . '/Views/EmailNotifications.php';
48
  $skip_views[] = dirname( __FILE__ ) . '/Views/ExternalDB.php';
49
  $skip_views[] = dirname( __FILE__ ) . '/Views/Licensing.php';
classes/Views/AuditLog.php CHANGED
@@ -51,9 +51,12 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
51
  add_action( 'wp_ajax_wsal_download_failed_login_log', array( $this, 'wsal_download_failed_login_log' ) );
52
  add_action( 'wp_ajax_wsal_download_404_log', array( $this, 'wsal_download_404_log' ) );
53
  add_action( 'wp_ajax_wsal_freemius_opt_in', array( $this, 'wsal_freemius_opt_in' ) );
 
 
54
  add_action( 'all_admin_notices', array( $this, 'AdminNoticesPremium' ) );
55
  add_action( 'admin_enqueue_scripts', array( $this, 'load_pointers' ), 1000 );
56
  add_filter( 'wsal_pointers_toplevel_page_wsal-auditlog', array( $this, 'register_privacy_pointer' ), 10, 1 );
 
57
  // Check plugin version for to dismiss the notice only until upgrade.
58
  $this->_version = WSAL_VERSION;
59
  $this->RegisterNotice( 'premium-wsal-' . $this->_version ); // Upgrade notice.
@@ -129,10 +132,12 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
129
  }
130
 
131
  // Add connectivity notice.
132
- if ( ! $connection ) {
 
133
  ?>
134
- <div class="notice notice-error">
135
  <p><?php esc_html_e( 'There are connectivity issues with the database where the WordPress activity log is stored. The logs will be temporary buffered in the WordPress database until the connection is fully restored.', 'wp-security-audit-log' ); ?></p>
 
136
  </div>
137
  <?php
138
  }
@@ -166,6 +171,24 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
166
  }
167
  }
168
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  /**
170
  * Method: Check if view has shortcut link.
171
  */
@@ -741,4 +764,41 @@ class WSAL_Views_AuditLog extends WSAL_AbstractView {
741
  }
742
  return $pointer;
743
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
744
  }
51
  add_action( 'wp_ajax_wsal_download_failed_login_log', array( $this, 'wsal_download_failed_login_log' ) );
52
  add_action( 'wp_ajax_wsal_download_404_log', array( $this, 'wsal_download_404_log' ) );
53
  add_action( 'wp_ajax_wsal_freemius_opt_in', array( $this, 'wsal_freemius_opt_in' ) );
54
+ add_action( 'wp_ajax_wsal_exclude_url', array( $this, 'wsal_exclude_url' ) );
55
+ add_action( 'wp_ajax_wsal_dismiss_notice_disconnect', array( $this, 'dismiss_notice_disconnect' ) );
56
  add_action( 'all_admin_notices', array( $this, 'AdminNoticesPremium' ) );
57
  add_action( 'admin_enqueue_scripts', array( $this, 'load_pointers' ), 1000 );
58
  add_filter( 'wsal_pointers_toplevel_page_wsal-auditlog', array( $this, 'register_privacy_pointer' ), 10, 1 );
59
+
60
  // Check plugin version for to dismiss the notice only until upgrade.
61
  $this->_version = WSAL_VERSION;
62
  $this->RegisterNotice( 'premium-wsal-' . $this->_version ); // Upgrade notice.
132
  }
133
 
134
  // Add connectivity notice.
135
+ $notice_dismissed = get_transient( 'wsal-dismiss-notice-disconnect' );
136
+ if ( ! $connection && false === $notice_dismissed ) {
137
  ?>
138
+ <div class="notice notice-error is-dismissible" id="wsal-notice-connect-issue">
139
  <p><?php esc_html_e( 'There are connectivity issues with the database where the WordPress activity log is stored. The logs will be temporary buffered in the WordPress database until the connection is fully restored.', 'wp-security-audit-log' ); ?></p>
140
+ <?php wp_nonce_field( 'wsal_dismiss_notice_disconnect', 'wsal-dismiss-notice-disconnect', false, true ); ?>
141
  </div>
142
  <?php
143
  }
171
  }
172
  }
173
 
174
+ /**
175
+ * Method: Ajax handler for dismissing DB disconnect issue.
176
+ */
177
+ public function dismiss_notice_disconnect() {
178
+ // Get $_POST array arguments.
179
+ $post_array_args = array(
180
+ 'nonce' => FILTER_SANITIZE_STRING,
181
+ );
182
+ $post_array = filter_input_array( INPUT_POST, $post_array_args );
183
+
184
+ // Verify nonce.
185
+ if ( wp_verify_nonce( $post_array['nonce'], 'wsal_dismiss_notice_disconnect' ) ) {
186
+ set_transient( 'wsal-dismiss-notice-disconnect', 1, 6 * HOUR_IN_SECONDS );
187
+ die();
188
+ }
189
+ die( 'Nonce verification failed!' );
190
+ }
191
+
192
  /**
193
  * Method: Check if view has shortcut link.
194
  */
764
  }
765
  return $pointer;
766
  }
767
+
768
+ /**
769
+ * Method: Ajax request handler to exclude URL from
770
+ * the event.
771
+ *
772
+ * @since 3.2.2
773
+ */
774
+ public function wsal_exclude_url() {
775
+ // Die if user does not have permission to disable.
776
+ if ( ! $this->_plugin->settings->CurrentUserCan( 'edit' ) ) {
777
+ echo '<p>' . esc_html__( 'Error: You do not have sufficient permissions to exclude this URL.', 'wp-security-audit-log' ) . '</p>';
778
+ die();
779
+ }
780
+
781
+ // Set filter input args.
782
+ $filter_input_args = array(
783
+ 'nonce' => FILTER_SANITIZE_STRING,
784
+ 'url' => FILTER_SANITIZE_STRING,
785
+ );
786
+
787
+ // Filter $_POST array for security.
788
+ $post_array = filter_input_array( INPUT_POST, $filter_input_args );
789
+
790
+ if ( isset( $post_array['nonce'] ) && ! wp_verify_nonce( $post_array['nonce'], 'wsal-exclude-url-' . $post_array['url'] ) ) {
791
+ die();
792
+ }
793
+
794
+ $excluded_urls = $this->_plugin->GetGlobalOption( 'excluded-urls' );
795
+ if ( isset( $excluded_urls ) && '' !== $excluded_urls ) {
796
+ $excluded_urls .= ',' . esc_url( $post_array['url'] );
797
+ } else {
798
+ $excluded_urls = esc_url( $post_array['url'] );
799
+ }
800
+ $this->_plugin->SetGlobalOption( 'excluded-urls', $excluded_urls );
801
+ echo '<p>URL ' . esc_html( $post_array['url'] ) . ' is no longer being monitored.<br />Enable the monitoring of this URL again from the <a href="' . esc_url( admin_url( 'admin.php?page=wsal-settings#tab-exclude' ) ) . '">Excluded Objects</a> tab in the plugin settings.</p>';
802
+ die;
803
+ }
804
  }
classes/Views/Help.php CHANGED
@@ -55,6 +55,20 @@ class WSAL_Views_Help extends WSAL_AbstractView {
55
  * Method: Get View Header.
56
  */
57
  public function Header() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  wp_enqueue_style(
59
  'extensions',
60
  $this->_plugin->GetBaseUrl() . '/css/extensions.css',
@@ -68,139 +82,440 @@ class WSAL_Views_Help extends WSAL_AbstractView {
68
  */
69
  public function Render() {
70
  ?>
71
- <div class="metabox-holder" style="position: relative;">
72
- <div class="postbox">
73
- <div class="inside wsal-block">
74
- <div class="activity-block">
75
- <h2><?php esc_html_e( 'Getting Started', 'wp-security-audit-log' ); ?></h2>
76
- <p>
77
- <?php esc_html_e( 'Getting started with WP Security Audit Log is really easy; once the plugin is installed it will automatically keep a log of everything that is happening on your website and you do not need to do anything. Watch the video below for a quick overview of the plugin.', 'wp-security-audit-log' ); ?>
78
- </p>
79
- <p>
80
- <iframe class="wsal-youtube-embed" width="560" height="315" src="https://www.youtube.com/embed/1nopATCS-CQ?rel=0" frameborder="0" allowfullscreen></iframe>
81
- </p>
82
- </div>
83
- <!-- /.activity-block -->
84
-
85
- <div class="activity-block">
86
- <h2><?php esc_html_e( 'Plugin Support', 'wp-security-audit-log' ); ?></h2>
87
- <p>
88
- <?php esc_html_e( 'Have you encountered or noticed any issues while using WP Security Audit Log plugin?', 'wp-security-audit-log' ); ?>
89
- <?php esc_html_e( 'Or you want to report something to us? Click any of the options below to post on the plugin\'s forum or contact our support directly.', 'wp-security-audit-log' ); ?>
90
- </p><p>
91
- <a class="button" href="https://wordpress.org/support/plugin/wp-security-audit-log" target="_blank"><?php esc_html_e( 'Free Support Forum', 'wp-security-audit-log' ); ?></a>
92
- &nbsp;&nbsp;&nbsp;&nbsp;
93
- <a class="button" href="http://www.wpsecurityauditlog.com/contact/" target="_blank"><?php esc_html_e( 'Free Support Email', 'wp-security-audit-log' ); ?></a>
94
- </p>
95
- </div>
96
- <!-- /.activity-block -->
97
-
98
- <div class="activity-block">
99
- <h2><?php esc_html_e( 'Plugin Documentation', 'wp-security-audit-log' ); ?></h2>
100
- <p>
101
- <?php esc_html_e( 'For more technical information about the WP Security Audit Log plugin please visit the plugin’s knowledge base.', 'wp-security-audit-log' ); ?>
102
- <?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 audit log.', 'wp-security-audit-log' ); ?>
103
- </p><p>
104
- <a class="button" href="http://www.wpsecurityauditlog.com/?utm_source=plugin&amp;utm_medium=helppage&amp;utm_campaign=support" target="_blank"><?php esc_html_e( 'Plugin Website', 'wp-security-audit-log' ); ?></a>
105
- &nbsp;&nbsp;&nbsp;&nbsp;
106
- <a class="button" href="https://www.wpsecurityauditlog.com/support-documentation/?utm_source=plugin&amp;utm_medium=helppage&amp;utm_campaign=support" target="_blank"><?php esc_html_e( 'Knowledge Base', 'wp-security-audit-log' ); ?></a>
107
- &nbsp;&nbsp;&nbsp;&nbsp;
108
- <a class="button" href="http://www.wpsecurityauditlog.com/documentation/list-monitoring-wordpress-security-alerts-audit-log/?utm_source=plugin&amp;utm_medium=helppage&amp;utm_campaign=support" target="_blank"><?php esc_html_e( 'List of WordPress Security Events', 'wp-security-audit-log' ); ?></a>
109
- </p>
110
- </div>
111
- <!-- /.activity-block -->
112
-
113
- <div class="activity-block">
114
- <h2><?php esc_html_e( 'Rate WP Security Audit Log', 'wp-security-audit-log' ); ?></h2>
115
- <p>
116
- <?php esc_html_e( 'We work really hard to deliver a plugin that enables you to keep a record of all the changes that are happening on your WordPress.', 'wp-security-audit-log' ); ?>
117
- <?php esc_html_e( 'It takes thousands of man-hours every year and endless amount of dedication to research, develop and maintain the free edition of WP Security Audit Log.', 'wp-security-audit-log' ); ?>
118
- <?php esc_html_e( 'Therefore if you like what you see, and find WP Security Audit Log useful we ask you nothing more than to please rate our plugin.', 'wp-security-audit-log' ); ?>
119
- <?php esc_html_e( 'We appreciate every star!', 'wp-security-audit-log' ); ?>
120
- </p>
121
- <p>
122
- <a class="rating-link" href="https://en-gb.wordpress.org/plugins/wp-security-audit-log/#reviews" target="_blank">
123
- <span class="dashicons dashicons-star-filled"></span>
124
- <span class="dashicons dashicons-star-filled"></span>
125
- <span class="dashicons dashicons-star-filled"></span>
126
- <span class="dashicons dashicons-star-filled"></span>
127
- <span class="dashicons dashicons-star-filled"></span>
128
- </a>
129
- <a class="button" href="https://en-gb.wordpress.org/plugins/wp-security-audit-log/#reviews" target="_blank"><?php esc_html_e( 'Rate Plugin', 'wp-security-audit-log' ); ?></a>
130
- </p>
131
- </div>
132
- <!-- /.activity-block -->
133
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  </div>
135
 
136
- <?php
137
- $is_current_view = $this->_plugin->views->GetActiveView() == $this;
138
- // Check if any of the extensions is activated.
139
- if ( wsal_freemius()->is_not_paying() ) :
140
- if ( current_user_can( 'manage_options' ) && $is_current_view ) :
141
- ?>
142
- <div class="wsal-sidebar-advert">
143
- <div class="postbox">
144
- <h3 class="hndl"><span><?php esc_html_e( 'Upgrade to Premium', 'wp-security-audit-log' ); ?></span></h3>
145
- <div class="inside">
146
- <ul class="wsal-features-list">
147
- <li>
148
- <?php esc_html_e( 'See who is logged in', 'wp-security-audit-log' ); ?><br />
149
- <?php esc_html_e( 'And remotely terminate sessions', 'wp-security-audit-log' ); ?>
150
- </li>
151
- <li>
152
- <?php esc_html_e( 'Generate reports', 'wp-security-audit-log' ); ?><br />
153
- <?php esc_html_e( 'Or configure automated email reports', 'wp-security-audit-log' ); ?>
154
- </li>
155
- <li>
156
- <?php esc_html_e( 'Configure email notifications', 'wp-security-audit-log' ); ?><br />
157
- <?php esc_html_e( 'Get instantly notified of important changes', 'wp-security-audit-log' ); ?>
158
- </li>
159
- <li>
160
- <?php esc_html_e( 'Add Search', 'wp-security-audit-log' ); ?><br />
161
- <?php esc_html_e( 'Easily track down suspicious behaviour', 'wp-security-audit-log' ); ?>
162
- </li>
163
- <li>
164
- <?php esc_html_e( 'Integrate & Centralise', 'wp-security-audit-log' ); ?><br />
165
- <?php esc_html_e( 'Export the logs to your centralised logging system', 'wp-security-audit-log' ); ?>
166
- </li>
167
- </ul>
168
- <?php
169
- // Buy Now button link.
170
- $buy_now = add_query_arg( 'page', 'wsal-auditlog-pricing', admin_url( 'admin.php' ) );
171
- $buy_now_target = '';
172
-
173
- // If user is not super admin and website is multisite then change the URL.
174
- if ( $this->_plugin->IsMultisite() && ! is_super_admin() ) {
175
- $buy_now = 'https://www.wpsecurityauditlog.com/pricing/';
176
- $buy_now_target = 'target="_blank"';
177
- } elseif ( $this->_plugin->IsMultisite() && is_super_admin() ) {
178
- $buy_now = add_query_arg( 'page', 'wsal-auditlog-pricing', network_admin_url( 'admin.php' ) );
179
- } elseif ( ! $this->_plugin->IsMultisite() && ! current_user_can( 'manage_options' ) ) {
180
- $buy_now = 'https://www.wpsecurityauditlog.com/pricing/';
181
- $buy_now_target = 'target="_blank"';
182
- }
183
-
184
- $more_info = add_query_arg(
185
- array(
186
- 'utm_source' => 'plugin',
187
- 'utm_medium' => 'page',
188
- 'utm_content' => 'update+more+info',
189
- 'utm_campaign' => 'upgrade+premium',
190
- ),
191
- 'https://www.wpsecurityauditlog.com/premium-features/'
192
- );
193
- ?>
194
- <p>
195
- <a class="button-primary wsal-extension-btn" href="<?php echo esc_attr( $buy_now ); ?>" <?php echo esc_attr( $buy_now_target ); ?>><?php esc_html_e( 'Upgrade to Premium', 'wp-security-audit-log' ); ?></a>
196
- <a class="button-primary wsal-extension-btn" href="<?php echo esc_attr( $more_info ); ?>" target="_blank"><?php esc_html_e( 'More Information', 'wp-security-audit-log' ); ?></a>
197
- </p>
 
198
  </div>
199
  </div>
200
- </div>
201
  <?php endif; ?>
202
- <?php endif; ?>
203
  </div>
204
  <?php
205
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
  }
55
  * Method: Get View Header.
56
  */
57
  public function Header() {
58
+ // Information display style.
59
+ ?>
60
+ <style>
61
+ #system-info-textarea {
62
+ font-family: monospace;
63
+ white-space: pre;
64
+ overflow: auto;
65
+ width: 100%;
66
+ height: 400px;
67
+ margin: 0;
68
+ }
69
+ </style>
70
+ <?php
71
+
72
  wp_enqueue_style(
73
  'extensions',
74
  $this->_plugin->GetBaseUrl() . '/css/extensions.css',
82
  */
83
  public function Render() {
84
  ?>
85
+ <h2 id="wsal-tabs" class="nav-tab-wrapper">
86
+ <a href="#tab-help" class="nav-tab"><?php esc_html_e( 'Help', 'wp-security-audit-log' ); ?></a>
87
+ <?php if ( $this->_plugin->settings->CurrentUserCan( 'edit' ) ) : ?>
88
+ <a href="#tab-system-info" class="nav-tab"><?php esc_html_e( 'System Info', 'wp-security-audit-log' ); ?></a>
89
+ <?php endif; ?>
90
+ </h2>
91
+ <div class="wsal-nav-tabs-wrap">
92
+ <div class="nav-tabs">
93
+ <table class="form-table wsal-tab widefat" id="tab-help">
94
+ <tbody>
95
+ <tr class="postbox">
96
+ <td>
97
+ <h2 class="wsal-tab__heading"><?php esc_html_e( 'Getting Started', 'wp-security-audit-log' ); ?></h2>
98
+ <p>
99
+ <?php esc_html_e( 'Getting started with WP Security Audit Log is really easy; once the plugin is installed it will automatically keep a log of everything that is happening on your website and you do not need to do anything. Watch the video below for a quick overview of the plugin.', 'wp-security-audit-log' ); ?>
100
+ </p>
101
+ <p>
102
+ <iframe class="wsal-youtube-embed" width="560" height="315" src="https://www.youtube.com/embed/1nopATCS-CQ?rel=0" frameborder="0" allowfullscreen></iframe>
103
+ </p>
104
+ </td>
105
+ </tr>
106
+ <tr class="postbox">
107
+ <td>
108
+ <h2 class="wsal-tab__heading"><?php esc_html_e( 'Plugin Support', 'wp-security-audit-log' ); ?></h2>
109
+ <p>
110
+ <?php esc_html_e( 'Have you encountered or noticed any issues while using WP Security Audit Log plugin?', 'wp-security-audit-log' ); ?>
111
+ <?php esc_html_e( 'Or you want to report something to us? Click any of the options below to post on the plugin\'s forum or contact our support directly.', 'wp-security-audit-log' ); ?>
112
+ </p><p>
113
+ <a class="button" href="https://wordpress.org/support/plugin/wp-security-audit-log" target="_blank"><?php esc_html_e( 'Free Support Forum', 'wp-security-audit-log' ); ?></a>
114
+ &nbsp;&nbsp;&nbsp;&nbsp;
115
+ <a class="button" href="http://www.wpsecurityauditlog.com/contact/" target="_blank"><?php esc_html_e( 'Free Support Email', 'wp-security-audit-log' ); ?></a>
116
+ </p>
117
+ </td>
118
+ </tr>
119
+ <tr class="postbox">
120
+ <td>
121
+ <h2 class="wsal-tab__heading"><?php esc_html_e( 'Plugin Documentation', 'wp-security-audit-log' ); ?></h2>
122
+ <p>
123
+ <?php esc_html_e( 'For more technical information about the WP Security Audit Log plugin please visit the plugin’s knowledge base.', 'wp-security-audit-log' ); ?>
124
+ <?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 audit log.', 'wp-security-audit-log' ); ?>
125
+ </p><p>
126
+ <a class="button" href="http://www.wpsecurityauditlog.com/?utm_source=plugin&amp;utm_medium=helppage&amp;utm_campaign=support" target="_blank"><?php esc_html_e( 'Plugin Website', 'wp-security-audit-log' ); ?></a>
127
+ &nbsp;&nbsp;&nbsp;&nbsp;
128
+ <a class="button" href="https://www.wpsecurityauditlog.com/support-documentation/?utm_source=plugin&amp;utm_medium=helppage&amp;utm_campaign=support" target="_blank"><?php esc_html_e( 'Knowledge Base', 'wp-security-audit-log' ); ?></a>
129
+ &nbsp;&nbsp;&nbsp;&nbsp;
130
+ <a class="button" href="http://www.wpsecurityauditlog.com/documentation/list-monitoring-wordpress-security-alerts-audit-log/?utm_source=plugin&amp;utm_medium=helppage&amp;utm_campaign=support" target="_blank"><?php esc_html_e( 'List of WordPress Security Events', 'wp-security-audit-log' ); ?></a>
131
+ </p>
132
+ </td>
133
+ </tr>
134
+ <tr class="postbox">
135
+ <td>
136
+ <h2 class="wsal-tab__heading"><?php esc_html_e( 'Rate WP Security Audit Log', 'wp-security-audit-log' ); ?></h2>
137
+ <p>
138
+ <?php esc_html_e( 'We work really hard to deliver a plugin that enables you to keep a record of all the changes that are happening on your WordPress.', 'wp-security-audit-log' ); ?>
139
+ <?php esc_html_e( 'It takes thousands of man-hours every year and endless amount of dedication to research, develop and maintain the free edition of WP Security Audit Log.', 'wp-security-audit-log' ); ?>
140
+ <?php esc_html_e( 'Therefore if you like what you see, and find WP Security Audit Log useful we ask you nothing more than to please rate our plugin.', 'wp-security-audit-log' ); ?>
141
+ <?php esc_html_e( 'We appreciate every star!', 'wp-security-audit-log' ); ?>
142
+ </p>
143
+ <p>
144
+ <a class="rating-link" href="https://en-gb.wordpress.org/plugins/wp-security-audit-log/#reviews" target="_blank">
145
+ <span class="dashicons dashicons-star-filled"></span>
146
+ <span class="dashicons dashicons-star-filled"></span>
147
+ <span class="dashicons dashicons-star-filled"></span>
148
+ <span class="dashicons dashicons-star-filled"></span>
149
+ <span class="dashicons dashicons-star-filled"></span>
150
+ </a>
151
+ <a class="button" href="https://en-gb.wordpress.org/plugins/wp-security-audit-log/#reviews" target="_blank"><?php esc_html_e( 'Rate Plugin', 'wp-security-audit-log' ); ?></a>
152
+ </p>
153
+ </td>
154
+ </tr>
155
+ </tbody>
156
+ </table>
157
+ <?php
158
+ // Check user permissions to view page.
159
+ if ( $this->_plugin->settings->CurrentUserCan( 'edit' ) ) :
160
+ ?>
161
+ <table class="form-table wsal-tab widefat" id="tab-system-info">
162
+ <tbody>
163
+ <tr>
164
+ <td>
165
+ <h3><?php esc_html_e( 'System Info', 'wp-security-audit-log' ); ?></h3>
166
+ <form method="post" dir="ltr">
167
+ <textarea readonly="readonly" onclick="this.focus(); this.select()" id="system-info-textarea" name="wsal-sysinfo"><?php echo esc_html( $this->get_sysinfo() ); ?></textarea>
168
+ <p class="submit">
169
+ <input type="hidden" name="wsal-action" value="download_sysinfo" />
170
+ <?php submit_button( 'Download System Info File', 'primary', 'wsal-download-sysinfo', false ); ?>
171
+ </p>
172
+ </form>
173
+ </td>
174
+ </tr>
175
+ </tbody>
176
+ </table>
177
+ <?php endif; ?>
178
  </div>
179
 
180
+ <?php
181
+ $is_current_view = $this->_plugin->views->GetActiveView() == $this;
182
+ // Check if any of the extensions is activated.
183
+ if ( wsal_freemius()->is_not_paying() ) :
184
+ if ( current_user_can( 'manage_options' ) && $is_current_view ) :
185
+ ?>
186
+ <div class="wsal-sidebar-advert">
187
+ <div class="postbox">
188
+ <h3 class="hndl"><span><?php esc_html_e( 'Upgrade to Premium', 'wp-security-audit-log' ); ?></span></h3>
189
+ <div class="inside">
190
+ <ul class="wsal-features-list">
191
+ <li>
192
+ <?php esc_html_e( 'See who is logged in', 'wp-security-audit-log' ); ?><br />
193
+ <?php esc_html_e( 'And remotely terminate sessions', 'wp-security-audit-log' ); ?>
194
+ </li>
195
+ <li>
196
+ <?php esc_html_e( 'Generate reports', 'wp-security-audit-log' ); ?><br />
197
+ <?php esc_html_e( 'Or configure automated email reports', 'wp-security-audit-log' ); ?>
198
+ </li>
199
+ <li>
200
+ <?php esc_html_e( 'Configure email notifications', 'wp-security-audit-log' ); ?><br />
201
+ <?php esc_html_e( 'Get instantly notified of important changes', 'wp-security-audit-log' ); ?>
202
+ </li>
203
+ <li>
204
+ <?php esc_html_e( 'Add Search', 'wp-security-audit-log' ); ?><br />
205
+ <?php esc_html_e( 'Easily track down suspicious behaviour', 'wp-security-audit-log' ); ?>
206
+ </li>
207
+ <li>
208
+ <?php esc_html_e( 'Integrate & Centralise', 'wp-security-audit-log' ); ?><br />
209
+ <?php esc_html_e( 'Export the logs to your centralised logging system', 'wp-security-audit-log' ); ?>
210
+ </li>
211
+ </ul>
212
+ <?php
213
+ // Buy Now button link.
214
+ $buy_now = add_query_arg( 'page', 'wsal-auditlog-pricing', admin_url( 'admin.php' ) );
215
+ $buy_now_target = '';
216
+
217
+ // If user is not super admin and website is multisite then change the URL.
218
+ if ( $this->_plugin->IsMultisite() && ! is_super_admin() ) {
219
+ $buy_now = 'https://www.wpsecurityauditlog.com/pricing/';
220
+ $buy_now_target = 'target="_blank"';
221
+ } elseif ( $this->_plugin->IsMultisite() && is_super_admin() ) {
222
+ $buy_now = add_query_arg( 'page', 'wsal-auditlog-pricing', network_admin_url( 'admin.php' ) );
223
+ } elseif ( ! $this->_plugin->IsMultisite() && ! current_user_can( 'manage_options' ) ) {
224
+ $buy_now = 'https://www.wpsecurityauditlog.com/pricing/';
225
+ $buy_now_target = 'target="_blank"';
226
+ }
227
+
228
+ $more_info = add_query_arg(
229
+ array(
230
+ 'utm_source' => 'plugin',
231
+ 'utm_medium' => 'page',
232
+ 'utm_content' => 'update+more+info',
233
+ 'utm_campaign' => 'upgrade+premium',
234
+ ),
235
+ 'https://www.wpsecurityauditlog.com/premium-features/'
236
+ );
237
+ ?>
238
+ <p>
239
+ <a class="button-primary wsal-extension-btn" href="<?php echo esc_attr( $buy_now ); ?>" <?php echo esc_attr( $buy_now_target ); ?>><?php esc_html_e( 'Upgrade to Premium', 'wp-security-audit-log' ); ?></a>
240
+ <a class="button-primary wsal-extension-btn" href="<?php echo esc_attr( $more_info ); ?>" target="_blank"><?php esc_html_e( 'More Information', 'wp-security-audit-log' ); ?></a>
241
+ </p>
242
+ </div>
243
  </div>
244
  </div>
245
+ <?php endif; ?>
246
  <?php endif; ?>
 
247
  </div>
248
  <?php
249
  }
250
+
251
+ /**
252
+ * Method: Get system information.
253
+ *
254
+ * @return string - System information.
255
+ */
256
+ public function get_sysinfo() {
257
+ // System info.
258
+ global $wpdb;
259
+
260
+ $sysinfo = '### System Info → Begin ###' . "\n\n";
261
+
262
+ // Start with the basics...
263
+ $sysinfo .= '-- Site Info --' . "\n\n";
264
+ $sysinfo .= 'Site URL (WP Address): ' . site_url() . "\n";
265
+ $sysinfo .= 'Home URL (Site Address): ' . home_url() . "\n";
266
+ $sysinfo .= 'Multisite: ' . ( is_multisite() ? 'Yes' : 'No' ) . "\n";
267
+
268
+ // Browser information.
269
+ if ( ! class_exists( 'WSAL_Browser' ) && file_exists( WSAL_BASE_DIR . 'includes/class-wsal-browser.php' ) ) {
270
+ require_once( WSAL_BASE_DIR . 'includes/class-wsal-browser.php' );
271
+
272
+ $browser = new WSAL_Browser();
273
+ $sysinfo .= "\n" . '-- User Browser --' . "\n\n";
274
+ $sysinfo .= $browser;
275
+ }
276
+
277
+ // Get theme info.
278
+ $theme_data = wp_get_theme();
279
+ $theme = $theme_data->Name . ' ' . $theme_data->Version;
280
+ $parent_theme = $theme_data->Template;
281
+ if ( ! empty( $parent_theme ) ) {
282
+ $parent_theme_data = wp_get_theme( $parent_theme );
283
+ $parent_theme = $parent_theme_data->Name . ' ' . $parent_theme_data->Version;
284
+ }
285
+
286
+ // Language information.
287
+ $locale = get_locale();
288
+
289
+ // WordPress configuration.
290
+ $sysinfo .= "\n" . '-- WordPress Configuration --' . "\n\n";
291
+ $sysinfo .= 'Version: ' . get_bloginfo( 'version' ) . "\n";
292
+ $sysinfo .= 'Language: ' . ( ! empty( $locale ) ? $locale : 'en_US' ) . "\n";
293
+ $sysinfo .= 'Permalink Structure: ' . ( get_option( 'permalink_structure' ) ? get_option( 'permalink_structure' ) : 'Default' ) . "\n";
294
+ $sysinfo .= 'Active Theme: ' . $theme . "\n";
295
+ if ( $parent_theme !== $theme ) {
296
+ $sysinfo .= 'Parent Theme: ' . $parent_theme . "\n";
297
+ }
298
+ $sysinfo .= 'Show On Front: ' . get_option( 'show_on_front' ) . "\n";
299
+
300
+ // Only show page specs if frontpage is set to 'page'.
301
+ if ( 'page' === get_option( 'show_on_front' ) ) {
302
+ $front_page_id = (int) get_option( 'page_on_front' );
303
+ $blog_page_id = (int) get_option( 'page_for_posts' );
304
+
305
+ $sysinfo .= 'Page On Front: ' . ( 0 !== $front_page_id ? get_the_title( $front_page_id ) . ' (#' . $front_page_id . ')' : 'Unset' ) . "\n";
306
+ $sysinfo .= 'Page For Posts: ' . ( 0 !== $blog_page_id ? get_the_title( $blog_page_id ) . ' (#' . $blog_page_id . ')' : 'Unset' ) . "\n";
307
+ }
308
+
309
+ $sysinfo .= 'ABSPATH: ' . ABSPATH . "\n";
310
+ $sysinfo .= 'WP_DEBUG: ' . ( defined( 'WP_DEBUG' ) ? WP_DEBUG ? 'Enabled' : 'Disabled' : 'Not set' ) . "\n";
311
+ $sysinfo .= 'WP Memory Limit: ' . WP_MEMORY_LIMIT . "\n";
312
+
313
+ // Get plugins that have an update.
314
+ $updates = get_plugin_updates();
315
+
316
+ // Must-use plugins.
317
+ // NOTE: MU plugins can't show updates!
318
+ $muplugins = get_mu_plugins();
319
+ if ( count( $muplugins ) > 0 ) {
320
+ $sysinfo .= "\n" . '-- Must-Use Plugins --' . "\n\n";
321
+
322
+ foreach ( $muplugins as $plugin => $plugin_data ) {
323
+ $sysinfo .= $plugin_data['Name'] . ': ' . $plugin_data['Version'] . "\n";
324
+ }
325
+ }
326
+
327
+ // WordPress active plugins.
328
+ $sysinfo .= "\n" . '-- WordPress Active Plugins --' . "\n\n";
329
+
330
+ $plugins = get_plugins();
331
+ $active_plugins = get_option( 'active_plugins', array() );
332
+
333
+ foreach ( $plugins as $plugin_path => $plugin ) {
334
+ if ( ! in_array( $plugin_path, $active_plugins ) )
335
+ continue;
336
+
337
+ $update = ( array_key_exists( $plugin_path, $updates ) ) ? ' (needs update - ' . $updates[ $plugin_path ]->update->new_version . ')' : '';
338
+ $sysinfo .= $plugin['Name'] . ': ' . $plugin['Version'] . $update . "\n";
339
+ }
340
+
341
+ // WordPress inactive plugins.
342
+ $sysinfo .= "\n" . '-- WordPress Inactive Plugins --' . "\n\n";
343
+
344
+ foreach ( $plugins as $plugin_path => $plugin ) {
345
+ if ( in_array( $plugin_path, $active_plugins ) ) {
346
+ continue;
347
+ }
348
+
349
+ $update = ( array_key_exists( $plugin_path, $updates ) ) ? ' (needs update - ' . $updates[ $plugin_path ]->update->new_version . ')' : '';
350
+ $sysinfo .= $plugin['Name'] . ': ' . $plugin['Version'] . $update . "\n";
351
+ }
352
+
353
+ if ( is_multisite() ) {
354
+ // WordPress Multisite active plugins.
355
+ $sysinfo .= "\n" . '-- Network Active Plugins --' . "\n\n";
356
+
357
+ $plugins = wp_get_active_network_plugins();
358
+ $active_plugins = get_site_option( 'active_sitewide_plugins', array() );
359
+
360
+ foreach ( $plugins as $plugin_path ) {
361
+ $plugin_base = plugin_basename( $plugin_path );
362
+
363
+ if ( ! array_key_exists( $plugin_base, $active_plugins ) ) {
364
+ continue;
365
+ }
366
+
367
+ $update = ( array_key_exists( $plugin_path, $updates ) ) ? ' (needs update - ' . $updates[ $plugin_path ]->update->new_version . ')' : '';
368
+ $plugin = get_plugin_data( $plugin_path );
369
+ $sysinfo .= $plugin['Name'] . ': ' . $plugin['Version'] . $update . "\n";
370
+ }
371
+ }
372
+
373
+ // Server configuration.
374
+ $server_software = filter_input( INPUT_SERVER, 'SERVER_SOFTWARE', FILTER_SANITIZE_STRING );
375
+ $sysinfo .= "\n" . '-- Webserver Configuration --' . "\n\n";
376
+ $sysinfo .= 'PHP Version: ' . PHP_VERSION . "\n";
377
+ $sysinfo .= 'MySQL Version: ' . $wpdb->db_version() . "\n";
378
+
379
+ if ( isset( $server_software ) ) {
380
+ $sysinfo .= 'Webserver Info: ' . $server_software . "\n";
381
+ } else {
382
+ $sysinfo .= 'Webserver Info: Global $_SERVER array is not set.' . "\n";
383
+ }
384
+
385
+ // PHP configs.
386
+ $sysinfo .= "\n" . '-- PHP Configuration --' . "\n\n";
387
+ $sysinfo .= 'PHP Safe Mode: ';
388
+ $sysinfo .= ini_get( 'safe_mode' ) ? 'Yes' . "\n" : 'No' . "\n";
389
+ $sysinfo .= 'Memory Limit: ' . ini_get( 'memory_limit' ) . "\n";
390
+ $sysinfo .= 'Upload Max Size: ' . ini_get( 'upload_max_filesize' ) . "\n";
391
+ $sysinfo .= 'Post Max Size: ' . ini_get( 'post_max_size' ) . "\n";
392
+ $sysinfo .= 'Upload Max Filesize: ' . ini_get( 'upload_max_filesize' ) . "\n";
393
+ $sysinfo .= 'Time Limit: ' . ini_get( 'max_execution_time' ) . "\n";
394
+ $sysinfo .= 'Max Input Vars: ' . ini_get( 'max_input_vars' ) . "\n";
395
+ $sysinfo .= 'Display Errors: ' . ( ini_get( 'display_errors' ) ? 'On (' . ini_get( 'display_errors' ) . ')' : 'N/A' ) . "\n";
396
+
397
+ // WSAL options.
398
+ $sysinfo .= "\n" . '-- WSAL Options --' . "\n\n";
399
+ $options = $this->get_wsal_options();
400
+
401
+ if ( ! empty( $options ) && is_array( $options ) ) {
402
+ foreach ( $options as $index => $option ) {
403
+ $sysinfo .= 'Option: ' . $option->option_name . "\n";
404
+ $sysinfo .= 'Value: ' . $option->option_value . "\n\n";
405
+ }
406
+ }
407
+
408
+ $sysinfo .= "\n" . '### System Info → End ###' . "\n\n";
409
+
410
+ return $sysinfo;
411
+ }
412
+
413
+ /**
414
+ * Method: Query WSAL Options from DB.
415
+ *
416
+ * @return array - WSAL Options array.
417
+ */
418
+ public function get_wsal_options() {
419
+ // Get options transient.
420
+ $wsal_options = get_transient( 'wsal_options' );
421
+
422
+ // If options transient is not set then query and set options.
423
+ if ( false === $wsal_options ) {
424
+ // Get raw options from DB.
425
+ $raw_options = $this->query_wsal_options();
426
+
427
+ if ( ! empty( $raw_options ) && is_array( $raw_options ) ) {
428
+ foreach ( $raw_options as $option_id => $option ) {
429
+ if ( ! empty( $option->option_value ) ) {
430
+ $wsal_options[] = $option;
431
+ }
432
+ }
433
+ }
434
+
435
+ // Store the results in a transient.
436
+ set_transient( 'wsal_options', $wsal_options, DAY_IN_SECONDS );
437
+ }
438
+
439
+ return $wsal_options;
440
+ }
441
+
442
+ /**
443
+ * Method: Query WSAL Options from DB.
444
+ *
445
+ * @return array - Array of options.
446
+ */
447
+ public function query_wsal_options() {
448
+ // Query WSAL options.
449
+ global $wpdb;
450
+
451
+ // Set table name.
452
+ $options_table = $wpdb->prefix . 'wsal_options';
453
+
454
+ // Query the options.
455
+ return $wpdb->get_results( "SELECT * FROM $options_table" );
456
+ }
457
+
458
+ /**
459
+ * Method: Render footer content.
460
+ */
461
+ public function Footer() {
462
+ ?>
463
+ <script>
464
+ /**
465
+ * Create and download a temporary file.
466
+ *
467
+ * @param {string} filename - File name.
468
+ * @param {string} text - File content.
469
+ */
470
+ function download(filename, text) {
471
+ // Create temporary element.
472
+ var element = document.createElement('a');
473
+ element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
474
+ element.setAttribute('download', filename);
475
+
476
+ // Set the element to not display.
477
+ element.style.display = 'none';
478
+ document.body.appendChild(element);
479
+
480
+ // Simlate click on the element.
481
+ element.click();
482
+
483
+ // Remove temporary element.
484
+ document.body.removeChild(element);
485
+ }
486
+
487
+ jQuery( document ).ready( function() {
488
+ var download_btn = jQuery( '#wsal-download-sysinfo' );
489
+ download_btn.click( function( event ) {
490
+ event.preventDefault();
491
+ download( 'wsal-system-info.txt', jQuery( '#system-info-textarea' ).val() );
492
+ } );
493
+ } );
494
+
495
+ // tab handling code
496
+ jQuery('#wsal-tabs>a').click(function(){
497
+ jQuery('#wsal-tabs>a').removeClass('nav-tab-active');
498
+ jQuery('table.wsal-tab').hide();
499
+ jQuery(jQuery(this).addClass('nav-tab-active').attr('href')).show();
500
+ });
501
+ // show relevant tab
502
+ var hashlink = jQuery('#wsal-tabs>a[href="' + location.hash + '"]');
503
+ if (hashlink.length) {
504
+ hashlink.click();
505
+ } else {
506
+ jQuery('#wsal-tabs>a:first').click();
507
+ }
508
+
509
+ jQuery(".sel-columns").change(function(){
510
+ var notChecked = 1;
511
+ jQuery(".sel-columns").each(function(){
512
+ if(this.checked) notChecked = 0;
513
+ })
514
+ if(notChecked == 1){
515
+ alert("You have to select at least one column!");
516
+ }
517
+ });
518
+ </script>
519
+ <?php
520
+ }
521
  }
classes/Views/Settings.php CHANGED
@@ -121,6 +121,12 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
121
  if ( in_array( $token, $post_types ) ) {
122
  return 'cpts';
123
  }
 
 
 
 
 
 
124
  return 'other';
125
  }
126
 
@@ -136,14 +142,15 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
136
 
137
  // Load saved settings of this view.
138
  $this->scan_settings = array(
139
- 'scan_file_changes' => $this->_plugin->GetGlobalOption( 'scan-file-changes', 'enable' ),
140
- 'scan_frequency' => $this->_plugin->GetGlobalOption( 'scan-frequency', 'weekly' ),
141
- 'scan_hour' => $this->_plugin->GetGlobalOption( 'scan-hour', '04' ),
142
- 'scan_day' => $this->_plugin->GetGlobalOption( 'scan-day', '1' ),
143
- 'scan_date' => $this->_plugin->GetGlobalOption( 'scan-date', '10' ),
144
- 'scan_directories' => $this->_plugin->GetGlobalOption( 'scan-directories', $default_scan_dirs ),
 
145
  'scan_excluded_extensions' => $this->_plugin->GetGlobalOption( 'scan-excluded-extensions', array( 'jpg', 'jpeg', 'png', 'bmp', 'pdf', 'txt', 'log', 'mo', 'po', 'mp3', 'wav' ) ),
146
- 'scan_in_progress' => $this->_plugin->GetGlobalOption( 'scan-in-progress', false ),
147
  );
148
  }
149
 
@@ -177,6 +184,7 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
177
  $this->_plugin->settings->SetExcludedMonitoringCustom( isset( $post_array['Customs'] ) ? $post_array['Customs'] : array() );
178
  $this->_plugin->settings->SetExcludedMonitoringIP( isset( $post_array['IpAddrs'] ) ? $post_array['IpAddrs'] : array() );
179
  $this->_plugin->settings->set_excluded_post_types( isset( $post_array['ExCPTss'] ) ? $post_array['ExCPTss'] : array() );
 
180
 
181
  $this->_plugin->settings->SetRestrictAdmins( isset( $post_array['RestrictAdmins'] ) );
182
  $this->_plugin->settings->set_login_page_notification( isset( $post_array['login_page_notification'] ) ? 'true' : 'false' );
@@ -590,77 +598,73 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
590
  <tbody>
591
  <!-- Audit Log Retention -->
592
  <?php
593
- $disabled = '';
594
  if ( $this->_plugin->settings->IsArchivingEnabled() ) :
595
- $disabled = 'disabled';
596
  ?>
597
  <tr>
598
  <td colspan="2">
599
- <?php esc_html_e( 'The options below are disabled because you enabled archiving of alerts to the archiving table from', 'wp-security-audit-log' ); ?>&nbsp;<a href="<?php echo esc_url( admin_url( 'admin.php?page=wsal-ext-settings#mirroring' ) ); ?>" target="_blank">here</a>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
600
  </td>
601
  </tr>
602
  <?php endif; ?>
603
- <tr>
604
- <th><label for="delete1"><?php esc_html_e( 'Audit Log Retention', 'wp-security-audit-log' ); ?></label></th>
605
- <td>
606
- <fieldset>
607
- <?php $text = __( '(eg: 1 month)', 'wp-security-audit-log' ); ?>
608
- <?php $nbld = ! ($this->_plugin->settings->IsPruningDateEnabled() || $this->_plugin->settings->IsPruningLimitEnabled()); ?>
609
- <label for="delete0">
610
- <input type="radio" id="delete0" name="PruneBy" value=""
611
- <?php checked( $nbld ); ?>
612
- <?php echo esc_attr( $disabled ); ?> />
613
- <?php echo esc_html__( 'None', 'wp-security-audit-log' ); ?>
614
- </label>
615
- </fieldset>
616
- <fieldset>
617
- <?php $text = __( '(Leave empty or enter 0 to disable automatic pruning.)', 'wp-security-audit-log' ); ?>
618
- <?php $nbld = $this->_plugin->settings->IsPruningDateEnabled(); ?>
619
- <label for="delete1">
620
- <input type="radio" id="delete1" name="PruneBy" value="date"
621
- <?php checked( $nbld ); ?>
622
- <?php echo esc_attr( $disabled ); ?> />
623
- <?php echo esc_html__( 'Delete events older than', 'wp-security-audit-log' ); ?>
624
- </label>
625
- <?php
626
- // Find and replace ` months` in the string.
627
- $pruning_date = str_replace( ' months', '', $this->_plugin->settings->GetPruningDate() );
628
- ?>
629
- <input type="text" id="PruningDate" name="PruningDate" placeholder="<?php echo esc_attr( $text ); ?>"
630
- value="<?php echo esc_attr( $pruning_date ); ?>"
631
- onfocus="jQuery('#delete1').attr('checked', true);" <?php echo esc_attr( $disabled ); ?> />
632
- <?php esc_html_e( 'months', 'wp-security-audit-log' ); ?>
633
- <span class="description"><?php echo esc_html( $text ); ?></span>
634
- </fieldset>
635
- <fieldset>
636
- <?php $text = __( '(eg: 80)', 'wp-security-audit-log' ); ?>
637
- <?php $nbld = $this->_plugin->settings->IsPruningLimitEnabled(); ?>
638
- <label for="delete2">
639
- <input type="radio" id="delete2" name="PruneBy" value="limit"
640
- <?php checked( $nbld ); ?>
641
- <?php echo esc_attr( $disabled ); ?> />
642
- <?php echo esc_html__( 'Keep up to', 'wp-security-audit-log' ); ?>
643
- </label>
644
- <input type="text" id="PruningLimit" name="PruningLimit" placeholder="<?php echo esc_attr( $text ); ?>"
645
- value="<?php echo esc_attr( $this->_plugin->settings->GetPruningLimit() ); ?>"
646
- onfocus="jQuery('#delete2').attr('checked', true);" <?php echo esc_attr( $disabled ); ?>/>
647
- <?php echo esc_html__( 'events', 'wp-security-audit-log' ); ?>
648
- <span><?php echo esc_html( $text ); ?></span>
649
- </fieldset>
650
- <p class="description">
651
- <?php
652
- $next = wp_next_scheduled( 'wsal_cleanup' );
653
- echo esc_html__( 'Next Scheduled Cleanup is in ', 'wp-security-audit-log' );
654
- echo esc_html( human_time_diff( current_time( 'timestamp' ), $next ) );
655
- echo '<!-- ' . esc_html( date( 'dMy H:i:s', $next ) ) . ' --> ';
656
- echo sprintf(
657
- esc_html__( '(or %s)', 'wp-security-audit-log' ),
658
- '<a class="' . esc_attr( $disabled ) . '" href="' . esc_url( add_query_arg( 'action', 'AjaxRunCleanup', admin_url( 'admin-ajax.php' ) ) ) . '">' . esc_html__( 'Run Manually', 'wp-security-audit-log' ) . '</a>'
659
- );
660
- ?>
661
- </p>
662
- </td>
663
- </tr>
664
  <!-- Can View Alerts -->
665
  <tr>
666
  <th><label for="ViewerQueryBox"><?php esc_html_e( 'Can View Events', 'wp-security-audit-log' ); ?></label></th>
@@ -1051,6 +1055,36 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1051
  </td>
1052
  </tr>
1053
  <!-- wsal-scan-directories -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1054
  <tr>
1055
  <th>
1056
  <label for="wsal_add_file_name"><?php esc_html_e( 'Exclude These Files', 'wp-security-audit-log' ); ?></label>
@@ -1149,7 +1183,7 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1149
  <table class="form-table wsal-tab widefat" id="tab-exclude">
1150
  <tbody>
1151
  <tr>
1152
- <th><h2><?php esc_html_e( 'Users & Roles', 'wp-security-audit-log' ); ?></h2></th>
1153
  </tr>
1154
  <tr>
1155
  <td colspan="2"><?php esc_html_e( 'Any of the users and roles listed in the below options will be excluded from monitoring. This means that any change they do will not be logged.', 'wp-security-audit-log' ); ?></td>
@@ -1195,7 +1229,7 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1195
  </td>
1196
  </tr>
1197
  <tr>
1198
- <th><h2><?php esc_html_e( 'Custom Fields', 'wp-security-audit-log' ); ?></h2></th>
1199
  </tr>
1200
  <tr>
1201
  <td colspan="2">
@@ -1224,7 +1258,7 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1224
  </td>
1225
  </tr>
1226
  <tr>
1227
- <th><h2><?php esc_html_e( 'IP Addresses', 'wp-security-audit-log' ); ?></h2></th>
1228
  </tr>
1229
  <tr>
1230
  <td colspan="2"><?php esc_html_e( 'Any of the IP addresses listed below will be excluded from monitoring. This means that all activity from such IP address will not be recorded.', 'wp-security-audit-log' ); ?></td>
@@ -1250,13 +1284,13 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1250
  </td>
1251
  </tr>
1252
  <tr>
1253
- <th><h2><?php esc_html_e( 'Custom Post Types', 'wp-security-audit-log' ); ?></h2></th>
1254
  </tr>
1255
  <tr>
1256
- <td colspan="2"><?php esc_html_e( 'The below list of Custom Post Types are excluded from monitoring. This means that all activity related to these Custom Post Types will not be recorded.', 'wp-security-audit-log' ); ?></td>
1257
  </tr>
1258
  <tr>
1259
- <th><label for="ExCPTsQueryBox"><?php esc_html_e( 'Exclude Custom Post Type from monitoring', 'wp-security-audit-log' ); ?></label></th>
1260
  <td>
1261
  <fieldset>
1262
  <input type="text" id="ExCPTsQueryBox" style="float: left; display: block; width: 250px;">
@@ -1275,6 +1309,40 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1275
  </td>
1276
  </tr>
1277
  <!-- Excluded Custom Post Types -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1278
  </tbody>
1279
  </table>
1280
  </div>
@@ -1308,8 +1376,7 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1308
  wsal_update_login_page_text( login_page_notif, login_page_notif_text );
1309
  } );
1310
  } );
1311
- // -->
1312
- </script>
1313
  <?php
1314
  }
1315
 
@@ -1391,8 +1458,7 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1391
  alert("You have to select at least one column!");
1392
  }
1393
  });
1394
- });
1395
- </script>
1396
  <?php
1397
  }
1398
 
@@ -1510,6 +1576,8 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1510
  die( esc_html__( 'Nonce verification failed.', 'wp-security-audit-log' ) );
1511
  } elseif ( 'extension' === $data_type && ! wp_verify_nonce( $post_array['nonce'], 'wsal-scan-exception-file-type' ) ) {
1512
  die( esc_html__( 'Nonce verification failed.', 'wp-security-audit-log' ) );
 
 
1513
  }
1514
 
1515
  // Get option type to be excluded.
@@ -1517,6 +1585,8 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1517
  $excluded_option = $this->_plugin->GetGlobalOption( 'scan_excluded_files', array() );
1518
  } elseif ( 'extension' === $data_type ) {
1519
  $excluded_option = $this->_plugin->GetGlobalOption( 'scan-excluded-extensions', array( 'jpg', 'jpeg', 'png', 'bmp', 'pdf', 'txt', 'log', 'mo', 'po', 'mp3', 'wav' ) );
 
 
1520
  }
1521
 
1522
  // Check if the file name is set and not empty.
@@ -1524,13 +1594,47 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1524
  // Check if option already exists.
1525
  if ( ! in_array( $post_array['data_name'], $excluded_option, true ) ) {
1526
  // Add to excluded files array.
1527
- $excluded_option[] = $post_array['data_name'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1528
 
1529
  // Save the option.
1530
  if ( 'file' === $data_type ) {
1531
  $this->_plugin->SetGlobalOption( 'scan_excluded_files', $excluded_option );
1532
  } elseif ( 'extension' === $data_type ) {
1533
  $this->_plugin->SetGlobalOption( 'scan-excluded-extensions', $excluded_option );
 
 
1534
  }
1535
 
1536
  echo wp_json_encode( array(
@@ -1542,6 +1646,8 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1542
  $message = esc_html__( 'This file is already excluded from the scan.', 'wp-security-audit-log' );
1543
  } elseif ( 'extension' === $data_type ) {
1544
  $message = esc_html__( 'This file extension is already excluded from the scan.', 'wp-security-audit-log' );
 
 
1545
  }
1546
  echo wp_json_encode( array(
1547
  'success' => false,
@@ -1581,6 +1687,8 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1581
  die( esc_html__( 'Nonce verification failed.', 'wp-security-audit-log' ) );
1582
  } elseif ( 'extension' === $data_type && ! wp_verify_nonce( $post_array['nonce'], 'wsal-scan-remove-exception-file-type' ) ) {
1583
  die( esc_html__( 'Nonce verification failed.', 'wp-security-audit-log' ) );
 
 
1584
  }
1585
 
1586
  // Get files to be excluded.
@@ -1588,6 +1696,8 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1588
  $excluded_option = $this->_plugin->GetGlobalOption( 'scan_excluded_files', array() );
1589
  } elseif ( 'extension' === $data_type ) {
1590
  $excluded_option = $this->_plugin->GetGlobalOption( 'scan-excluded-extensions', array( 'jpg', 'jpeg', 'png', 'bmp', 'pdf', 'txt', 'log', 'mo', 'po', 'mp3', 'wav' ) );
 
 
1591
  }
1592
 
1593
  if ( ! empty( $excluded_option ) && isset( $post_array['data_removed'] ) && ! empty( $post_array['data_removed'] ) ) {
@@ -1619,6 +1729,9 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1619
  if ( empty( $site_content->skip_extensions ) ) {
1620
  $site_content->skip_extensions = array();
1621
  }
 
 
 
1622
 
1623
  // Save the option.
1624
  if ( 'file' === $data_type ) {
@@ -1631,6 +1744,11 @@ class WSAL_Views_Settings extends WSAL_AbstractView {
1631
 
1632
  $site_content->skip_extensions = array_merge( $site_content->skip_extensions, $to_be_excluded );
1633
  $this->_plugin->SetGlobalOption( 'site_content', $site_content );
 
 
 
 
 
1634
  }
1635
 
1636
  echo wp_json_encode( array(
121
  if ( in_array( $token, $post_types ) ) {
122
  return 'cpts';
123
  }
124
+
125
+ // Check if the token matches a URL.
126
+ if ( ( false !== strpos( $token, home_url() ) ) && filter_var( $token, FILTER_VALIDATE_URL ) ) {
127
+ return 'urls';
128
+ }
129
+
130
  return 'other';
131
  }
132
 
142
 
143
  // Load saved settings of this view.
144
  $this->scan_settings = array(
145
+ 'scan_file_changes' => $this->_plugin->GetGlobalOption( 'scan-file-changes', 'enable' ),
146
+ 'scan_frequency' => $this->_plugin->GetGlobalOption( 'scan-frequency', 'weekly' ),
147
+ 'scan_hour' => $this->_plugin->GetGlobalOption( 'scan-hour', '04' ),
148
+ 'scan_day' => $this->_plugin->GetGlobalOption( 'scan-day', '1' ),
149
+ 'scan_date' => $this->_plugin->GetGlobalOption( 'scan-date', '10' ),
150
+ 'scan_directories' => $this->_plugin->GetGlobalOption( 'scan-directories', $default_scan_dirs ),
151
+ 'scan_excluded_dirs' => $this->_plugin->GetGlobalOption( 'scan-excluded-directories', array() ),
152
  'scan_excluded_extensions' => $this->_plugin->GetGlobalOption( 'scan-excluded-extensions', array( 'jpg', 'jpeg', 'png', 'bmp', 'pdf', 'txt', 'log', 'mo', 'po', 'mp3', 'wav' ) ),
153
+ 'scan_in_progress' => $this->_plugin->GetGlobalOption( 'scan-in-progress', false ),
154
  );
155
  }
156
 
184
  $this->_plugin->settings->SetExcludedMonitoringCustom( isset( $post_array['Customs'] ) ? $post_array['Customs'] : array() );
185
  $this->_plugin->settings->SetExcludedMonitoringIP( isset( $post_array['IpAddrs'] ) ? $post_array['IpAddrs'] : array() );
186
  $this->_plugin->settings->set_excluded_post_types( isset( $post_array['ExCPTss'] ) ? $post_array['ExCPTss'] : array() );
187
+ $this->_plugin->settings->set_excluded_urls( isset( $post_array['ExURLss'] ) ? $post_array['ExURLss'] : array() );
188
 
189
  $this->_plugin->settings->SetRestrictAdmins( isset( $post_array['RestrictAdmins'] ) );
190
  $this->_plugin->settings->set_login_page_notification( isset( $post_array['login_page_notification'] ) ? 'true' : 'false' );
598
  <tbody>
599
  <!-- Audit Log Retention -->
600
  <?php
 
601
  if ( $this->_plugin->settings->IsArchivingEnabled() ) :
 
602
  ?>
603
  <tr>
604
  <td colspan="2">
605
+ <?php
606
+ $archiving_page = admin_url( 'admin.php?page=wsal-ext-settings#archiving' );
607
+ echo sprintf( esc_html__( 'Retention settings moved to %1$s archiving settings %2$s because archiving is enabled', 'wp-security-audit-log' ), '<a href="' . esc_url( $archiving_page ) . '" target="_blank">', '</a>' );
608
+ ?>
609
+ </td>
610
+ </tr>
611
+ <?php else : ?>
612
+ <tr>
613
+ <th><label for="delete1"><?php esc_html_e( 'Audit Log Retention', 'wp-security-audit-log' ); ?></label></th>
614
+ <td>
615
+ <fieldset>
616
+ <?php $text = __( '(eg: 1 month)', 'wp-security-audit-log' ); ?>
617
+ <?php $nbld = ! ($this->_plugin->settings->IsPruningDateEnabled() || $this->_plugin->settings->IsPruningLimitEnabled()); ?>
618
+ <label for="delete0">
619
+ <input type="radio" id="delete0" name="PruneBy" value="" <?php checked( $nbld ); ?> />
620
+ <?php echo esc_html__( 'None', 'wp-security-audit-log' ); ?>
621
+ </label>
622
+ </fieldset>
623
+ <fieldset>
624
+ <?php $text = __( '(Leave empty or enter 0 to disable automatic pruning.)', 'wp-security-audit-log' ); ?>
625
+ <?php $nbld = $this->_plugin->settings->IsPruningDateEnabled(); ?>
626
+ <label for="delete1">
627
+ <input type="radio" id="delete1" name="PruneBy" value="date" <?php checked( $nbld ); ?> />
628
+ <?php echo esc_html__( 'Delete events older than', 'wp-security-audit-log' ); ?>
629
+ </label>
630
+ <?php
631
+ // Find and replace ` months` in the string.
632
+ $pruning_date = str_replace( ' months', '', $this->_plugin->settings->GetPruningDate() );
633
+ ?>
634
+ <input type="text" id="PruningDate" name="PruningDate" placeholder="<?php echo esc_attr( $text ); ?>"
635
+ value="<?php echo esc_attr( $pruning_date ); ?>"
636
+ onfocus="jQuery('#delete1').attr('checked', true);" />
637
+ <?php esc_html_e( 'months', 'wp-security-audit-log' ); ?>
638
+ <span class="description"><?php echo esc_html( $text ); ?></span>
639
+ </fieldset>
640
+ <fieldset>
641
+ <?php $text = __( '(eg: 80)', 'wp-security-audit-log' ); ?>
642
+ <?php $nbld = $this->_plugin->settings->IsPruningLimitEnabled(); ?>
643
+ <label for="delete2">
644
+ <input type="radio" id="delete2" name="PruneBy" value="limit" <?php checked( $nbld ); ?> />
645
+ <?php echo esc_html__( 'Keep up to', 'wp-security-audit-log' ); ?>
646
+ </label>
647
+ <input type="text" id="PruningLimit" name="PruningLimit" placeholder="<?php echo esc_attr( $text ); ?>"
648
+ value="<?php echo esc_attr( $this->_plugin->settings->GetPruningLimit() ); ?>"
649
+ onfocus="jQuery('#delete2').attr('checked', true);" />
650
+ <?php echo esc_html__( 'events', 'wp-security-audit-log' ); ?>
651
+ <span><?php echo esc_html( $text ); ?></span>
652
+ </fieldset>
653
+ <p class="description">
654
+ <?php
655
+ $next = wp_next_scheduled( 'wsal_cleanup' );
656
+ echo esc_html__( 'Next Scheduled Cleanup is in ', 'wp-security-audit-log' );
657
+ echo esc_html( human_time_diff( current_time( 'timestamp' ), $next ) );
658
+ echo '<!-- ' . esc_html( date( 'dMy H:i:s', $next ) ) . ' --> ';
659
+ echo sprintf(
660
+ esc_html__( '(or %s)', 'wp-security-audit-log' ),
661
+ '<a href="' . esc_url( add_query_arg( 'action', 'AjaxRunCleanup', admin_url( 'admin-ajax.php' ) ) ) . '">' . esc_html__( 'Run Manually', 'wp-security-audit-log' ) . '</a>'
662
+ );
663
+ ?>
664
+ </p>
665
  </td>
666
  </tr>
667
  <?php endif; ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
668
  <!-- Can View Alerts -->
669
  <tr>
670
  <th><label for="ViewerQueryBox"><?php esc_html_e( 'Can View Events', 'wp-security-audit-log' ); ?></label></th>
1055
  </td>
1056
  </tr>
1057
  <!-- wsal-scan-directories -->
1058
+ <tr>
1059
+ <th>
1060
+ <label for="wsal_add_dir_name"><?php esc_html_e( 'Exclude All Files in These Directories', 'wp-security-audit-log' ); ?></label>
1061
+ </th>
1062
+ <td>
1063
+ <div class="wsal_file_containter">
1064
+ <div id="wsal_dirs">
1065
+ <?php foreach ( $this->scan_settings['scan_excluded_dirs'] as $index => $dir ) : ?>
1066
+ <span id="wsal_dir-<?php echo esc_attr( $dir ); ?>">
1067
+ <input type="checkbox" id="<?php echo esc_attr( $dir ); ?>" value="<?php echo esc_attr( $dir ); ?>" />
1068
+ <label for="<?php echo esc_attr( $dir ); ?>"><?php echo esc_html( $dir ); ?></label>
1069
+ </span>
1070
+ <?php endforeach; ?>
1071
+ </div>
1072
+ <?php wp_nonce_field( 'wsal-scan-remove-exception-dir', 'wsal_scan_remove_exception_dir' ); ?>
1073
+ <input class="button" id="wsal_remove_exception_dir" type="button" value="<?php esc_html_e( 'REMOVE', 'wp-security-audit-log' ); ?>" />
1074
+ </div>
1075
+ <div class="wsal_file_containter">
1076
+ <input type="text" id="wsal_add_dir_name" />
1077
+ <?php wp_nonce_field( 'wsal-scan-exception-dir', 'wsal_scan_exception_dir' ); ?>
1078
+ <input id="wsal_add_dir" class="button" type="button" value="<?php esc_html_e( 'ADD', 'wp-security-audit-log' ); ?>" />
1079
+ </div>
1080
+ <span class="description">
1081
+ <?php echo sprintf( esc_html__( 'Specify the name of the directory and the path to it in relation to the website\'s root. For example, if you want to want to exclude all files in the sub directory dir1/dir2 specify the following: %s.', 'wp-security-audit-log' ), esc_html( trailingslashit( ABSPATH ) ) . 'dir1/dir2/' ); ?>
1082
+ <?php esc_html_e( 'Note that when you exclude a sub directory, all the files in that sub directory and all sub directories underneath it will be excluded from the scan.', 'wp-security-audit-log' ); ?>
1083
+ </span>
1084
+ <span class="error hide" id="wsal_dir_error"></span>
1085
+ </td>
1086
+ </tr>
1087
+ <!-- wsal-scan-exclude-dirs -->
1088
  <tr>
1089
  <th>
1090
  <label for="wsal_add_file_name"><?php esc_html_e( 'Exclude These Files', 'wp-security-audit-log' ); ?></label>
1183
  <table class="form-table wsal-tab widefat" id="tab-exclude">
1184
  <tbody>
1185
  <tr>
1186
+ <th><h2 class="wsal-tab__heading"><?php esc_html_e( 'Users & Roles', 'wp-security-audit-log' ); ?></h2></th>
1187
  </tr>
1188
  <tr>
1189
  <td colspan="2"><?php esc_html_e( 'Any of the users and roles listed in the below options will be excluded from monitoring. This means that any change they do will not be logged.', 'wp-security-audit-log' ); ?></td>
1229
  </td>
1230
  </tr>
1231
  <tr>
1232
+ <td><h2 class="wsal-tab__heading"><?php esc_html_e( 'Custom Fields', 'wp-security-audit-log' ); ?></h2></td>
1233
  </tr>
1234
  <tr>
1235
  <td colspan="2">
1258
  </td>
1259
  </tr>
1260
  <tr>
1261
+ <th><h2 class="wsal-tab__heading"><?php esc_html_e( 'IP Addresses', 'wp-security-audit-log' ); ?></h2></th>
1262
  </tr>
1263
  <tr>
1264
  <td colspan="2"><?php esc_html_e( 'Any of the IP addresses listed below will be excluded from monitoring. This means that all activity from such IP address will not be recorded.', 'wp-security-audit-log' ); ?></td>
1284
  </td>
1285
  </tr>
1286
  <tr>
1287
+ <th><h2 class="wsal-tab__heading"><?php esc_html_e( 'Post Types', 'wp-security-audit-log' ); ?></h2></th>
1288
  </tr>
1289
  <tr>
1290
+ <td colspan="2"><?php esc_html_e( 'The below list of Post Types are excluded from monitoring. This means that all activity related to these post types will not be recorded.', 'wp-security-audit-log' ); ?></td>
1291
  </tr>
1292
  <tr>
1293
+ <th><label for="ExCPTsQueryBox"><?php esc_html_e( 'Exclude Post Type from monitoring', 'wp-security-audit-log' ); ?></label></th>
1294
  <td>
1295
  <fieldset>
1296
  <input type="text" id="ExCPTsQueryBox" style="float: left; display: block; width: 250px;">
1309
  </td>
1310
  </tr>
1311
  <!-- Excluded Custom Post Types -->
1312
+ <tr>
1313
+ <th colspan="2">
1314
+ <h2 class="wsal-tab__heading"><?php esc_html_e( 'Non-Existing URLs (404)', 'wp-security-audit-log' ); ?></h2>
1315
+ </th>
1316
+ </tr>
1317
+ <tr>
1318
+ <td colspan="2">
1319
+ <?php esc_html_e( 'Add the non existing URLs for which you do not want to be alerted of HTTP 404 errors in the activity log by specifying the whole URL.', 'wp-security-audit-log' ); ?>
1320
+ <br />
1321
+ <br />
1322
+ <?php echo sprintf( esc_html__( 'Example for file: %s/subdirectory/file.php', 'wp-security-audit-log' ), esc_url( home_url() ) ); ?>
1323
+ <br />
1324
+ <?php echo sprintf( esc_html__( 'Example for directory: %s/subdirectory/subdirectory2', 'wp-security-audit-log' ), esc_url( home_url() ) ); ?>
1325
+ </td>
1326
+ </tr>
1327
+ <tr>
1328
+ <th><label for="ExURLsQueryBox"><?php esc_html_e( 'Excluded Non-Existing URLs', 'wp-security-audit-log' ); ?></label></th>
1329
+ <td>
1330
+ <fieldset>
1331
+ <input type="text" id="ExURLsQueryBox" style="float: left; display: block; width: 250px;">
1332
+ <input type="button" id="ExURLsQueryAdd" style="float: left; display: block;" class="button-primary" value="Add">
1333
+ <br style="clear: both;"/>
1334
+ <div id="ExURLsList">
1335
+ <?php foreach ( $this->_plugin->settings->get_excluded_urls() as $item ) : ?>
1336
+ <span class="sectoken-<?php echo esc_attr( $this->GetTokenType( $item ) ); ?>">
1337
+ <input type="hidden" name="ExURLss[]" value="<?php echo esc_attr( $item ); ?>"/>
1338
+ <?php echo esc_html( $item ); ?>
1339
+ <a href="javascript:;" title="Remove">&times;</a>
1340
+ </span>
1341
+ <?php endforeach; ?>
1342
+ </div>
1343
+ </fieldset>
1344
+ </td>
1345
+ </tr>
1346
  </tbody>
1347
  </table>
1348
  </div>
1376
  wsal_update_login_page_text( login_page_notif, login_page_notif_text );
1377
  } );
1378
  } );
1379
+ // --></script>
 
1380
  <?php
1381
  }
1382
 
1458
  alert("You have to select at least one column!");
1459
  }
1460
  });
1461
+ });</script>
 
1462
  <?php
1463
  }
1464
 
1576
  die( esc_html__( 'Nonce verification failed.', 'wp-security-audit-log' ) );
1577
  } elseif ( 'extension' === $data_type && ! wp_verify_nonce( $post_array['nonce'], 'wsal-scan-exception-file-type' ) ) {
1578
  die( esc_html__( 'Nonce verification failed.', 'wp-security-audit-log' ) );
1579
+ } elseif ( 'dir' === $data_type && ! wp_verify_nonce( $post_array['nonce'], 'wsal-scan-exception-dir' ) ) {
1580
+ die( esc_html__( 'Nonce verification failed.', 'wp-security-audit-log' ) );
1581
  }
1582
 
1583
  // Get option type to be excluded.
1585
  $excluded_option = $this->_plugin->GetGlobalOption( 'scan_excluded_files', array() );
1586
  } elseif ( 'extension' === $data_type ) {
1587
  $excluded_option = $this->_plugin->GetGlobalOption( 'scan-excluded-extensions', array( 'jpg', 'jpeg', 'png', 'bmp', 'pdf', 'txt', 'log', 'mo', 'po', 'mp3', 'wav' ) );
1588
+ } elseif ( 'dir' === $data_type ) {
1589
+ $excluded_option = $this->_plugin->GetGlobalOption( 'scan-excluded-directories', array() );
1590
  }
1591
 
1592
  // Check if the file name is set and not empty.
1594
  // Check if option already exists.
1595
  if ( ! in_array( $post_array['data_name'], $excluded_option, true ) ) {
1596
  // Add to excluded files array.
1597
+ if ( 'dir' === $data_type ) {
1598
+ // Prepare directories array.
1599
+ // @todo Store this in transient to cache the value. We don't need to load it every time.
1600
+ $uploads_dir = wp_upload_dir();
1601
+
1602
+ // Server directories.
1603
+ $server_dirs = array(
1604
+ untrailingslashit( ABSPATH ), // Root directory.
1605
+ ABSPATH . 'wp-admin', // WordPress Admin.
1606
+ ABSPATH . WPINC, // wp-includes.
1607
+ WP_CONTENT_DIR, // wp-content.
1608
+ WP_CONTENT_DIR . '/themes', // Themes.
1609
+ WP_PLUGIN_DIR, // Plugins.
1610
+ $uploads_dir['basedir'], // Uploads.
1611
+ );
1612
+
1613
+ $dir_name = $post_array['data_name'];
1614
+ if ( '/' === substr( $dir_name, -1 ) ) {
1615
+ $dir_name = untrailingslashit( $dir_name );
1616
+ }
1617
+
1618
+ if ( ! in_array( $dir_name, $server_dirs, true ) ) {
1619
+ $excluded_option[] = $dir_name;
1620
+ } else {
1621
+ echo wp_json_encode( array(
1622
+ 'success' => false,
1623
+ 'message' => esc_html__( 'You can exclude this directory using the check boxes above.', 'wp-security-audit-log' ),
1624
+ ) );
1625
+ exit();
1626
+ }
1627
+ } else {
1628
+ $excluded_option[] = $post_array['data_name'];
1629
+ }
1630
 
1631
  // Save the option.
1632
  if ( 'file' === $data_type ) {
1633
  $this->_plugin->SetGlobalOption( 'scan_excluded_files', $excluded_option );
1634
  } elseif ( 'extension' === $data_type ) {
1635
  $this->_plugin->SetGlobalOption( 'scan-excluded-extensions', $excluded_option );
1636
+ } elseif ( 'dir' === $data_type ) {
1637
+ $this->_plugin->SetGlobalOption( 'scan-excluded-directories', $excluded_option );
1638
  }
1639
 
1640
  echo wp_json_encode( array(
1646
  $message = esc_html__( 'This file is already excluded from the scan.', 'wp-security-audit-log' );
1647
  } elseif ( 'extension' === $data_type ) {
1648
  $message = esc_html__( 'This file extension is already excluded from the scan.', 'wp-security-audit-log' );
1649
+ } elseif ( 'dir' === $data_type ) {
1650
+ $message = esc_html__( 'This directory is already excluded from the scan.', 'wp-security-audit-log' );
1651
  }
1652
  echo wp_json_encode( array(
1653
  'success' => false,
1687
  die( esc_html__( 'Nonce verification failed.', 'wp-security-audit-log' ) );
1688
  } elseif ( 'extension' === $data_type && ! wp_verify_nonce( $post_array['nonce'], 'wsal-scan-remove-exception-file-type' ) ) {
1689
  die( esc_html__( 'Nonce verification failed.', 'wp-security-audit-log' ) );
1690
+ } elseif ( 'dir' === $data_type && ! wp_verify_nonce( $post_array['nonce'], 'wsal-scan-remove-exception-dir' ) ) {
1691
+ die( esc_html__( 'Nonce verification failed.', 'wp-security-audit-log' ) );
1692
  }
1693
 
1694
  // Get files to be excluded.
1696
  $excluded_option = $this->_plugin->GetGlobalOption( 'scan_excluded_files', array() );
1697
  } elseif ( 'extension' === $data_type ) {
1698
  $excluded_option = $this->_plugin->GetGlobalOption( 'scan-excluded-extensions', array( 'jpg', 'jpeg', 'png', 'bmp', 'pdf', 'txt', 'log', 'mo', 'po', 'mp3', 'wav' ) );
1699
+ } elseif ( 'dir' === $data_type ) {
1700
+ $excluded_option = $this->_plugin->GetGlobalOption( 'scan-excluded-directories', array() );
1701
  }
1702
 
1703
  if ( ! empty( $excluded_option ) && isset( $post_array['data_removed'] ) && ! empty( $post_array['data_removed'] ) ) {
1729
  if ( empty( $site_content->skip_extensions ) ) {
1730
  $site_content->skip_extensions = array();
1731
  }
1732
+ if ( empty( $site_content->skip_directories ) ) {
1733
+ $site_content->skip_directories = array();
1734
+ }
1735
 
1736
  // Save the option.
1737
  if ( 'file' === $data_type ) {
1744
 
1745
  $site_content->skip_extensions = array_merge( $site_content->skip_extensions, $to_be_excluded );
1746
  $this->_plugin->SetGlobalOption( 'site_content', $site_content );
1747
+ } elseif ( 'dir' === $data_type ) {
1748
+ $this->_plugin->SetGlobalOption( 'scan-excluded-directories', $excluded_option );
1749
+
1750
+ $site_content->skip_directories = array_merge( $site_content->skip_directories, $to_be_excluded );
1751
+ $this->_plugin->SetGlobalOption( 'site_content', $site_content );
1752
  }
1753
 
1754
  echo wp_json_encode( array(
classes/Views/ToggleAlerts.php CHANGED
@@ -68,10 +68,10 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
68
  wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'wp-security-audit-log' ) );
69
  }
70
 
71
- $alert = new WSAL_Alert(); // IDE type hinting.
72
  $grouped_alerts = $this->_plugin->alerts->GetCategorizedAlerts();
73
- $safe_names = array_map( array( $this, 'GetSafeCatgName' ), array_keys( $grouped_alerts ) );
74
- $safe_names = array_combine( array_keys( $grouped_alerts ), $safe_names );
75
 
76
  // Filter $_POST array.
77
  $post_array = filter_input_array( INPUT_POST );
@@ -79,7 +79,7 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
79
  if ( isset( $post_array['submit'] ) && isset( $post_array['alert'] ) ) {
80
  check_admin_referer( 'wsal-togglealerts' );
81
  try {
82
- $enabled = array_map( 'intval', $post_array['alert'] );
83
  $disabled = array();
84
  foreach ( $this->_plugin->alerts->GetAlerts() as $alert ) {
85
  if ( ! in_array( $alert->type, $enabled ) ) {
@@ -106,6 +106,7 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
106
  $this->_plugin->SetGlobalOption( 'log-visitor-404', isset( $post_array['log_visitor_404'] ) ? 'on' : 'off' );
107
  $this->_plugin->SetGlobalOption( 'purge-visitor-404-log', isset( $post_array['purge_visitor_log'] ) ? 'on' : 'off' );
108
  $this->_plugin->SetGlobalOption( 'log-visitor-404-referrer', isset( $post_array['log_visitor_404_referrer'] ) ? 'on' : 'off' );
 
109
 
110
  $this->_plugin->settings->Set404LogLimit( $post_array['user_404Limit'] );
111
  $this->_plugin->settings->SetVisitor404LogLimit( $post_array['visitor_404Limit'] );
@@ -160,7 +161,7 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
160
  </h2>
161
  <?php
162
  foreach ( $group as $subname => $alerts ) {
163
- $active = array();
164
  $allactive = true;
165
  foreach ( $alerts as $alert ) {
166
  if ( $alert->type <= 0006 ) {
@@ -175,30 +176,92 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
175
  }
176
  }
177
 
 
 
 
178
  // Skip Pages and CPTs section.
179
  if ( __( 'Custom Post Types', 'wp-security-audit-log' ) === $subname || __( 'Pages', 'wp-security-audit-log' ) === $subname ) {
180
  continue;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
  }
182
  ?>
183
  <table class="wp-list-table wsal-tab widefat fixed wsal-sub-tab" cellspacing="0" id="tab-<?php echo esc_attr( $this->GetSafeCatgName( $subname ) ); ?>">
184
  <thead>
185
  <tr>
186
- <th width="48"><input type="checkbox" <?php checked( $allactive ); ?> /></th>
187
  <th width="80"><?php esc_html_e( 'Code', 'wp-security-audit-log' ); ?></th>
188
  <th width="100"><?php esc_html_e( 'Type', 'wp-security-audit-log' ); ?></th>
189
  <th><?php esc_html_e( 'Description', 'wp-security-audit-log' ); ?></th>
190
  </tr>
191
  </thead>
192
  <tbody id="<?php echo ( __( 'File Changes', 'wp-security-audit-log' ) === $subname ) ? 'alerts-file-changes' : false; ?>">
193
- <?php
194
- // Content section notice.
195
- if ( __( 'Content', 'wp-security-audit-log' ) === $subname ) :
196
- ?>
197
  <tr>
198
  <td colspan="4">
199
  <p class="wsal-tab-help description"><?php echo wp_kses( __( '<strong>Note:</strong> Post refers to any type of content, i.e. blog post, page or a post with a custom post type.', 'wp-security-audit-log' ), $this->_plugin->allowed_html_tags ); ?></p>
200
  </td>
201
  </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
  <?php
203
  endif;
204
 
@@ -227,7 +290,8 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
227
  type="checkbox"
228
  class="alert"
229
  <?php checked( $active[ $alert->type ] ); ?>
230
- value="<?php echo (int) $alert->type; ?>"
 
231
  <?php echo ( __( 'File Changes', 'wp-security-audit-log' ) === $subname ) ? 'onclick="wsal_toggle_file_changes(this)"' : false; ?>
232
  />
233
  </th>
@@ -237,8 +301,8 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
237
  </tr>
238
  <?php
239
  if ( 6007 === $alert->type ) {
240
- $log_404 = $this->_plugin->GetGlobalOption( 'log-404' );
241
- $purge_log = $this->_plugin->GetGlobalOption( 'purge-404-log' );
242
  $log_404_referrer = $this->_plugin->GetGlobalOption( 'log-404-referrer', 'on' );
243
  ?>
244
  <tr>
@@ -270,8 +334,8 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
270
  <?php
271
  }
272
  if ( 6023 === $alert->type ) {
273
- $log_visitor_404 = $this->_plugin->GetGlobalOption( 'log-visitor-404' );
274
- $purge_visitor_log = $this->_plugin->GetGlobalOption( 'purge-visitor-404-log' );
275
  $log_visitor_404_referrer = $this->_plugin->GetGlobalOption( 'log-visitor-404-referrer', 'on' );
276
  ?>
277
  <tr>
@@ -328,6 +392,18 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
328
  </tr>
329
  <?php
330
  }
 
 
 
 
 
 
 
 
 
 
 
 
331
  }
332
 
333
  // File integrity scan link.
@@ -406,6 +482,9 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
406
  .widefat td .wsal-tab-help {
407
  margin: 0 8px;
408
  }
 
 
 
409
  </style>
410
  <?php
411
  }
@@ -487,6 +566,16 @@ class WSAL_Views_ToggleAlerts extends WSAL_AbstractView {
487
  jQuery(".check_visitor_log").removeAttr('checked');
488
  }
489
  });
 
 
 
 
 
 
 
 
 
 
490
  });
491
 
492
  var alerts = jQuery( '#alerts-file-changes .alert' ); // File change alerts.
68
  wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'wp-security-audit-log' ) );
69
  }
70
 
71
+ $alert = new WSAL_Alert(); // IDE type hinting.
72
  $grouped_alerts = $this->_plugin->alerts->GetCategorizedAlerts();
73
+ $safe_names = array_map( array( $this, 'GetSafeCatgName' ), array_keys( $grouped_alerts ) );
74
+ $safe_names = array_combine( array_keys( $grouped_alerts ), $safe_names );
75
 
76
  // Filter $_POST array.
77
  $post_array = filter_input_array( INPUT_POST );
79
  if ( isset( $post_array['submit'] ) && isset( $post_array['alert'] ) ) {
80
  check_admin_referer( 'wsal-togglealerts' );
81
  try {
82
+ $enabled = array_map( 'intval', $post_array['alert'] );
83
  $disabled = array();
84
  foreach ( $this->_plugin->alerts->GetAlerts() as $alert ) {
85
  if ( ! in_array( $alert->type, $enabled ) ) {
106
  $this->_plugin->SetGlobalOption( 'log-visitor-404', isset( $post_array['log_visitor_404'] ) ? 'on' : 'off' );
107
  $this->_plugin->SetGlobalOption( 'purge-visitor-404-log', isset( $post_array['purge_visitor_log'] ) ? 'on' : 'off' );
108
  $this->_plugin->SetGlobalOption( 'log-visitor-404-referrer', isset( $post_array['log_visitor_404_referrer'] ) ? 'on' : 'off' );
109
+ $this->_plugin->SetGlobalOption( 'wc-all-stock-changes', isset( $post_array['wc_all_stock_changes'] ) ? 'on' : 'off' );
110
 
111
  $this->_plugin->settings->Set404LogLimit( $post_array['user_404Limit'] );
112
  $this->_plugin->settings->SetVisitor404LogLimit( $post_array['visitor_404Limit'] );
161
  </h2>
162
  <?php
163
  foreach ( $group as $subname => $alerts ) {
164
+ $active = array();
165
  $allactive = true;
166
  foreach ( $alerts as $alert ) {
167
  if ( $alert->type <= 0006 ) {
176
  }
177
  }
178
 
179
+ // Disabled alerts.
180
+ $disabled = '';
181
+
182
  // Skip Pages and CPTs section.
183
  if ( __( 'Custom Post Types', 'wp-security-audit-log' ) === $subname || __( 'Pages', 'wp-security-audit-log' ) === $subname ) {
184
  continue;
185
+ } elseif (
186
+ __( 'BBPress Forum', 'wp-security-audit-log' ) === $subname
187
+ || __( 'WooCommerce', 'wp-security-audit-log' ) === $subname
188
+ || __( 'Yoast SEO', 'wp-security-audit-log' ) === $subname
189
+ || __( 'MultiSite', 'wp-security-audit-log' ) === $subname
190
+ ) {
191
+ switch ( $subname ) {
192
+ case __( 'BBPress Forum', 'wp-security-audit-log' ):
193
+ // Check if BBPress plugin exists.
194
+ if ( ! is_plugin_active( 'bbpress/bbpress.php' ) ) {
195
+ $disabled = 'disabled';
196
+ }
197
+ break;
198
+
199
+ case __( 'WooCommerce', 'wp-security-audit-log' ):
200
+ // Check if WooCommerce plugin exists.
201
+ if ( ! is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
202
+ $disabled = 'disabled';
203
+ }
204
+ break;
205
+
206
+ case __( 'Yoast SEO', 'wp-security-audit-log' ):
207
+ // Check if Yoast SEO plugin exists.
208
+ if ( ! is_plugin_active( 'wordpress-seo/wp-seo.php' ) ) {
209
+ $disabled = 'disabled';
210
+ }
211
+ break;
212
+
213
+ case __( 'MultiSite', 'wp-security-audit-log' ):
214
+ // Disable if not multisite.
215
+ if ( ! is_multisite() ) {
216
+ $disabled = 'disabled';
217
+ }
218
+ break;
219
+
220
+ default:
221
+ break;
222
+ }
223
  }
224
  ?>
225
  <table class="wp-list-table wsal-tab widefat fixed wsal-sub-tab" cellspacing="0" id="tab-<?php echo esc_attr( $this->GetSafeCatgName( $subname ) ); ?>">
226
  <thead>
227
  <tr>
228
+ <th width="48"><input type="checkbox" <?php checked( $allactive ); ?> <?php echo esc_attr( $disabled ); ?> /></th>
229
  <th width="80"><?php esc_html_e( 'Code', 'wp-security-audit-log' ); ?></th>
230
  <th width="100"><?php esc_html_e( 'Type', 'wp-security-audit-log' ); ?></th>
231
  <th><?php esc_html_e( 'Description', 'wp-security-audit-log' ); ?></th>
232
  </tr>
233
  </thead>
234
  <tbody id="<?php echo ( __( 'File Changes', 'wp-security-audit-log' ) === $subname ) ? 'alerts-file-changes' : false; ?>">
235
+ <?php if ( __( 'Content', 'wp-security-audit-log' ) === $subname ) : ?>
 
 
 
236
  <tr>
237
  <td colspan="4">
238
  <p class="wsal-tab-help description"><?php echo wp_kses( __( '<strong>Note:</strong> Post refers to any type of content, i.e. blog post, page or a post with a custom post type.', 'wp-security-audit-log' ), $this->_plugin->allowed_html_tags ); ?></p>
239
  </td>
240
  </tr>
241
+ <?php elseif ( __( 'BBPress Forum', 'wp-security-audit-log' ) === $subname && ! empty( $disabled ) ) : ?>
242
+ <tr>
243
+ <td colspan="4">
244
+ <p class="wsal-tab-help wsal-tab-notice description"><?php echo esc_html__( 'The plugin BBPress is not installed on your website so these events have been disabled.', 'wp-security-audit-log' ); ?></p>
245
+ </td>
246
+ </tr>
247
+ <?php elseif ( __( 'WooCommerce', 'wp-security-audit-log' ) === $subname && ! empty( $disabled ) ) : ?>
248
+ <tr>
249
+ <td colspan="4">
250
+ <p class="wsal-tab-help wsal-tab-notice description"><?php echo esc_html__( 'The plugin WooCommerce is not installed on your website so these events have been disabled.', 'wp-security-audit-log' ); ?></p>
251
+ </td>
252
+ </tr>
253
+ <?php elseif ( __( 'Yoast SEO', 'wp-security-audit-log' ) === $subname && ! empty( $disabled ) ) : ?>
254
+ <tr>
255
+ <td colspan="4">
256
+ <p class="wsal-tab-help wsal-tab-notice description"><?php echo esc_html__( 'The plugin Yoast SEO is not installed on your website so these events have been disabled.', 'wp-security-audit-log' ); ?></p>
257
+ </td>
258
+ </tr>
259
+ <?php elseif ( __( 'MultiSite', 'wp-security-audit-log' ) === $subname && ! empty( $disabled ) ) : ?>
260
+ <tr>
261
+ <td colspan="4">
262
+ <p class="wsal-tab-help wsal-tab-notice description"><?php echo esc_html__( 'Your website is a single site so the multisite events have been disabled.', 'wp-security-audit-log' ); ?></p>
263
+ </td>
264
+ </tr>
265
  <?php
266
  endif;
267
 
290
  type="checkbox"
291
  class="alert"
292
  <?php checked( $active[ $alert->type ] ); ?>
293
+ value="<?php echo esc_attr( (int) $alert->type ); ?>"
294
+ <?php echo esc_attr( $disabled ); ?>
295
  <?php echo ( __( 'File Changes', 'wp-security-audit-log' ) === $subname ) ? 'onclick="wsal_toggle_file_changes(this)"' : false; ?>
296
  />
297
  </th>
301
  </tr>
302
  <?php
303
  if ( 6007 === $alert->type ) {
304
+ $log_404 = $this->_plugin->GetGlobalOption( 'log-404' );
305
+ $purge_log = $this->_plugin->GetGlobalOption( 'purge-404-log' );
306
  $log_404_referrer = $this->_plugin->GetGlobalOption( 'log-404-referrer', 'on' );
307
  ?>
308
  <tr>
334
  <?php
335
  }
336
  if ( 6023 === $alert->type ) {
337
+ $log_visitor_404 = $this->_plugin->GetGlobalOption( 'log-visitor-404' );
338
+ $purge_visitor_log = $this->_plugin->GetGlobalOption( 'purge-visitor-404-log' );
339
  $log_visitor_404_referrer = $this->_plugin->GetGlobalOption( 'log-visitor-404-referrer', 'on' );
340
  ?>
341
  <tr>
392
  </tr>
393
  <?php
394
  }
395
+ if ( 9019 === $alert->type ) {
396
+ $wc_all_stock_changes = $this->_plugin->GetGlobalOption( 'wc-all-stock-changes', 'on' );
397
+ ?>
398
+ <tr>
399
+ <td></td>
400
+ <td>
401
+ <input name="wc_all_stock_changes" type="checkbox" id="wc_all_stock_changes" value="1" <?php checked( $wc_all_stock_changes, 'on' ); ?> />
402
+ </td>
403
+ <td colspan="2"><?php esc_html_e( 'Log all stock changes. Disable this setting to only keep a log of stock changes done manually via the WooCommerce dashboard. Therefore automated stock changes typically done via customers placing orders or via other plugins will not be logged.', 'wp-security-audit-log' ); ?></td>
404
+ </tr>
405
+ <?php
406
+ }
407
  }
408
 
409
  // File integrity scan link.
482
  .widefat td .wsal-tab-help {
483
  margin: 0 8px;
484
  }
485
+ .widefat td .wsal-tab-notice {
486
+ color: red;
487
+ }
488
  </style>
489
  <?php
490
  }
566
  jQuery(".check_visitor_log").removeAttr('checked');
567
  }
568
  });
569
+
570
+ // Specific for alert 9019
571
+ jQuery("input[value=9019]").on("change", function(){
572
+ var check = jQuery("input[value=9019]").is(":checked");
573
+ if(check) {
574
+ jQuery("#wc_all_stock_changes").attr ( "checked" ,"checked" );
575
+ } else {
576
+ jQuery("#wc_all_stock_changes").removeAttr('checked');
577
+ }
578
+ });
579
  });
580
 
581
  var alerts = jQuery( '#alerts-file-changes .alert' ); // File change alerts.
classes/WidgetManager.php CHANGED
@@ -1,4 +1,18 @@
1
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  /**
3
  * Widget Manager
4
  *
@@ -22,19 +36,24 @@ class WSAL_WidgetManager {
22
  */
23
  public function __construct( WpSecurityAuditLog $plugin ) {
24
  $this->_plugin = $plugin;
25
- add_action( 'wp_dashboard_setup', array( $this, 'AddWidgets' ) );
26
  }
27
 
28
  /**
29
  * Method: Add widgets.
30
  */
31
- public function AddWidgets() {
32
- if ( $this->_plugin->settings->IsWidgetsEnabled()
33
- && $this->_plugin->settings->CurrentUserCan( 'view' ) ) {
 
 
 
 
 
34
  wp_add_dashboard_widget(
35
  'wsal',
36
  __( 'Latest Events', 'wp-security-audit-log' ) . ' | WP Security Audit Log',
37
- array( $this, 'RenderWidget' )
38
  );
39
  }
40
  }
@@ -42,7 +61,7 @@ class WSAL_WidgetManager {
42
  /**
43
  * Method: Render widget.
44
  */
45
- public function RenderWidget() {
46
  $query = new WSAL_Models_OccurrenceQuery();
47
 
48
  $bid = (int) $this->get_view_site_id();
@@ -62,7 +81,7 @@ class WSAL_WidgetManager {
62
  } else {
63
  ?>
64
  <table class="wp-list-table widefat" cellspacing="0" cellpadding="0"
65
- style="display: block; overflow-x: auto;">
66
  <thead>
67
  <th class="manage-column" style="width: 15%;" scope="col"><?php esc_html_e( 'User', 'wp-security-audit-log' ); ?></th>
68
  <th class="manage-column" style="width: 85%;" scope="col"><?php esc_html_e( 'Description', 'wp-security-audit-log' ); ?></th>
@@ -76,7 +95,8 @@ class WSAL_WidgetManager {
76
  <tr>
77
  <td>
78
  <?php
79
- echo ($un = $entry->GetUsername()) ? esc_html( $un ) : '<i>unknown</i>';
 
80
  ?>
81
  </td>
82
  <td>
@@ -87,8 +107,8 @@ class WSAL_WidgetManager {
87
  </tr>
88
  <?php
89
  }
90
- ?>
91
- </tbody>
92
  </table>
93
  <?php
94
  }
1
  <?php
2
+ /**
3
+ * Widget Manager
4
+ *
5
+ * Manager class for WSAL's WP Dashboard widget.
6
+ *
7
+ * @since 1.0.0
8
+ * @package Wsal
9
+ */
10
+
11
+ // Exit if accessed directly.
12
+ if ( ! defined( 'ABSPATH' ) ) {
13
+ exit;
14
+ }
15
+
16
  /**
17
  * Widget Manager
18
  *
36
  */
37
  public function __construct( WpSecurityAuditLog $plugin ) {
38
  $this->_plugin = $plugin;
39
+ add_action( 'wp_dashboard_setup', array( $this, 'add_widgets' ) );
40
  }
41
 
42
  /**
43
  * Method: Add widgets.
44
  */
45
+ public function add_widgets() {
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 Security Audit Log',
56
+ array( $this, 'render_widget' )
57
  );
58
  }
59
  }
61
  /**
62
  * Method: Render widget.
63
  */
64
+ public function render_widget() {
65
  $query = new WSAL_Models_OccurrenceQuery();
66
 
67
  $bid = (int) $this->get_view_site_id();
81
  } else {
82
  ?>
83
  <table class="wp-list-table widefat" cellspacing="0" cellpadding="0"
84
+ style="display: block; overflow-x: auto;">
85
  <thead>
86
  <th class="manage-column" style="width: 15%;" scope="col"><?php esc_html_e( 'User', 'wp-security-audit-log' ); ?></th>
87
  <th class="manage-column" style="width: 85%;" scope="col"><?php esc_html_e( 'Description', 'wp-security-audit-log' ); ?></th>
95
  <tr>
96
  <td>
97
  <?php
98
+ $username = $entry->GetUsername();
99
+ echo ( $username ) ? esc_html( $username ) : '<i>unknown</i>';
100
  ?>
101
  </td>
102
  <td>
107
  </tr>
108
  <?php
109
  }
110
+ ?>
111
+ </tbody>
112
  </table>
113
  <?php
114
  }
css/extensions.css CHANGED
@@ -125,7 +125,7 @@
125
  margin: 0 auto;
126
  }
127
 
128
- .activity-block .rating-link {
129
  display: inline-block;
130
  line-height: 1.5;
131
  color: #ffb900;
@@ -141,18 +141,42 @@
141
  font-size: 17px;
142
  }
143
 
144
- .postbox {
145
- margin-right: 270px;
 
146
  }
147
 
148
  .wsal-sidebar-advert {
149
  position: absolute;
150
  top: 10px;
151
- right: 70px;
152
- width: 180px;
 
 
 
 
153
  }
154
 
155
  .swipebox {
156
  display: inline-block;
157
  margin-top: 10px;
158
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
125
  margin: 0 auto;
126
  }
127
 
128
+ .rating-link {
129
  display: inline-block;
130
  line-height: 1.5;
131
  color: #ffb900;
141
  font-size: 17px;
142
  }
143
 
144
+ .wsal-nav-tabs-wrap {
145
+ position: relative;
146
+ padding-right: 300px;
147
  }
148
 
149
  .wsal-sidebar-advert {
150
  position: absolute;
151
  top: 10px;
152
+ right: 57px;
153
+ width: 200px;
154
+ }
155
+
156
+ .postbox .hndl {
157
+ padding: 0 12px;
158
  }
159
 
160
  .swipebox {
161
  display: inline-block;
162
  margin-top: 10px;
163
  }
164
+
165
+ .wsal-tab {
166
+ display: none;
167
+ margin-top: 0px;
168
+ }
169
+ .wsal-tab th {
170
+ padding-left: 20px;
171
+ }
172
+ .wsal-tab td {
173
+ padding-left: 20px;
174
+ }
175
+
176
+ .wsal-tab__heading {
177
+ font-size: 23px;
178
+ font-weight: 400;
179
+ margin: 0;
180
+ padding: 9px 0 4px;
181
+ line-height: 29px;
182
+ }
css/settings.css CHANGED
@@ -16,9 +16,13 @@
16
  margin: 4px 0;
17
  }
18
 
 
 
 
19
  .sectoken-user,
20
  .sectoken-role,
21
  .sectoken-cpts,
 
22
  .sectoken-other {
23
  display: inline-block;
24
  border-width: 1px;
@@ -36,6 +40,7 @@
36
  .sectoken-user a,
37
  .sectoken-role a,
38
  .sectoken-cpts a,
 
39
  .sectoken-other a {
40
  text-decoration: none;
41
  font-size: 12px;
@@ -55,6 +60,7 @@
55
  .sectoken-user a:hover,
56
  .sectoken-role a:hover,
57
  .sectoken-cpts a:hover,
 
58
  .sectoken-other a:hover {
59
  background: #FB9;
60
  }
@@ -62,6 +68,7 @@
62
  .sectoken-user { background: #EFF; border-color: #5BE; }
63
  .sectoken-role { background: #EFE; border-color: #5B5; }
64
  .sectoken-cpts { background: #EFF; border-color: #5BE; }
 
65
  .sectoken-other { background: #FFE; border-color: #ED5; }
66
  .sectoken-del { background: #FEE; border-color: #EBB; }
67
 
@@ -179,7 +186,8 @@ a.disabled {
179
  }
180
 
181
  #wsal_files,
182
- #wsal_files_types {
 
183
  width: 250px;
184
  height: 230px;
185
  overflow-y: scroll;
@@ -189,7 +197,8 @@ a.disabled {
189
  }
190
 
191
  #wsal_files label,
192
- #wsal_files_types label {
 
193
  display: block;
194
  margin-bottom: 2px;
195
  padding: 3px 5px;
@@ -197,23 +206,27 @@ a.disabled {
197
  }
198
 
199
  #wsal_files input[type='checkbox'],
200
- #wsal_files_types input[type='checkbox'] {
 
201
  display: none;
202
  }
203
 
204
  #wsal_files input[type='checkbox']:checked + label,
205
- #wsal_files_types input[type='checkbox']:checked + label {
 
206
  background: #f1f1f1;
207
  }
208
 
209
  #wsal_files label:hover,
210
- #wsal_files_types label:hover {
 
211
  background: #f1f1f1;
212
  transition: all 0.2s linear;
213
  }
214
 
215
  #wsal_add_file_name,
216
- #wsal_add_file_type_name {
 
217
  display: inline-block;
218
  width: 261px;
219
  height: 28px;
16
  margin: 4px 0;
17
  }
18
 
19
+ .wsal-tab__heading {
20
+ margin-bottom: 0;
21
+ }
22
  .sectoken-user,
23
  .sectoken-role,
24
  .sectoken-cpts,
25
+ .sectoken-urls,
26
  .sectoken-other {
27
  display: inline-block;
28
  border-width: 1px;
40
  .sectoken-user a,
41
  .sectoken-role a,
42
  .sectoken-cpts a,
43
+ .sectoken-urls a,
44
  .sectoken-other a {
45
  text-decoration: none;
46
  font-size: 12px;
60
  .sectoken-user a:hover,
61
  .sectoken-role a:hover,
62
  .sectoken-cpts a:hover,
63
+ .sectoken-urls a:hover,
64
  .sectoken-other a:hover {
65
  background: #FB9;
66
  }
68
  .sectoken-user { background: #EFF; border-color: #5BE; }
69
  .sectoken-role { background: #EFE; border-color: #5B5; }
70
  .sectoken-cpts { background: #EFF; border-color: #5BE; }
71
+ .sectoken-urls { background: #EFF; border-color: #5BE; }
72
  .sectoken-other { background: #FFE; border-color: #ED5; }
73
  .sectoken-del { background: #FEE; border-color: #EBB; }
74
 
186
  }
187
 
188
  #wsal_files,
189
+ #wsal_files_types,
190
+ #wsal_dirs {
191
  width: 250px;
192
  height: 230px;
193
  overflow-y: scroll;
197
  }
198
 
199
  #wsal_files label,
200
+ #wsal_files_types label,
201
+ #wsal_dirs label {
202
  display: block;
203
  margin-bottom: 2px;
204
  padding: 3px 5px;
206
  }
207
 
208
  #wsal_files input[type='checkbox'],
209
+ #wsal_files_types input[type='checkbox'],
210
+ #wsal_dirs input[type='checkbox'] {
211
  display: none;
212
  }
213
 
214
  #wsal_files input[type='checkbox']:checked + label,
215
+ #wsal_files_types input[type='checkbox']:checked + label,
216
+ #wsal_dirs input[type='checkbox']:checked + label {
217
  background: #f1f1f1;
218
  }
219
 
220
  #wsal_files label:hover,
221
+ #wsal_files_types label:hover,
222
+ #wsal_dirs label:hover {
223
  background: #f1f1f1;
224
  transition: all 0.2s linear;
225
  }
226
 
227
  #wsal_add_file_name,
228
+ #wsal_add_file_type_name,
229
+ #wsal_add_dir_name {
230
  display: inline-block;
231
  width: 261px;
232
  height: 28px;
defaults.php CHANGED
@@ -352,8 +352,8 @@ function wsaldefaults_wsal_init( WpSecurityAuditLog $wsal ) {
352
  array( 6003, E_CRITICAL, __( 'WordPress Administrator Notification email changed', 'wp-security-audit-log' ), __( 'Changed the WordPress administrator notifications email address from %OldEmail% to %NewEmail%.', 'wp-security-audit-log' ) ),
353
  array( 6004, E_CRITICAL, __( 'WordPress was updated', 'wp-security-audit-log' ), __( 'Updated WordPress from version %OldVersion% to %NewVersion%.', 'wp-security-audit-log' ) ),
354
  array( 6005, E_CRITICAL, __( 'User changes the WordPress Permalinks', 'wp-security-audit-log' ), __( 'Changed the WordPress permalinks from %OldPattern% to %NewPattern%.', 'wp-security-audit-log' ) ),
355
- array( 6007, E_NOTICE, __( 'User requests non-existing pages (404 Error Pages)', 'wp-security-audit-log' ), __( 'Has requested a non existing page (404 Error Pages) %Attempts% %Msg%. %LinkFile%', 'wp-security-audit-log' ) ),
356
- array( 6023, E_NOTICE, __( 'Website Visitor User requests non-existing pages (404 Error Pages)', 'wp-security-audit-log' ), __( 'Website Visitor Has requested a non existing page (404 Error Pages) %Attempts% %Msg%. %LinkFile%', 'wp-security-audit-log' ) ),
357
  array( 6024, E_CRITICAL, __( 'Option WordPress Address (URL) in WordPress settings changed', 'wp-security-audit-log' ), __( 'Changed the WordPress address (URL) from %old_url% to %new_url%.', 'wp-security-audit-log' ) ),
358
  array( 6025, E_CRITICAL, __( 'Option Site Address (URL) in WordPress settings changed', 'wp-security-audit-log' ), __( 'Changed the site address (URL) from %old_url% to %new_url%.', 'wp-security-audit-log' ) ),
359
  array( 9999, E_CRITICAL, __( 'Advertising Add-ons.', 'wp-security-audit-log' ), __( '%PromoName% %PromoMessage%', 'wp-security-audit-log' ) ),
@@ -410,7 +410,7 @@ function wsaldefaults_wsal_init( WpSecurityAuditLog $wsal ) {
410
  array( 6028, E_CRITICAL, __( 'File content has been modified.', 'wp-security-audit-log' ), __( 'The content of the file %FileLocation% has been modified.', 'wp-security-audit-log' ) ),
411
  array( 6029, E_CRITICAL, __( 'File added to the site.', 'wp-security-audit-log' ), __( 'The file %FileLocation% has been added to your website.', 'wp-security-audit-log' ) ),
412
  array( 6030, E_CRITICAL, __( 'File deleted from the site.', 'wp-security-audit-log' ), __( 'The file %FileLocation% has been deleted from your website.', 'wp-security-audit-log' ) ),
413
- array( 6031, E_CRITICAL, __( 'File not scanned because it is bigger than 2MB.', 'wp-security-audit-log' ), __( 'The file %FileLocation% was not scanned because it is bigger than 2MB. Please <a href="https://www.wpsecurityauditlog.com/contact/" target="_blank">contact our support</a> for more information.', 'wp-security-audit-log' ) ),
414
  array( 6032, E_CRITICAL, __( 'File integrity scan stopped due to the limit of 1 million files.', 'wp-security-audit-log' ), __( 'The file changes scanning engine has reached the limit of 1 million files and stopped the scan. Please <a href="https://www.wpsecurityauditlog.com/contact/" target="_blank">contact our support</a> for more information.', 'wp-security-audit-log' ) ),
415
  ),
416
  ),
@@ -529,7 +529,13 @@ function wsaldefaults_wsal_init( WpSecurityAuditLog $wsal ) {
529
  array( 9032, E_CRITICAL, __( 'User Enabled/Disabled the use of coupons during checkout', 'wp-security-audit-log' ), __( '%Status% the use of coupons during checkout in WooCommerce.', 'wp-security-audit-log' ) ),
530
  array( 9033, E_CRITICAL, __( 'User Enabled/Disabled guest checkout', 'wp-security-audit-log' ), __( '%Status% guest checkout in WooCommerce.', 'wp-security-audit-log' ) ),
531
  array( 9034, E_CRITICAL, __( 'User Enabled/Disabled cash on delivery', 'wp-security-audit-log' ), __( '%Status% the option Enable cash on delivery in WooCommerce.', 'wp-security-audit-log' ) ),
 
 
532
  ),
 
 
 
 
533
  __( 'Yoast SEO', 'wp-security-audit-log' ) => array(
534
  array( 8801, E_NOTICE, __( 'User changed title of a SEO post', 'wp-security-audit-log' ), __( 'Changed the SEO title of the %PostStatus% %PostType%%ReportText%.%ChangeText% %EditorLinkPost%.', 'wp-security-audit-log' ) ),
535
  array( 8802, E_NOTICE, __( 'User changed the meta description of a SEO post', 'wp-security-audit-log' ), __( 'Changed the Meta description of the %PostStatus% %PostType% titled %PostTitle%%ReportText%.%ChangeText% %EditorLinkPost%.', 'wp-security-audit-log' ) ),
352
  array( 6003, E_CRITICAL, __( 'WordPress Administrator Notification email changed', 'wp-security-audit-log' ), __( 'Changed the WordPress administrator notifications email address from %OldEmail% to %NewEmail%.', 'wp-security-audit-log' ) ),
353
  array( 6004, E_CRITICAL, __( 'WordPress was updated', 'wp-security-audit-log' ), __( 'Updated WordPress from version %OldVersion% to %NewVersion%.', 'wp-security-audit-log' ) ),
354
  array( 6005, E_CRITICAL, __( 'User changes the WordPress Permalinks', 'wp-security-audit-log' ), __( 'Changed the WordPress permalinks from %OldPattern% to %NewPattern%.', 'wp-security-audit-log' ) ),
355
+ array( 6007, E_NOTICE, __( 'User requests non-existing pages (404 Error Pages)', 'wp-security-audit-log' ), __( 'Has requested a non existing page (404 Error Pages) %Attempts% %Msg%. %LinkFile%%URL%', 'wp-security-audit-log' ) ),
356
+ array( 6023, E_NOTICE, __( 'Website Visitor User requests non-existing pages (404 Error Pages)', 'wp-security-audit-log' ), __( 'Website Visitor Has requested a non existing page (404 Error Pages) %Attempts% %Msg%. %LinkFile%%URL%', 'wp-security-audit-log' ) ),
357
  array( 6024, E_CRITICAL, __( 'Option WordPress Address (URL) in WordPress settings changed', 'wp-security-audit-log' ), __( 'Changed the WordPress address (URL) from %old_url% to %new_url%.', 'wp-security-audit-log' ) ),
358
  array( 6025, E_CRITICAL, __( 'Option Site Address (URL) in WordPress settings changed', 'wp-security-audit-log' ), __( 'Changed the site address (URL) from %old_url% to %new_url%.', 'wp-security-audit-log' ) ),
359
  array( 9999, E_CRITICAL, __( 'Advertising Add-ons.', 'wp-security-audit-log' ), __( '%PromoName% %PromoMessage%', 'wp-security-audit-log' ) ),
410
  array( 6028, E_CRITICAL, __( 'File content has been modified.', 'wp-security-audit-log' ), __( 'The content of the file %FileLocation% has been modified.', 'wp-security-audit-log' ) ),
411
  array( 6029, E_CRITICAL, __( 'File added to the site.', 'wp-security-audit-log' ), __( 'The file %FileLocation% has been added to your website.', 'wp-security-audit-log' ) ),
412
  array( 6030, E_CRITICAL, __( 'File deleted from the site.', 'wp-security-audit-log' ), __( 'The file %FileLocation% has been deleted from your website.', 'wp-security-audit-log' ) ),
413
+ array( 6031, E_CRITICAL, __( 'File not scanned because it is bigger than 5MB.', 'wp-security-audit-log' ), __( 'The file %FileLocation% was not scanned because it is bigger than 5MB. Please <a href="https://www.wpsecurityauditlog.com/contact/" target="_blank">contact our support</a> for more information.', 'wp-security-audit-log' ) ),
414
  array( 6032, E_CRITICAL, __( 'File integrity scan stopped due to the limit of 1 million files.', 'wp-security-audit-log' ), __( 'The file changes scanning engine has reached the limit of 1 million files and stopped the scan. Please <a href="https://www.wpsecurityauditlog.com/contact/" target="_blank">contact our support</a> for more information.', 'wp-security-audit-log' ) ),
415
  ),
416
  ),
529
  array( 9032, E_CRITICAL, __( 'User Enabled/Disabled the use of coupons during checkout', 'wp-security-audit-log' ), __( '%Status% the use of coupons during checkout in WooCommerce.', 'wp-security-audit-log' ) ),
530
  array( 9033, E_CRITICAL, __( 'User Enabled/Disabled guest checkout', 'wp-security-audit-log' ), __( '%Status% guest checkout in WooCommerce.', 'wp-security-audit-log' ) ),
531
  array( 9034, E_CRITICAL, __( 'User Enabled/Disabled cash on delivery', 'wp-security-audit-log' ), __( '%Status% the option Enable cash on delivery in WooCommerce.', 'wp-security-audit-log' ) ),
532
+ array( 9072, E_NOTICE, __( 'User opened a product in the editor', 'wp-security-audit-log' ), __( 'Opened the %ProductStatus% product page %ProductTitle% in editor. View the product: %EditorLinkProduct%.', 'wp-security-audit-log' ) ),
533
+ array( 9073, E_NOTICE, __( 'User viewed a product', 'wp-security-audit-log' ), __( 'Viewed the %ProductStatus% product page %ProductTitle%. View the product: %EditorLinkProduct%.', 'wp-security-audit-log' ) ),
534
  ),
535
+
536
+ /**
537
+ * Alerts: Yoast SEO
538
+ */
539
  __( 'Yoast SEO', 'wp-security-audit-log' ) => array(
540
  array( 8801, E_NOTICE, __( 'User changed title of a SEO post', 'wp-security-audit-log' ), __( 'Changed the SEO title of the %PostStatus% %PostType%%ReportText%.%ChangeText% %EditorLinkPost%.', 'wp-security-audit-log' ) ),
541
  array( 8802, E_NOTICE, __( 'User changed the meta description of a SEO post', 'wp-security-audit-log' ), __( 'Changed the Meta description of the %PostStatus% %PostType% titled %PostTitle%%ReportText%.%ChangeText% %EditorLinkPost%.', 'wp-security-audit-log' ) ),
includes/class-wsal-browser.php ADDED
@@ -0,0 +1,1545 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Browser Information Class
4
+ *
5
+ * Browser Information Class of the plugin.
6
+ *
7
+ * @since 3.2.2
8
+ * @package Wsal
9
+ */
10
+
11
+ // Exit if accessed directly.
12
+ if ( ! defined( 'ABSPATH' ) ) {
13
+ exit;
14
+ }
15
+
16
+ /**
17
+ * File: Browser.php
18
+ * Author: Chris Schuld (http://chrisschuld.com/)
19
+ * Last Modified: August 20th, 2010
20
+ *
21
+ * Copyright (C) 2008-2010 Chris Schuld (chris@chrisschuld.com)
22
+ *
23
+ * This program is free software; you can redistribute it and/or
24
+ * modify it under the terms of the GNU General Public License as
25
+ * published by the Free Software Foundation; either version 2 of
26
+ * the License, or (at your option) any later version.
27
+ *
28
+ * This program is distributed in the hope that it will be useful,
29
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
30
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31
+ * GNU General Public License for more details at:
32
+ * http://www.gnu.org/copyleft/gpl.html
33
+ *
34
+ *
35
+ * Typical Usage:
36
+ *
37
+ * $browser = new Browser();
38
+ * if( $browser->getBrowser() == Browser::BROWSER_FIREFOX && $browser->getVersion() >= 2 ) {
39
+ * echo 'You have FireFox version 2 or greater';
40
+ * }
41
+ *
42
+ * User Agents Sampled from: http://www.useragentstring.com/
43
+ *
44
+ * This implementation is based on the original work from Gary White
45
+ * http://apptools.com/phptools/browser/
46
+ *
47
+ * UPDATES:
48
+ *
49
+ * 2010-08-20 (v1.9):
50
+ * + Added MSN Explorer Browser (legacy)
51
+ * + Added Bing/MSN Robot (Thanks Rob MacDonald)
52
+ * + Added the Android Platform (PLATFORM_ANDROID)
53
+ * + Fixed issue with Android 1.6/2.2 (Thanks Tom Hirashima)
54
+ *
55
+ * 2010-04-27 (v1.8):
56
+ * + Added iPad Support
57
+ *
58
+ * 2010-03-07 (v1.7):
59
+ * + *MAJOR* Rebuild (preg_match and other "slow" routine removal(s))
60
+ * + Almost allof Gary's original code has been replaced
61
+ * + Large PHPUNIT testing environment created to validate new releases and additions
62
+ * + Added FreeBSD Platform
63
+ * + Added OpenBSD Platform
64
+ * + Added NetBSD Platform
65
+ * + Added SunOS Platform
66
+ * + Added OpenSolaris Platform
67
+ * + Added support of the Iceweazel Browser
68
+ * + Added isChromeFrame() call to check if chromeframe is in use
69
+ * + Moved the Opera check in front of the Firefox check due to legacy Opera User Agents
70
+ * + Added the __toString() method (Thanks Deano)
71
+ *
72
+ * 2009-11-15:
73
+ * + Updated the checkes for Firefox
74
+ * + Added the NOKIA platform
75
+ * + Added Checks for the NOKIA brower(s)
76
+ *
77
+ * 2009-11-08:
78
+ * + PHP 5.3 Support
79
+ * + Added support for BlackBerry OS and BlackBerry browser
80
+ * + Added support for the Opera Mini browser
81
+ * + Added additional documenation
82
+ * + Added support for isRobot() and isMobile()
83
+ * + Added support for Opera version 10
84
+ * + Added support for deprecated Netscape Navigator version 9
85
+ * + Added support for IceCat
86
+ * + Added support for Shiretoko
87
+ *
88
+ * 2010-04-27 (v1.8):
89
+ * + Added iPad Support
90
+ *
91
+ * 2009-08-18:
92
+ * + Updated to support PHP 5.3 - removed all deprecated function calls
93
+ * + Updated to remove all double quotes (") -- converted to single quotes (')
94
+ *
95
+ * 2009-04-27:
96
+ * + Updated the IE check to remove a typo and bug (thanks John)
97
+ *
98
+ * 2009-04-22:
99
+ * + Added detection for GoogleBot
100
+ * + Added detection for the W3C Validator.
101
+ * + Added detection for Yahoo! Slurp
102
+ *
103
+ * 2009-03-14:
104
+ * + Added detection for iPods.
105
+ * + Added Platform detection for iPhones
106
+ * + Added Platform detection for iPods
107
+ *
108
+ * 2009-02-16: (Rick Hale)
109
+ * + Added version detection for Android phones.
110
+ *
111
+ * 2008-12-09:
112
+ * + Removed unused constant
113
+ *
114
+ * 2008-11-07:
115
+ * + Added Google's Chrome to the detection list
116
+ * + Added isBrowser(string) to the list of functions special thanks to
117
+ * Daniel 'mavrick' Lang for the function concept (http://mavrick.id.au)
118
+ *
119
+ *
120
+ * Gary White noted: "Since browser detection is so unreliable, I am
121
+ * no longer maintaining this script. You are free to use and or
122
+ * modify/update it as you want, however the author assumes no
123
+ * responsibility for the accuracy of the detected values."
124
+ *
125
+ * Anyone experienced with Gary's script might be interested in these notes:
126
+ *
127
+ * Added class constants
128
+ * Added detection and version detection for Google's Chrome
129
+ * Updated the version detection for Amaya
130
+ * Updated the version detection for Firefox
131
+ * Updated the version detection for Lynx
132
+ * Updated the version detection for WebTV
133
+ * Updated the version detection for NetPositive
134
+ * Updated the version detection for IE
135
+ * Updated the version detection for OmniWeb
136
+ * Updated the version detection for iCab
137
+ * Updated the version detection for Safari
138
+ * Updated Safari to remove mobile devices (iPhone)
139
+ * Added detection for iPhone
140
+ * Added detection for robots
141
+ * Added detection for mobile devices
142
+ * Added detection for BlackBerry
143
+ * Removed Netscape checks (matches heavily with firefox & mozilla)
144
+ *
145
+ * @version 1.9
146
+ * @package PegasusPHP
147
+ */
148
+ class WSAL_Browser {
149
+
150
+ /**
151
+ * Agent
152
+ *
153
+ * @var string
154
+ */
155
+ public $_agent = '';
156
+
157
+ /**
158
+ * Browser name
159
+ *
160
+ * @var string
161
+ */
162
+ public $_browser_name = '';
163
+
164
+ /**
165
+ * Version
166
+ *
167
+ * @var string
168
+ */
169
+ public $_version = '';
170
+
171
+ /**
172
+ * Platform
173
+ *
174
+ * @var string
175
+ */
176
+ public $_platform = '';
177
+
178
+ /**
179
+ * OS
180
+ *
181
+ * @var string
182
+ */
183
+ public $_os = '';
184
+
185
+ /**
186
+ * _is_aol
187
+ *
188
+ * @var bool
189
+ */
190
+ public $_is_aol = false;
191
+
192
+ /**
193
+ * _is_mobile
194
+ *
195
+ * @var bool
196
+ */
197
+ public $_is_mobile = false;
198
+
199
+ /**
200
+ * _is_robot
201
+ *
202
+ * @var bool
203
+ */
204
+ public $_is_robot = false;
205
+
206
+ /**
207
+ * _aol_version
208
+ *
209
+ * @var string
210
+ */
211
+ public $_aol_version = '';
212
+
213
+
214
+ /**
215
+ * BROWSER_UNKNOWN
216
+ *
217
+ * @var string
218
+ */
219
+ public $BROWSER_UNKNOWN = 'unknown';
220
+
221
+ /**
222
+ * VERSION_UNKNOWN
223
+ *
224
+ * @var string
225
+ */
226
+ public $VERSION_UNKNOWN = 'unknown';
227
+
228
+
229
+ /**
230
+ * BROWSER_OPERA
231
+ *
232
+ * @var string
233
+ */
234
+ public $BROWSER_OPERA = 'Opera'; // URL: http://www.opera.com/.
235
+
236
+ /**
237
+ * BROWSER_OPERA_MINI
238
+ *
239
+ * @var string
240
+ */
241
+ public $BROWSER_OPERA_MINI = 'Opera Mini'; // URL: http://www.opera.com/mini/.
242
+
243
+ /**
244
+ * BROWSER_WEBTV
245
+ *
246
+ * @var string
247
+ */
248
+ public $BROWSER_WEBTV = 'WebTV'; // URL: http://www.webtv.net/pc/.
249
+
250
+ /**
251
+ * BROWSER_IE
252
+ *
253
+ * @var string
254
+ */
255
+ public $BROWSER_IE = 'Internet Explorer'; // URL: http://www.microsoft.com/ie/.
256
+
257
+ /**
258
+ * BROWSER_POCKET_IE
259
+ *
260
+ * @var string
261
+ */
262
+ public $BROWSER_POCKET_IE = 'Pocket Internet Explorer'; // URL: http://en.wikipedia.org/wiki/Internet_Explorer_Mobile.
263
+
264
+ /**
265
+ * BROWSER_KONQUEROR
266
+ *
267
+ * @var string
268
+ */
269
+ public $BROWSER_KONQUEROR = 'Konqueror'; // URL: http://www.konqueror.org/.
270
+
271
+ /**
272
+ * BROWSER_ICAB
273
+ *
274
+ * @var string
275
+ */
276
+ public $BROWSER_ICAB = 'iCab'; // URL: http://www.icab.de/.
277
+
278
+ /**
279
+ * BROWSER_OMNIWEB
280
+ *
281
+ * @var string
282
+ */
283
+ public $BROWSER_OMNIWEB = 'OmniWeb'; // URL: http://www.omnigroup.com/applications/omniweb/.
284
+
285
+ /**
286
+ * BROWSER_FIREBIRD
287
+ *
288
+ * @var string
289
+ */
290
+ public $BROWSER_FIREBIRD = 'Firebird'; // URL: http://www.ibphoenix.com/.
291
+
292
+ /**
293
+ * BROWSER_FIREFOX
294
+ *
295
+ * @var string
296
+ */
297
+ public $BROWSER_FIREFOX = 'Firefox'; // URL: http://www.mozilla.com/en-US/firefox/firefox.html.
298
+
299
+ /**
300
+ * BROWSER_ICEWEASEL
301
+ *
302
+ * @var string
303
+ */
304
+ public $BROWSER_ICEWEASEL = 'Iceweasel'; // URL: http://www.geticeweasel.org/.
305
+
306
+ /**
307
+ * BROWSER_SHIRETOKO
308
+ *
309
+ * @var string
310
+ */
311
+ public $BROWSER_SHIRETOKO = 'Shiretoko'; // URL: http://wiki.mozilla.org/Projects/shiretoko.
312
+
313
+ /**
314
+ * BROWSER_MOZILLA
315
+ *
316
+ * @var string
317
+ */
318
+ public $BROWSER_MOZILLA = 'Mozilla'; // URL: http://www.mozilla.com/en-US/.
319
+
320
+ /**
321
+ * BROWSER_AMAYA
322
+ *
323
+ * @var string
324
+ */
325
+ public $BROWSER_AMAYA = 'Amaya'; // URL: http://www.w3.org/Amaya/.
326
+
327
+ /**
328
+ * BROWSER_LYNX
329
+ *
330
+ * @var string
331
+ */
332
+ public $BROWSER_LYNX = 'Lynx'; // URL: http://en.wikipedia.org/wiki/Lynx.
333
+
334
+ /**
335
+ * BROWSER_SAFARI
336
+ *
337
+ * @var string
338
+ */
339
+ public $BROWSER_SAFARI = 'Safari'; // URL: http://apple.com.
340
+
341
+ /**
342
+ * BROWSER_IPHONE
343
+ *
344
+ * @var string
345
+ */
346
+ public $BROWSER_IPHONE = 'iPhone'; // URL: http://apple.com.
347
+
348
+ /**
349
+ * BROWSER_IPOD
350
+ *
351
+ * @var string
352
+ */
353
+ public $BROWSER_IPOD = 'iPod'; // URL: http://apple.com.
354
+
355
+ /**
356
+ * BROWSER_IPAD
357
+ *
358
+ * @var string
359
+ */
360
+ public $BROWSER_IPAD = 'iPad'; // URL: http://apple.com.
361
+
362
+ /**
363
+ * BROWSER_CHROME
364
+ *
365
+ * @var string
366
+ */
367
+ public $BROWSER_CHROME = 'Chrome'; // URL: http://www.google.com/chrome.
368
+
369
+ /**
370
+ * BROWSER_ANDROID
371
+ *
372
+ * @var string
373
+ */
374
+ public $BROWSER_ANDROID = 'Android'; // URL: http://www.android.com/.
375
+
376
+ /**
377
+ * BROWSER_GOOGLEBOT
378
+ *
379
+ * @var string
380
+ */
381
+ public $BROWSER_GOOGLEBOT = 'GoogleBot'; // URL: http://en.wikipedia.org/wiki/Googlebot.
382
+
383
+ /**
384
+ * BROWSER_SLURP
385
+ *
386
+ * @var string
387
+ */
388
+ public $BROWSER_SLURP = 'Yahoo! Slurp'; // URL: http://en.wikipedia.org/wiki/Yahoo!_Slurp.
389
+
390
+ /**
391
+ * BROWSER_W3CVALIDATOR
392
+ *
393
+ * @var string
394
+ */
395
+ public $BROWSER_W3CVALIDATOR = 'W3C Validator'; // URL: http://validator.w3.org/.
396
+
397
+ /**
398
+ * BROWSER_BLACKBERRY
399
+ *
400
+ * @var string
401
+ */
402
+ public $BROWSER_BLACKBERRY = 'BlackBerry'; // URL: http://www.blackberry.com/.
403
+
404
+ /**
405
+ * BROWSER_ICECAT
406
+ *
407
+ * @var string
408
+ */
409
+ public $BROWSER_ICECAT = 'IceCat'; // URL: http://en.wikipedia.org/wiki/GNU_IceCat.
410
+
411
+ /**
412
+ * BROWSER_NOKIA_S60
413
+ *
414
+ * @var string
415
+ */
416
+ public $BROWSER_NOKIA_S60 = 'Nokia S60 OSS Browser'; // URL: http://en.wikipedia.org/wiki/Web_Browser_for_S60.
417
+
418
+ /**
419
+ * BROWSER_NOKIA
420
+ *
421
+ * @var string
422
+ */
423
+ public $BROWSER_NOKIA = 'Nokia Browser'; // * All other WAP-based browsers on the Nokia Platform.
424
+
425
+ /**
426
+ * BROWSER_MSN
427
+ *
428
+ * @var string
429
+ */
430
+ public $BROWSER_MSN = 'MSN Browser'; // URL: http://explorer.msn.com/.
431
+
432
+ /**
433
+ * BROWSER_MSNBOT
434
+ *
435
+ * @var string
436
+ */
437
+ public $BROWSER_MSNBOT = 'MSN Bot'; // URL: http://search.msn.com/msnbot.htm. URL: http://en.wikipedia.org/wiki/Msnbot (used for Bing as well).
438
+
439
+ /**
440
+ * BROWSER_NETSCAPE_NAVIGATOR
441
+ *
442
+ * @var string
443
+ */
444
+ public $BROWSER_NETSCAPE_NAVIGATOR = 'Netscape Navigator'; // URL: http://browser.netscape.com/ (DEPRECATED).
445
+
446
+ /**
447
+ * BROWSER_GALEON
448
+ *
449
+ * @var string
450
+ */
451
+ public $BROWSER_GALEON = 'Galeon'; // URL: http://galeon.sourceforge.net/ (DEPRECATED).
452
+
453
+ /**
454
+ * BROWSER_NETPOSITIVE
455
+ *
456
+ * @var string
457
+ */
458
+ public $BROWSER_NETPOSITIVE = 'NetPositive'; // URL: http://en.wikipedia.org/wiki/NetPositive (DEPRECATED).
459
+
460
+ /**
461
+ * BROWSER_PHOENIX
462
+ *
463
+ * @var string
464
+ */
465
+ public $BROWSER_PHOENIX = 'Phoenix'; // URL: http://en.wikipedia.org/wiki/History_of_Mozilla_Firefox (DEPRECATED).
466
+
467
+
468
+ /**
469
+ * PLATFORM_UNKNOWN
470
+ *
471
+ * @var string
472
+ */
473
+ public $PLATFORM_UNKNOWN = 'unknown';
474
+
475
+ /**
476
+ * PLATFORM_WINDOWS
477
+ *
478
+ * @var string
479
+ */
480
+ public $PLATFORM_WINDOWS = 'Windows';
481
+
482
+ /**
483
+ * PLATFORM_WINDOWS_CE
484
+ *
485
+ * @var string
486
+ */
487
+ public $PLATFORM_WINDOWS_CE = 'Windows CE';
488
+
489
+ /**
490
+ * PLATFORM_APPLE
491
+ *
492
+ * @var string
493
+ */
494
+ public $PLATFORM_APPLE = 'Apple';
495
+
496
+ /**
497
+ * PLATFORM_LINUX
498
+ *
499
+ * @var string
500
+ */
501
+ public $PLATFORM_LINUX = 'Linux';
502
+
503
+ /**
504
+ * PLATFORM_OS2
505
+ *
506
+ * @var string
507
+ */
508
+ public $PLATFORM_OS2 = 'OS/2';
509
+
510
+ /**
511
+ * PLATFORM_BEOS
512
+ *
513
+ * @var string
514
+ */
515
+ public $PLATFORM_BEOS = 'BeOS';
516
+
517
+ /**
518
+ * PLATFORM_IPHONE
519
+ *
520
+ * @var string
521
+ */
522
+ public $PLATFORM_IPHONE = 'iPhone';
523
+
524
+ /**
525
+ * PLATFORM_IPOD
526
+ *
527
+ * @var string
528
+ */
529
+ public $PLATFORM_IPOD = 'iPod';
530
+
531
+ /**
532
+ * PLATFORM_IPAD
533
+ *
534
+ * @var string
535
+ */
536
+ public $PLATFORM_IPAD = 'iPad';
537
+
538
+ /**
539
+ * PLATFORM_BLACKBERRY
540
+ *
541
+ * @var string
542
+ */
543
+ public $PLATFORM_BLACKBERRY = 'BlackBerry';
544
+
545
+ /**
546
+ * PLATFORM_NOKIA
547
+ *
548
+ * @var string
549
+ */
550
+ public $PLATFORM_NOKIA = 'Nokia';
551
+
552
+ /**
553
+ * PLATFORM_FREEBSD
554
+ *
555
+ * @var string
556
+ */
557
+ public $PLATFORM_FREEBSD = 'FreeBSD';
558
+
559
+ /**
560
+ * PLATFORM_OPENBSD
561
+ *
562
+ * @var string
563
+ */
564
+ public $PLATFORM_OPENBSD = 'OpenBSD';
565
+
566
+ /**
567
+ * PLATFORM_NETBSD
568
+ *
569
+ * @var string
570
+ */
571
+ public $PLATFORM_NETBSD = 'NetBSD';
572
+
573
+ /**
574
+ * PLATFORM_SUNOS
575
+ *
576
+ * @var string
577
+ */
578
+ public $PLATFORM_SUNOS = 'SunOS';
579
+
580
+ /**
581
+ * PLATFORM_OPENSOLARIS
582
+ *
583
+ * @var string
584
+ */
585
+ public $PLATFORM_OPENSOLARIS = 'OpenSolaris';
586
+
587
+ /**
588
+ * PLATFORM_ANDROID
589
+ *
590
+ * @var string
591
+ */
592
+ public $PLATFORM_ANDROID = 'Android';
593
+
594
+
595
+ /**
596
+ * OPERATING_SYSTEM_UNKNOWN
597
+ *
598
+ * @var string
599
+ */
600
+ public $OPERATING_SYSTEM_UNKNOWN = 'unknown';
601
+
602
+ /**
603
+ * Method: Constructor.
604
+ *
605
+ * @param string $useragent - User agent.
606
+ */
607
+ function __construct( $useragent = '' ) {
608
+ $this->reset();
609
+ if ( '' != $useragent ) {
610
+ $this->setUserAgent( $useragent );
611
+ } else {
612
+ $this->determine();
613
+ }
614
+ }
615
+
616
+ /**
617
+ * Reset all properties
618
+ */
619
+ function reset() {
620
+ $http_user_agent = filter_input( INPUT_SERVER, 'HTTP_USER_AGENT', FILTER_SANITIZE_STRING );
621
+ $this->_agent = ! empty( $http_user_agent ) ? $http_user_agent : '';
622
+ $this->_browser_name = $this->BROWSER_UNKNOWN;
623
+ $this->_version = $this->VERSION_UNKNOWN;
624
+ $this->_platform = $this->PLATFORM_UNKNOWN;
625
+ $this->_os = $this->OPERATING_SYSTEM_UNKNOWN;
626
+ $this->_is_aol = false;
627
+ $this->_is_mobile = false;
628
+ $this->_is_robot = false;
629
+ $this->_aol_version = $this->VERSION_UNKNOWN;
630
+ }
631
+
632
+ /**
633
+ * Check to see if the specific browser is valid
634
+ *
635
+ * @param string $browser_name - Browser name.
636
+ * @return True if the browser is the specified browser
637
+ */
638
+ function isBrowser( $browser_name ) {
639
+ return 0 == strcasecmp( $this->_browser_name, trim( $browser_name ) );
640
+ }
641
+
642
+ /**
643
+ * The name of the browser. All return types are from the class contants
644
+ *
645
+ * @return string Name of the browser
646
+ */
647
+ function getBrowser() {
648
+ return $this->_browser_name;
649
+ }
650
+
651
+ /**
652
+ * Set the name of the browser
653
+ *
654
+ * @param unknown $browser - The name of the Browser.
655
+ */
656
+ function setBrowser( $browser ) {
657
+ return $this->_browser_name = $browser;
658
+ }
659
+
660
+ /**
661
+ * The name of the platform. All return types are from the class contants
662
+ *
663
+ * @return string Name of the browser
664
+ */
665
+ function getPlatform() {
666
+ return $this->_platform;
667
+ }
668
+
669
+ /**
670
+ * Set the name of the platform
671
+ *
672
+ * @param unknown $platform - The name of the Platform.
673
+ */
674
+ function setPlatform( $platform ) {
675
+ return $this->_platform = $platform;
676
+ }
677
+
678
+ /**
679
+ * The version of the browser.
680
+ *
681
+ * @return string Version of the browser (will only contain alpha-numeric characters and a period)
682
+ */
683
+ function getVersion() {
684
+ return $this->_version;
685
+ }
686
+
687
+
688
+ /**
689
+ * Set the version of the browser
690
+ *
691
+ * @param unknown $version - The version of the Browser.
692
+ */
693
+ function setVersion( $version ) {
694
+ $this->_version = preg_replace( '/[^0-9,.,a-z,A-Z-]/', '', $version );
695
+ }
696
+
697
+ /**
698
+ * The version of AOL.
699
+ *
700
+ * @return string Version of AOL (will only contain alpha-numeric characters and a period)
701
+ */
702
+ function getAolVersion() {
703
+ return $this->_aol_version;
704
+ }
705
+
706
+ /**
707
+ * Set the version of AOL
708
+ *
709
+ * @param unknown $version - The version of AOL.
710
+ */
711
+ function setAolVersion( $version ) {
712
+ $this->_aol_version = preg_replace( '/[^0-9,.,a-z,A-Z]/', '', $version );
713
+ }
714
+
715
+ /**
716
+ * Is the browser from AOL?
717
+ *
718
+ * @return boolean True if the browser is from AOL otherwise false
719
+ */
720
+ function isAol() {
721
+ return $this->_is_aol;
722
+ }
723
+
724
+ /**
725
+ * Is the browser from a mobile device?
726
+ *
727
+ * @return boolean True if the browser is from a mobile device otherwise false
728
+ */
729
+ function isMobile() {
730
+ return $this->_is_mobile;
731
+ }
732
+
733
+ /**
734
+ * Is the browser from a robot (ex Slurp,GoogleBot)?
735
+ *
736
+ * @return boolean True if the browser is from a robot otherwise false
737
+ */
738
+ function isRobot() {
739
+ return $this->_is_robot;
740
+ }
741
+
742
+ /**
743
+ * Set the browser to be from AOL
744
+ *
745
+ * @param unknown $isAol - True/False.
746
+ */
747
+ function setAol( $isAol ) {
748
+ $this->_is_aol = $isAol;
749
+ }
750
+
751
+ /**
752
+ * Set the Browser to be mobile
753
+ *
754
+ * @param boolean $value - is the browser a mobile brower or not.
755
+ */
756
+ function setMobile( $value = true ) {
757
+ $this->_is_mobile = $value;
758
+ }
759
+
760
+ /**
761
+ * Set the Browser to be a robot
762
+ *
763
+ * @param boolean $value - is the browser a robot or not.
764
+ */
765
+ function setRobot( $value = true ) {
766
+ $this->_is_robot = $value;
767
+ }
768
+
769
+ /**
770
+ * Get the user agent value in use to determine the browser
771
+ *
772
+ * @return string The user agent from the HTTP header
773
+ */
774
+ function getUserAgent() {
775
+ return $this->_agent;
776
+ }
777
+
778
+ /**
779
+ * Set the user agent value (the construction will use the HTTP header value - this will overwrite it)
780
+ *
781
+ * @param unknown $agent_string - The value for the User Agent.
782
+ */
783
+ function setUserAgent( $agent_string ) {
784
+ $this->reset();
785
+ $this->_agent = $agent_string;
786
+ $this->determine();
787
+ }
788
+
789
+ /**
790
+ * Used to determine if the browser is actually "chromeframe"
791
+ *
792
+ * @since 1.7
793
+ * @return boolean True if the browser is using chromeframe
794
+ */
795
+ function isChromeFrame() {
796
+ return strpos( $this->_agent, 'chromeframe' ) !== false;
797
+ }
798
+
799
+ /**
800
+ * Returns a formatted string with a summary of the details of the browser.
801
+ *
802
+ * @return string formatted string with a summary of the browser
803
+ */
804
+ function __toString() {
805
+ $text1 = $this->getUserAgent(); // Grabs the UA (user agent) string.
806
+ $ua_line1 = substr( $text1, 0, 32 ); // The first line we print should only be the first 32 characters of the UA string.
807
+ $text2 = $this->getUserAgent(); // Now we grab it again and save it to a string.
808
+ $towrap_ua = str_replace( $ua_line1, '', $text2 ); // The rest of the printoff (other than first line) is equivolent.
809
+
810
+ /**
811
+ * To the whole string minus the part we printed off. IE
812
+ * User Agent: thefirst32charactersfromUAline1
813
+ * the rest of it is now stored in
814
+ * $text2 to be printed off
815
+ * But we need to add spaces before each line that is split other than line 1
816
+ */
817
+ $space = '';
818
+ for ( $i = 0; $i < 25; $i++ ) {
819
+ $space .= ' ';
820
+ }
821
+
822
+ // Now we split the remaining string of UA ($text2) into lines that are prefixed by spaces for formatting.
823
+ $wordwrapped = chunk_split( $towrap_ua, 32, "\n $space" );
824
+ return "Platform: {$this->getPlatform()} \n" .
825
+ "Browser Name: {$this->getBrowser()} \n" .
826
+ "Browser Version: {$this->getVersion()} \n" .
827
+ "User Agent String: $ua_line1 \n\t\t\t " .
828
+ "$wordwrapped";
829
+ }
830
+
831
+ /**
832
+ * Protected routine to calculate and determine what the browser is in use (including platform)
833
+ */
834
+ function determine() {
835
+ $this->checkPlatform();
836
+ $this->checkBrowsers();
837
+ $this->checkForAol();
838
+ }
839
+
840
+ /**
841
+ * Protected routine to determine the browser type
842
+ *
843
+ * @return boolean True if the browser was detected otherwise false
844
+ */
845
+ function checkBrowsers() {
846
+ return (
847
+ /**
848
+ * Well-known, well-used
849
+ * Special Notes:
850
+ * (1) Opera must be checked before FireFox due to the odd
851
+ * user agents used in some older versions of Opera
852
+ * (2) WebTV is strapped onto Internet Explorer so we must
853
+ * check for WebTV before IE
854
+ * (3) (deprecated) Galeon is based on Firefox and needs to be
855
+ * tested before Firefox is tested
856
+ * (4) OmniWeb is based on Safari so OmniWeb check must occur
857
+ * before Safari
858
+ * (5) Netscape 9+ is based on Firefox so Netscape checks
859
+ * before FireFox are necessary.
860
+ */
861
+ $this->checkBrowserWebTv() ||
862
+ $this->checkBrowserInternetExplorer() ||
863
+ $this->checkBrowserOpera() ||
864
+ $this->checkBrowserGaleon() ||
865
+ $this->checkBrowserNetscapeNavigator9Plus() ||
866
+ $this->checkBrowserFirefox() ||
867
+ $this->checkBrowserChrome() ||
868
+ $this->checkBrowserOmniWeb() ||
869
+
870
+ // Common mobile.
871
+ $this->checkBrowserAndroid() ||
872
+ $this->checkBrowseriPad() ||
873
+ $this->checkBrowseriPod() ||
874
+ $this->checkBrowseriPhone() ||
875
+ $this->checkBrowserBlackBerry() ||
876
+ $this->checkBrowserNokia() ||
877
+
878
+ // Common bots.
879
+ $this->checkBrowserGoogleBot() ||
880
+ $this->checkBrowserMSNBot() ||
881
+ $this->checkBrowserSlurp() ||
882
+
883
+ // WebKit base check (post mobile and others).
884
+ $this->checkBrowserSafari() ||
885
+
886
+ // Everyone else.
887
+ $this->checkBrowserNetPositive() ||
888
+ $this->checkBrowserFirebird() ||
889
+ $this->checkBrowserKonqueror() ||
890
+ $this->checkBrowserIcab() ||
891
+ $this->checkBrowserPhoenix() ||
892
+ $this->checkBrowserAmaya() ||
893
+ $this->checkBrowserLynx() ||
894
+
895
+ $this->checkBrowserShiretoko() ||
896
+ $this->checkBrowserIceCat() ||
897
+ $this->checkBrowserW3CValidator() ||
898
+ $this->checkBrowserMozilla() /* Mozilla is such an open standard that you must check it last */
899
+ );
900
+ }
901
+
902
+ /**
903
+ * Determine if the user is using a BlackBerry (last updated 1.7)
904
+ *
905
+ * @return boolean True if the browser is the BlackBerry browser otherwise false
906
+ */
907
+ function checkBrowserBlackBerry() {
908
+ if ( stripos( $this->_agent, 'blackberry' ) !== false ) {
909
+ $aresult = explode( '/', stristr( $this->_agent, 'BlackBerry' ) );
910
+ $aversion = explode( ' ', $aresult[1] );
911
+ $this->setVersion( $aversion[0] );
912
+ $this->_browser_name = $this->BROWSER_BLACKBERRY;
913
+ $this->setMobile( true );
914
+ return true;
915
+ }
916
+ return false;
917
+ }
918
+
919
+ /**
920
+ * Determine if the user is using an AOL User Agent (last updated 1.7)
921
+ *
922
+ * @return boolean True if the browser is from AOL otherwise false
923
+ */
924
+ function checkForAol() {
925
+ $this->setAol( false );
926
+ $this->setAolVersion( $this->VERSION_UNKNOWN );
927
+
928
+ if ( stripos( $this->_agent, 'aol' ) !== false ) {
929
+ $aversion = explode( ' ', stristr( $this->_agent, 'AOL' ) );
930
+ $this->setAol( true );
931
+ $this->setAolVersion( preg_replace( '/[^0-9\.a-z]/i', '', $aversion[1] ) );
932
+ return true;
933
+ }
934
+ return false;
935
+ }
936
+
937
+ /**
938
+ * Determine if the browser is the GoogleBot or not (last updated 1.7)
939
+ *
940
+ * @return boolean True if the browser is the GoogletBot otherwise false
941
+ */
942
+ function checkBrowserGoogleBot() {
943
+ if ( stripos( $this->_agent, 'googlebot' ) !== false ) {
944
+ $aresult = explode( '/', stristr( $this->_agent, 'googlebot' ) );
945
+ $aversion = explode( ' ', $aresult[1] );
946
+ $this->setVersion( str_replace( ';', '', $aversion[0] ) );
947
+ $this->_browser_name = $this->BROWSER_GOOGLEBOT;
948
+ $this->setRobot( true );
949
+ return true;
950
+ }
951
+ return false;
952
+ }
953
+
954
+ /**
955
+ * Determine if the browser is the MSNBot or not (last updated 1.9)
956
+ *
957
+ * @return boolean True if the browser is the MSNBot otherwise false
958
+ */
959
+ function checkBrowserMSNBot() {
960
+ if ( stripos( $this->_agent, 'msnbot' ) !== false ) {
961
+ $aresult = explode( '/', stristr( $this->_agent, 'msnbot' ) );
962
+ $aversion = explode( ' ', $aresult[1] );
963
+ $this->setVersion( str_replace( ';', '', $aversion[0] ) );
964
+ $this->_browser_name = $this->BROWSER_MSNBOT;
965
+ $this->setRobot( true );
966
+ return true;
967
+ }
968
+ return false;
969
+ }
970
+
971
+ /**
972
+ * Determine if the browser is the W3C Validator or not (last updated 1.7)
973
+ *
974
+ * @return boolean True if the browser is the W3C Validator otherwise false
975
+ */
976
+ function checkBrowserW3CValidator() {
977
+ if ( stripos( $this->_agent, 'W3C-checklink' ) !== false ) {
978
+ $aresult = explode( '/', stristr( $this->_agent, 'W3C-checklink' ) );
979
+ $aversion = explode( ' ', $aresult[1] );
980
+ $this->setVersion( $aversion[0] );
981
+ $this->_browser_name = $this->BROWSER_W3CVALIDATOR;
982
+ return true;
983
+ } elseif ( stripos( $this->_agent, 'W3C_Validator' ) !== false ) {
984
+ // Some of the Validator versions do not delineate w/ a slash - add it back in.
985
+ $ua = str_replace( 'W3C_Validator ', 'W3C_Validator/', $this->_agent );
986
+ $aresult = explode( '/', stristr( $ua, 'W3C_Validator' ) );
987
+ $aversion = explode( ' ', $aresult[1] );
988
+ $this->setVersion( $aversion[0] );
989
+ $this->_browser_name = $this->BROWSER_W3CVALIDATOR;
990
+ return true;
991
+ }
992
+ return false;
993
+ }
994
+
995
+ /**
996
+ * Determine if the browser is the Yahoo! Slurp Robot or not (last updated 1.7)
997
+ *
998
+ * @return boolean True if the browser is the Yahoo! Slurp Robot otherwise false
999
+ */
1000
+ function checkBrowserSlurp() {
1001
+ if ( stripos( $this->_agent, 'slurp' ) !== false ) {
1002
+ $aresult = explode( '/', stristr( $this->_agent, 'Slurp' ) );
1003
+ $aversion = explode( ' ', $aresult[1] );
1004
+ $this->setVersion( $aversion[0] );
1005
+ $this->_browser_name = $this->BROWSER_SLURP;
1006
+ $this->setRobot( true );
1007
+ $this->setMobile( false );
1008
+ return true;
1009
+ }
1010
+ return false;
1011
+ }
1012
+
1013
+ /**
1014
+ * Determine if the browser is Internet Explorer or not (last updated 1.7)
1015
+ *
1016
+ * @return boolean True if the browser is Internet Explorer otherwise false
1017
+ */
1018
+ function checkBrowserInternetExplorer() {
1019
+
1020
+ // Test for v1 - v1.5 IE.
1021
+ if ( stripos( $this->_agent, 'microsoft internet explorer' ) !== false ) {
1022
+ $this->setBrowser( $this->BROWSER_IE );
1023
+ $this->setVersion( '1.0' );
1024
+ $aresult = stristr( $this->_agent, '/' );
1025
+ if ( preg_match( '/308|425|426|474|0b1/i', $aresult ) ) {
1026
+ $this->setVersion( '1.5' );
1027
+ }
1028
+ return true;
1029
+
1030
+ // Test for versions > 1.5.
1031
+ } elseif ( stripos( $this->_agent, 'msie' ) !== false && stripos( $this->_agent, 'opera' ) === false ) {
1032
+ // See if the browser is the odd MSN Explorer.
1033
+ if ( stripos( $this->_agent, 'msnb' ) !== false ) {
1034
+ $aresult = explode( ' ', stristr( str_replace( ';', '; ', $this->_agent ), 'MSN' ) );
1035
+ $this->setBrowser( $this->BROWSER_MSN );
1036
+ $this->setVersion( str_replace( array( '(', ')', ';' ), '', $aresult[1] ) );
1037
+ return true;
1038
+ }
1039
+ $aresult = explode( ' ', stristr( str_replace( ';', '; ', $this->_agent ), 'msie' ) );
1040
+ $this->setBrowser( $this->BROWSER_IE );
1041
+ $this->setVersion( str_replace( array( '(', ')', ';' ), '', $aresult[1] ) );
1042
+ return true;
1043
+
1044
+ // Test for Pocket IE.
1045
+ } elseif ( stripos( $this->_agent, 'mspie' ) !== false || stripos( $this->_agent, 'pocket' ) !== false ) {
1046
+ $aresult = explode( ' ', stristr( $this->_agent, 'mspie' ) );
1047
+ $this->setPlatform( $this->PLATFORM_WINDOWS_CE );
1048
+ $this->setBrowser( $this->BROWSER_POCKET_IE );
1049
+ $this->setMobile( true );
1050
+
1051
+ if ( stripos( $this->_agent, 'mspie' ) !== false ) {
1052
+ $this->setVersion( $aresult[1] );
1053
+ } else {
1054
+ $aversion = explode( '/', $this->_agent );
1055
+ $this->setVersion( $aversion[1] );
1056
+ }
1057
+ return true;
1058
+ }
1059
+ return false;
1060
+ }
1061
+
1062
+ /**
1063
+ * Determine if the browser is Opera or not (last updated 1.7)
1064
+ *
1065
+ * @return boolean True if the browser is Opera otherwise false
1066
+ */
1067
+ function checkBrowserOpera() {
1068
+ if ( stripos( $this->_agent, 'opera mini' ) !== false ) {
1069
+ $resultant = stristr( $this->_agent, 'opera mini' );
1070
+ if ( preg_match( '/\//', $resultant ) ) {
1071
+ $aresult = explode( '/', $resultant );
1072
+ $aversion = explode( ' ', $aresult[1] );
1073
+ $this->setVersion( $aversion[0] );
1074
+ } else {
1075
+ $aversion = explode( ' ', stristr( $resultant, 'opera mini' ) );
1076
+ $this->setVersion( $aversion[1] );
1077
+ }
1078
+ $this->_browser_name = $this->BROWSER_OPERA_MINI;
1079
+ $this->setMobile( true );
1080
+ return true;
1081
+ } elseif ( stripos( $this->_agent, 'opera' ) !== false ) {
1082
+ $resultant = stristr( $this->_agent, 'opera' );
1083
+ if ( preg_match( '/Version\/(10.*)$/', $resultant, $matches ) ) {
1084
+ $this->setVersion( $matches[1] );
1085
+ } elseif ( preg_match( '/\//', $resultant ) ) {
1086
+ $aresult = explode( '/', str_replace( '(', ' ', $resultant ) );
1087
+ $aversion = explode( ' ', $aresult[1] );
1088
+ $this->setVersion( $aversion[0] );
1089
+ } else {
1090
+ $aversion = explode( ' ', stristr( $resultant, 'opera' ) );
1091
+ $this->setVersion( isset( $aversion[1] ) ? $aversion[1] : '' );
1092
+ }
1093
+ $this->_browser_name = $this->BROWSER_OPERA;
1094
+ return true;
1095
+ }
1096
+ return false;
1097
+ }
1098
+
1099
+ /**
1100
+ * Determine if the browser is Chrome or not (last updated 1.7)
1101
+ *
1102
+ * @return boolean True if the browser is Chrome otherwise false
1103
+ */
1104
+ function checkBrowserChrome() {
1105
+ if ( stripos( $this->_agent, 'Chrome' ) !== false ) {
1106
+ $aresult = explode( '/', stristr( $this->_agent, 'Chrome' ) );
1107
+ $aversion = explode( ' ', $aresult[1] );
1108
+ $this->setVersion( $aversion[0] );
1109
+ $this->setBrowser( $this->BROWSER_CHROME );
1110
+ return true;
1111
+ }
1112
+ return false;
1113
+ }
1114
+
1115
+
1116
+ /**
1117
+ * Determine if the browser is WebTv or not (last updated 1.7)
1118
+ *
1119
+ * @return boolean True if the browser is WebTv otherwise false
1120
+ */
1121
+ function checkBrowserWebTv() {
1122
+ if ( stripos( $this->_agent, 'webtv' ) !== false ) {
1123
+ $aresult = explode( '/', stristr( $this->_agent, 'webtv' ) );
1124
+ $aversion = explode( ' ', $aresult[1] );
1125
+ $this->setVersion( $aversion[0] );
1126
+ $this->setBrowser( $this->BROWSER_WEBTV );
1127
+ return true;
1128
+ }
1129
+ return false;
1130
+ }
1131
+
1132
+ /**
1133
+ * Determine if the browser is NetPositive or not (last updated 1.7)
1134
+ *
1135
+ * @return boolean True if the browser is NetPositive otherwise false
1136
+ */
1137
+ function checkBrowserNetPositive() {
1138
+ if ( stripos( $this->_agent, 'NetPositive' ) !== false ) {
1139
+ $aresult = explode( '/', stristr( $this->_agent, 'NetPositive' ) );
1140
+ $aversion = explode( ' ', $aresult[1] );
1141
+ $this->setVersion( str_replace( array( '(', ')', ';' ), '', $aversion[0] ) );
1142
+ $this->setBrowser( $this->BROWSER_NETPOSITIVE );
1143
+ return true;
1144
+ }
1145
+ return false;
1146
+ }
1147
+
1148
+ /**
1149
+ * Determine if the browser is Galeon or not (last updated 1.7)
1150
+ *
1151
+ * @return boolean True if the browser is Galeon otherwise false
1152
+ */
1153
+ function checkBrowserGaleon() {
1154
+ if ( stripos( $this->_agent, 'galeon' ) !== false ) {
1155
+ $aresult = explode( ' ', stristr( $this->_agent, 'galeon' ) );
1156
+ $aversion = explode( '/', $aresult[0] );
1157
+ $this->setVersion( $aversion[1] );
1158
+ $this->setBrowser( $this->BROWSER_GALEON );
1159
+ return true;
1160
+ }
1161
+ return false;
1162
+ }
1163
+
1164
+ /**
1165
+ * Determine if the browser is Konqueror or not (last updated 1.7)
1166
+ *
1167
+ * @return boolean True if the browser is Konqueror otherwise false
1168
+ */
1169
+ function checkBrowserKonqueror() {
1170
+ if ( stripos( $this->_agent, 'Konqueror' ) !== false ) {
1171
+ $aresult = explode( ' ', stristr( $this->_agent, 'Konqueror' ) );
1172
+ $aversion = explode( '/', $aresult[0] );
1173
+ $this->setVersion( $aversion[1] );
1174
+ $this->setBrowser( $this->BROWSER_KONQUEROR );
1175
+ return true;
1176
+ }
1177
+ return false;
1178
+ }
1179
+
1180
+ /**
1181
+ * Determine if the browser is iCab or not (last updated 1.7)
1182
+ *
1183
+ * @return boolean True if the browser is iCab otherwise false
1184
+ */
1185
+ function checkBrowserIcab() {
1186
+ if ( stripos( $this->_agent, 'icab' ) !== false ) {
1187
+ $aversion = explode( ' ', stristr( str_replace( '/', ' ', $this->_agent ), 'icab' ) );
1188
+ $this->setVersion( $aversion[1] );
1189
+ $this->setBrowser( $this->BROWSER_ICAB );
1190
+ return true;
1191
+ }
1192
+ return false;
1193
+ }
1194
+
1195
+ /**
1196
+ * Determine if the browser is OmniWeb or not (last updated 1.7)
1197
+ *
1198
+ * @return boolean True if the browser is OmniWeb otherwise false
1199
+ */
1200
+ function checkBrowserOmniWeb() {
1201
+ if ( stripos( $this->_agent, 'omniweb' ) !== false ) {
1202
+ $aresult = explode( '/', stristr( $this->_agent, 'omniweb' ) );
1203
+ $aversion = explode( ' ', isset( $aresult[1] ) ? $aresult[1] : '' );
1204
+ $this->setVersion( $aversion[0] );
1205
+ $this->setBrowser( $this->BROWSER_OMNIWEB );
1206
+ return true;
1207
+ }
1208
+ return false;
1209
+ }
1210
+
1211
+ /**
1212
+ * Determine if the browser is Phoenix or not (last updated 1.7)
1213
+ *
1214
+ * @return boolean True if the browser is Phoenix otherwise false
1215
+ */
1216
+ function checkBrowserPhoenix() {
1217
+ if ( stripos( $this->_agent, 'Phoenix' ) !== false ) {
1218
+ $aversion = explode( '/', stristr( $this->_agent, 'Phoenix' ) );
1219
+ $this->setVersion( $aversion[1] );
1220
+ $this->setBrowser( $this->BROWSER_PHOENIX );
1221
+ return true;
1222
+ }
1223
+ return false;
1224
+ }
1225
+
1226
+ /**
1227
+ * Determine if the browser is Firebird or not (last updated 1.7)
1228
+ *
1229
+ * @return boolean True if the browser is Firebird otherwise false
1230
+ */
1231
+ function checkBrowserFirebird() {
1232
+ if ( stripos( $this->_agent, 'Firebird' ) !== false ) {
1233
+ $aversion = explode( '/', stristr( $this->_agent, 'Firebird' ) );
1234
+ $this->setVersion( $aversion[1] );
1235
+ $this->setBrowser( $this->BROWSER_FIREBIRD );
1236
+ return true;
1237
+ }
1238
+ return false;
1239
+ }
1240
+
1241
+ /**
1242
+ * Determine if the browser is Netscape Navigator 9+ or not (last updated 1.7)
1243
+ * NOTE: (http://browser.netscape.com/ - Official support ended on March 1st, 2008)
1244
+ *
1245
+ * @return boolean True if the browser is Netscape Navigator 9+ otherwise false
1246
+ */
1247
+ function checkBrowserNetscapeNavigator9Plus() {
1248
+ if ( stripos( $this->_agent, 'Firefox' ) !== false && preg_match( '/Navigator\/([^ ]*)/i', $this->_agent, $matches ) ) {
1249
+ $this->setVersion( $matches[1] );
1250
+ $this->setBrowser( $this->BROWSER_NETSCAPE_NAVIGATOR );
1251
+ return true;
1252
+ } elseif ( stripos( $this->_agent, 'Firefox' ) === false && preg_match( '/Netscape6?\/([^ ]*)/i', $this->_agent, $matches ) ) {
1253
+ $this->setVersion( $matches[1] );
1254
+ $this->setBrowser( $this->BROWSER_NETSCAPE_NAVIGATOR );
1255
+ return true;
1256
+ }
1257
+ return false;
1258
+ }
1259
+
1260
+ /**
1261
+ * Determine if the browser is Shiretoko or not (https://wiki.mozilla.org/Projects/shiretoko) (last updated 1.7)
1262
+ *
1263
+ * @return boolean True if the browser is Shiretoko otherwise false
1264
+ */
1265
+ function checkBrowserShiretoko() {
1266
+ if ( stripos( $this->_agent, 'Mozilla' ) !== false && preg_match( '/Shiretoko\/([^ ]*)/i', $this->_agent, $matches ) ) {
1267
+ $this->setVersion( $matches[1] );
1268
+ $this->setBrowser( $this->BROWSER_SHIRETOKO );
1269
+ return true;
1270
+ }
1271
+ return false;
1272
+ }
1273
+
1274
+ /**
1275
+ * Determine if the browser is Ice Cat or not (http://en.wikipedia.org/wiki/GNU_IceCat) (last updated 1.7)
1276
+ *
1277
+ * @return boolean True if the browser is Ice Cat otherwise false
1278
+ */
1279
+ function checkBrowserIceCat() {
1280
+ if ( stripos( $this->_agent, 'Mozilla' ) !== false && preg_match( '/IceCat\/([^ ]*)/i', $this->_agent, $matches ) ) {
1281
+ $this->setVersion( $matches[1] );
1282
+ $this->setBrowser( $this->BROWSER_ICECAT );
1283
+ return true;
1284
+ }
1285
+ return false;
1286
+ }
1287
+
1288
+ /**
1289
+ * Determine if the browser is Nokia or not (last updated 1.7)
1290
+ *
1291
+ * @return boolean True if the browser is Nokia otherwise false
1292
+ */
1293
+ function checkBrowserNokia() {
1294
+ if ( preg_match( '/Nokia([^\/]+)\/([^ SP]+)/i', $this->_agent, $matches ) ) {
1295
+ $this->setVersion( $matches[2] );
1296
+ if ( stripos( $this->_agent, 'Series60' ) !== false || strpos( $this->_agent, 'S60' ) !== false ) {
1297
+ $this->setBrowser( $this->BROWSER_NOKIA_S60 );
1298
+ } else {
1299
+ $this->setBrowser( $this->BROWSER_NOKIA );
1300
+ }
1301
+ $this->setMobile( true );
1302
+ return true;
1303
+ }
1304
+ return false;
1305
+ }
1306
+
1307
+ /**
1308
+ * Determine if the browser is Firefox or not (last updated 1.7)
1309
+ *
1310
+ * @return boolean True if the browser is Firefox otherwise false
1311
+ */
1312
+ function checkBrowserFirefox() {
1313
+ if ( stripos( $this->_agent, 'safari' ) === false ) {
1314
+ if ( preg_match( '/Firefox[\/ \(]([^ ;\)]+)/i', $this->_agent, $matches ) ) {
1315
+ $this->setVersion( $matches[1] );
1316
+ $this->setBrowser( $this->BROWSER_FIREFOX );
1317
+ return true;
1318
+ } elseif ( preg_match( '/Firefox$/i', $this->_agent, $matches ) ) {
1319
+ $this->setVersion( '' );
1320
+ $this->setBrowser( $this->BROWSER_FIREFOX );
1321
+ return true;
1322
+ }
1323
+ }
1324
+ return false;
1325
+ }
1326
+
1327
+ /**
1328
+ * Determine if the browser is Firefox or not (last updated 1.7)
1329
+ *
1330
+ * @return boolean True if the browser is Firefox otherwise false
1331
+ */
1332
+ function checkBrowserIceweasel() {
1333
+ if ( stripos( $this->_agent, 'Iceweasel' ) !== false ) {
1334
+ $aresult = explode( '/', stristr( $this->_agent, 'Iceweasel' ) );
1335
+ $aversion = explode( ' ', $aresult[1] );
1336
+ $this->setVersion( $aversion[0] );
1337
+ $this->setBrowser( $this->BROWSER_ICEWEASEL );
1338
+ return true;
1339
+ }
1340
+ return false;
1341
+ }
1342
+
1343
+ /**
1344
+ * Determine if the browser is Mozilla or not (last updated 1.7)
1345
+ *
1346
+ * @return boolean True if the browser is Mozilla otherwise false
1347
+ */
1348
+ function checkBrowserMozilla() {
1349
+ if ( stripos( $this->_agent, 'mozilla' ) !== false && preg_match( '/rv:[0-9].[0-9][a-b]?/i', $this->_agent ) && stripos( $this->_agent, 'netscape' ) === false ) {
1350
+ $aversion = explode( ' ', stristr( $this->_agent, 'rv:' ) );
1351
+ preg_match( '/rv:[0-9].[0-9][a-b]?/i', $this->_agent, $aversion );
1352
+ $this->setVersion( str_replace( 'rv:', '', $aversion[0] ) );
1353
+ $this->setBrowser( $this->BROWSER_MOZILLA );
1354
+ return true;
1355
+ } elseif ( stripos( $this->_agent, 'mozilla' ) !== false && preg_match( '/rv:[0-9]\.[0-9]/i', $this->_agent ) && stripos( $this->_agent, 'netscape' ) === false ) {
1356
+ $aversion = explode( '', stristr( $this->_agent, 'rv:' ) );
1357
+ $this->setVersion( str_replace( 'rv:', '', $aversion[0] ) );
1358
+ $this->setBrowser( $this->BROWSER_MOZILLA );
1359
+ return true;
1360
+ } elseif ( stripos( $this->_agent, 'mozilla' ) !== false && preg_match( '/mozilla\/([^ ]*)/i', $this->_agent, $matches ) && stripos( $this->_agent, 'netscape' ) === false ) {
1361
+ $this->setVersion( $matches[1] );
1362
+ $this->setBrowser( $this->BROWSER_MOZILLA );
1363
+ return true;
1364
+ }
1365
+ return false;
1366
+ }
1367
+
1368
+ /**
1369
+ * Determine if the browser is Lynx or not (last updated 1.7)
1370
+ *
1371
+ * @return boolean True if the browser is Lynx otherwise false
1372
+ */
1373
+ function checkBrowserLynx() {
1374
+ if ( stripos( $this->_agent, 'lynx' ) !== false ) {
1375
+ $aresult = explode( '/', stristr( $this->_agent, 'Lynx' ) );
1376
+ $aversion = explode( ' ', ( isset( $aresult[1] ) ? $aresult[1] : '' ) );
1377
+ $this->setVersion( $aversion[0] );
1378
+ $this->setBrowser( $this->BROWSER_LYNX );
1379
+ return true;
1380
+ }
1381
+ return false;
1382
+ }
1383
+
1384
+ /**
1385
+ * Determine if the browser is Amaya or not (last updated 1.7)
1386
+ *
1387
+ * @return boolean True if the browser is Amaya otherwise false
1388
+ */
1389
+ function checkBrowserAmaya() {
1390
+ if ( stripos( $this->_agent, 'amaya' ) !== false ) {
1391
+ $aresult = explode( '/', stristr( $this->_agent, 'Amaya' ) );
1392
+ $aversion = explode( ' ', $aresult[1] );
1393
+ $this->setVersion( $aversion[0] );
1394
+ $this->setBrowser( $this->BROWSER_AMAYA );
1395
+ return true;
1396
+ }
1397
+ return false;
1398
+ }
1399
+
1400
+ /**
1401
+ * Determine if the browser is Safari or not (last updated 1.7)
1402
+ *
1403
+ * @return boolean True if the browser is Safari otherwise false
1404
+ */
1405
+ function checkBrowserSafari() {
1406
+ if ( stripos( $this->_agent, 'Safari' ) !== false && stripos( $this->_agent, 'iPhone' ) === false && stripos( $this->_agent, 'iPod' ) === false ) {
1407
+ $aresult = explode( '/', stristr( $this->_agent, 'Version' ) );
1408
+ if ( isset( $aresult[1] ) ) {
1409
+ $aversion = explode( ' ', $aresult[1] );
1410
+ $this->setVersion( $aversion[0] );
1411
+ } else {
1412
+ $this->setVersion( $this->VERSION_UNKNOWN );
1413
+ }
1414
+ $this->setBrowser( $this->BROWSER_SAFARI );
1415
+ return true;
1416
+ }
1417
+ return false;
1418
+ }
1419
+
1420
+ /**
1421
+ * Determine if the browser is iPhone or not (last updated 1.7)
1422
+ *
1423
+ * @return boolean True if the browser is iPhone otherwise false
1424
+ */
1425
+ function checkBrowseriPhone() {
1426
+ if ( stripos( $this->_agent, 'iPhone' ) !== false ) {
1427
+ $aresult = explode( '/', stristr( $this->_agent, 'Version' ) );
1428
+ if ( isset( $aresult[1] ) ) {
1429
+ $aversion = explode( ' ', $aresult[1] );
1430
+ $this->setVersion( $aversion[0] );
1431
+ } else {
1432
+ $this->setVersion( $this->VERSION_UNKNOWN );
1433
+ }
1434
+ $this->setMobile( true );
1435
+ $this->setBrowser( $this->BROWSER_IPHONE );
1436
+ return true;
1437
+ }
1438
+ return false;
1439
+ }
1440
+
1441
+ /**
1442
+ * Determine if the browser is iPod or not (last updated 1.7)
1443
+ *
1444
+ * @return boolean True if the browser is iPod otherwise false
1445
+ */
1446
+ function checkBrowseriPad() {
1447
+ if ( stripos( $this->_agent, 'iPad' ) !== false ) {
1448
+ $aresult = explode( '/', stristr( $this->_agent, 'Version' ) );
1449
+ if ( isset( $aresult[1] ) ) {
1450
+ $aversion = explode( ' ', $aresult[1] );
1451
+ $this->setVersion( $aversion[0] );
1452
+ } else {
1453
+ $this->setVersion( $this->VERSION_UNKNOWN );
1454
+ }
1455
+ $this->setMobile( true );
1456
+ $this->setBrowser( $this->BROWSER_IPAD );
1457
+ return true;
1458
+ }
1459
+ return false;
1460
+ }
1461
+
1462
+ /**
1463
+ * Determine if the browser is iPod or not (last updated 1.7)
1464
+ *
1465
+ * @return boolean True if the browser is iPod otherwise false
1466
+ */
1467
+ function checkBrowseriPod() {
1468
+ if ( stripos( $this->_agent, 'iPod' ) !== false ) {
1469
+ $aresult = explode( '/', stristr( $this->_agent, 'Version' ) );
1470
+ if ( isset( $aresult[1] ) ) {
1471
+ $aversion = explode( ' ', $aresult[1] );
1472
+ $this->setVersion( $aversion[0] );
1473
+ } else {
1474
+ $this->setVersion( $this->VERSION_UNKNOWN );
1475
+ }
1476
+ $this->setMobile( true );
1477
+ $this->setBrowser( $this->BROWSER_IPOD );
1478
+ return true;
1479
+ }
1480
+ return false;
1481
+ }
1482
+
1483
+ /**
1484
+ * Determine if the browser is Android or not (last updated 1.7)
1485
+ *
1486
+ * @return boolean True if the browser is Android otherwise false
1487
+ */
1488
+ function checkBrowserAndroid() {
1489
+ if ( stripos( $this->_agent, 'Android' ) !== false ) {
1490
+ $aresult = explode( ' ', stristr( $this->_agent, 'Android' ) );
1491
+ if ( isset( $aresult[1] ) ) {
1492
+ $aversion = explode( ' ', $aresult[1] );
1493
+ $this->setVersion( $aversion[0] );
1494
+ } else {
1495
+ $this->setVersion( $this->VERSION_UNKNOWN );
1496
+ }
1497
+ $this->setMobile( true );
1498
+ $this->setBrowser( $this->BROWSER_ANDROID );
1499
+ return true;
1500
+ }
1501
+ return false;
1502
+ }
1503
+
1504
+ /**
1505
+ * Determine the user's platform (last updated 1.7)
1506
+ */
1507
+ function checkPlatform() {
1508
+ if ( stripos( $this->_agent, 'windows' ) !== false ) {
1509
+ $this->_platform = $this->PLATFORM_WINDOWS;
1510
+ } elseif ( stripos( $this->_agent, 'iPad' ) !== false ) {
1511
+ $this->_platform = $this->PLATFORM_IPAD;
1512
+ } elseif ( stripos( $this->_agent, 'iPod' ) !== false ) {
1513
+ $this->_platform = $this->PLATFORM_IPOD;
1514
+ } elseif ( stripos( $this->_agent, 'iPhone' ) !== false ) {
1515
+ $this->_platform = $this->PLATFORM_IPHONE;
1516
+ } elseif ( stripos( $this->_agent, 'mac' ) !== false ) {
1517
+ $this->_platform = $this->PLATFORM_APPLE;
1518
+ } elseif ( stripos( $this->_agent, 'android' ) !== false ) {
1519
+ $this->_platform = $this->PLATFORM_ANDROID;
1520
+ } elseif ( stripos( $this->_agent, 'linux' ) !== false ) {
1521
+ $this->_platform = $this->PLATFORM_LINUX;
1522
+ } elseif ( stripos( $this->_agent, 'Nokia' ) !== false ) {
1523
+ $this->_platform = $this->PLATFORM_NOKIA;
1524
+ } elseif ( stripos( $this->_agent, 'BlackBerry' ) !== false ) {
1525
+ $this->_platform = $this->PLATFORM_BLACKBERRY;
1526
+ } elseif ( stripos( $this->_agent, 'FreeBSD' ) !== false ) {
1527
+ $this->_platform = $this->PLATFORM_FREEBSD;
1528
+ } elseif ( stripos( $this->_agent, 'OpenBSD' ) !== false ) {
1529
+ $this->_platform = $this->PLATFORM_OPENBSD;
1530
+ } elseif ( stripos( $this->_agent, 'NetBSD' ) !== false ) {
1531
+ $this->_platform = $this->PLATFORM_NETBSD;
1532
+ } elseif ( stripos( $this->_agent, 'OpenSolaris' ) !== false ) {
1533
+ $this->_platform = $this->PLATFORM_OPENSOLARIS;
1534
+ } elseif ( stripos( $this->_agent, 'SunOS' ) !== false ) {
1535
+ $this->_platform = $this->PLATFORM_SUNOS;
1536
+ } elseif ( stripos( $this->_agent, 'OS\/2' ) !== false ) {
1537
+ $this->_platform = $this->PLATFORM_OS2;
1538
+ } elseif ( stripos( $this->_agent, 'BeOS' ) !== false ) {
1539
+ $this->_platform = $this->PLATFORM_BEOS;
1540
+ } elseif ( stripos( $this->_agent, 'win' ) !== false ) {
1541
+ $this->_platform = $this->PLATFORM_WINDOWS;
1542
+ }
1543
+
1544
+ }
1545
+ }
{sdk → includes}/freemius/LICENSE.txt RENAMED
File without changes
{sdk → includes}/freemius/README.md RENAMED
File without changes
{sdk → includes}/freemius/assets/css/admin/account.css RENAMED
File without changes
{sdk → includes}/freemius/assets/css/admin/add-ons.css RENAMED
File without changes
{sdk → includes}/freemius/assets/css/admin/affiliation.css RENAMED
File without changes
{sdk → includes}/freemius/assets/css/admin/checkout.css RENAMED
File without changes
{sdk → includes}/freemius/assets/css/admin/common.css RENAMED
File without changes
{sdk → includes}/freemius/assets/css/admin/connect.css RENAMED
File without changes
{sdk → includes}/freemius/assets/css/admin/deactivation-feedback.css RENAMED
File without changes
{sdk → includes}/freemius/assets/css/admin/debug.css RENAMED
File without changes
{sdk → includes}/freemius/assets/css/admin/dialog-boxes.css RENAMED
File without changes
{sdk → includes}/freemius/assets/css/admin/gdpr-optin-notice.css RENAMED
File without changes
{sdk → includes}/freemius/assets/css/admin/index.php RENAMED
File without changes
{sdk → includes}/freemius/assets/css/admin/license-activation.css RENAMED
File without changes
{sdk → includes}/freemius/assets/css/customizer.css RENAMED
File without changes
{sdk → includes}/freemius/assets/css/index.php RENAMED
File without changes
{sdk → includes}/freemius/assets/img/index.php RENAMED
File without changes
{sdk → includes}/freemius/assets/img/plugin-icon.png RENAMED
File without changes
{sdk → includes}/freemius/assets/img/theme-icon.png RENAMED
File without changes
{sdk → includes}/freemius/assets/img/wp-security-audit-log.png RENAMED
File without changes
{sdk → includes}/freemius/assets/index.php RENAMED
File without changes
{sdk → includes}/freemius/assets/js/index.php RENAMED
File without changes
{sdk → includes}/freemius/assets/js/nojquery.ba-postmessage.js RENAMED
File without changes
{sdk → includes}/freemius/assets/js/nojquery.ba-postmessage.min.js RENAMED
File without changes
{sdk → includes}/freemius/assets/js/postmessage.js RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/_colors.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/_functions.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/_load.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/_mixins.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/_start.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/_vars.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/admin/_ajax-loader.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/admin/_auto-install.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/admin/_deactivation-feedback.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/admin/_gdpr-consent.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/admin/_license-activation.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/admin/_license-key-resend.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/admin/_modal-common.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/admin/_multisite-options.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/admin/_themes.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/admin/_tooltip.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/admin/account.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/admin/add-ons.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/admin/affiliation.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/admin/checkout.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/admin/common.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/admin/connect.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/admin/debug.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/admin/dialog-boxes.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/admin/gdpr-optin-notice.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/admin/index.php RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/customizer.scss RENAMED
File without changes
{sdk → includes}/freemius/assets/scss/index.php RENAMED
File without changes
{sdk → includes}/freemius/config.php RENAMED
File without changes
{sdk → includes}/freemius/includes/class-freemius-abstract.php RENAMED
File without changes
{sdk → includes}/freemius/includes/class-freemius.php RENAMED
File without changes
{sdk → includes}/freemius/includes/class-fs-admin-notices.php RENAMED
File without changes
{sdk → includes}/freemius/includes/class-fs-api.php RENAMED
File without changes
{sdk → includes}/freemius/includes/class-fs-logger.php RENAMED
File without changes
{sdk → includes}/freemius/includes/class-fs-options.php RENAMED
File without changes
{sdk → includes}/freemius/includes/class-fs-plugin-updater.php RENAMED
File without changes
{sdk → includes}/freemius/includes/class-fs-security.php RENAMED
File without changes
{sdk → includes}/freemius/includes/class-fs-storage.php RENAMED
File without changes
{sdk → includes}/freemius/includes/class-fs-user-lock.php RENAMED
File without changes
{sdk → includes}/freemius/includes/customizer/class-fs-customizer-support-section.php RENAMED
File without changes
{sdk → includes}/freemius/includes/customizer/class-fs-customizer-upsell-control.php RENAMED
File without changes
{sdk → includes}/freemius/includes/customizer/index.php RENAMED
File without changes
{sdk → includes}/freemius/includes/debug/class-fs-debug-bar-panel.php RENAMED
File without changes
{sdk → includes}/freemius/includes/debug/debug-bar-start.php RENAMED
File without changes
{sdk → includes}/freemius/includes/debug/index.php RENAMED
File without changes
{sdk → includes}/freemius/includes/entities/class-fs-affiliate-terms.php RENAMED
File without changes
{sdk → includes}/freemius/includes/entities/class-fs-affiliate.php RENAMED
File without changes
{sdk → includes}/freemius/includes/entities/class-fs-billing.php RENAMED
File without changes
{sdk → includes}/freemius/includes/entities/class-fs-entity.php RENAMED
File without changes
{sdk → includes}/freemius/includes/entities/class-fs-payment.php RENAMED
File without changes
{sdk → includes}/freemius/includes/entities/class-fs-plugin-info.php RENAMED
File without changes
{sdk → includes}/freemius/includes/entities/class-fs-plugin-license.php RENAMED
File without changes
{sdk → includes}/freemius/includes/entities/class-fs-plugin-plan.php RENAMED
File without changes
{sdk → includes}/freemius/includes/entities/class-fs-plugin-tag.php RENAMED
File without changes
{sdk → includes}/freemius/includes/entities/class-fs-plugin.php RENAMED
File without changes
{sdk → includes}/freemius/includes/entities/class-fs-pricing.php RENAMED
File without changes
{sdk → includes}/freemius/includes/entities/class-fs-scope-entity.php RENAMED
File without changes
{sdk → includes}/freemius/includes/entities/class-fs-site.php RENAMED
File without changes
{sdk → includes}/freemius/includes/entities/class-fs-subscription.php RENAMED
File without changes
{sdk → includes}/freemius/includes/entities/class-fs-user.php RENAMED
File without changes
{sdk → includes}/freemius/includes/entities/index.php RENAMED
File without changes
{sdk → includes}/freemius/includes/fs-core-functions.php RENAMED
File without changes
{sdk → includes}/freemius/includes/fs-essential-functions.php RENAMED
File without changes
{sdk → includes}/freemius/includes/fs-plugin-info-dialog.php RENAMED
File without changes
{sdk → includes}/freemius/includes/i18n.php RENAMED
File without changes
{sdk → includes}/freemius/includes/index.php RENAMED
File without changes
{sdk → includes}/freemius/includes/l10n.php RENAMED
File without changes
{sdk → includes}/freemius/includes/managers/class-fs-admin-menu-manager.php RENAMED
File without changes
{sdk → includes}/freemius/includes/managers/class-fs-admin-notice-manager.php RENAMED
File without changes
{sdk → includes}/freemius/includes/managers/class-fs-cache-manager.php RENAMED
File without changes
{sdk → includes}/freemius/includes/managers/class-fs-gdpr-manager.php RENAMED
File without changes
{sdk → includes}/freemius/includes/managers/class-fs-key-value-storage.php RENAMED
File without changes
{sdk → includes}/freemius/includes/managers/class-fs-license-manager.php RENAMED
File without changes
{sdk → includes}/freemius/includes/managers/class-fs-option-manager.php RENAMED
File without changes
{sdk → includes}/freemius/includes/managers/class-fs-plan-manager.php RENAMED
File without changes
{sdk → includes}/freemius/includes/managers/class-fs-plugin-manager.php RENAMED
File without changes
{sdk → includes}/freemius/includes/managers/index.php RENAMED
File without changes
{sdk → includes}/freemius/includes/sdk/Exceptions/ArgumentNotExistException.php RENAMED
File without changes
{sdk → includes}/freemius/includes/sdk/Exceptions/EmptyArgumentException.php RENAMED
File without changes
{sdk → includes}/freemius/includes/sdk/Exceptions/Exception.php RENAMED
File without changes
{sdk → includes}/freemius/includes/sdk/Exceptions/InvalidArgumentException.php RENAMED
File without changes
{sdk → includes}/freemius/includes/sdk/Exceptions/OAuthException.php RENAMED
File without changes
{sdk → includes}/freemius/includes/sdk/Exceptions/index.php RENAMED
File without changes
{sdk → includes}/freemius/includes/sdk/FreemiusBase.php RENAMED
File without changes
{sdk → includes}/freemius/includes/sdk/FreemiusWordPress.php RENAMED
File without changes
{sdk → includes}/freemius/includes/sdk/LICENSE.txt RENAMED
File without changes
{sdk → includes}/freemius/includes/sdk/index.php RENAMED
File without changes
{sdk → includes}/freemius/includes/supplements/fs-essential-functions-1.1.7.1.php RENAMED
File without changes
{sdk → includes}/freemius/includes/supplements/index.php RENAMED
File without changes
{sdk → includes}/freemius/index.php RENAMED
File without changes
{sdk → includes}/freemius/languages/freemius-da_DK.mo RENAMED
File without changes
{sdk → includes}/freemius/languages/freemius-da_DK.po RENAMED
File without changes
{sdk → includes}/freemius/languages/freemius-en.mo RENAMED
File without changes
{sdk → includes}/freemius/languages/freemius-en.po RENAMED
File without changes
{sdk → includes}/freemius/languages/freemius-es_ES.mo RENAMED
File without changes
{sdk → includes}/freemius/languages/freemius-es_ES.po RENAMED
File without changes
{sdk → includes}/freemius/languages/freemius-fr_FR.mo RENAMED
File without changes
{sdk → includes}/freemius/languages/freemius-fr_FR.po RENAMED
File without changes
{sdk → includes}/freemius/languages/freemius-he_IL.mo RENAMED
File without changes
{sdk → includes}/freemius/languages/freemius-he_IL.po RENAMED
File without changes
{sdk → includes}/freemius/languages/freemius-it_IT.mo RENAMED
File without changes
{sdk → includes}/freemius/languages/freemius-it_IT.po RENAMED
File without changes
{sdk → includes}/freemius/languages/freemius-ja_JP.mo RENAMED
File without changes
{sdk → includes}/freemius/languages/freemius-ja_JP.po RENAMED
File without changes
{sdk → includes}/freemius/languages/freemius-nl_NL.mo RENAMED
File without changes
{sdk → includes}/freemius/languages/freemius-nl_NL.po RENAMED
File without changes
{sdk → includes}/freemius/languages/freemius-ru_RU.mo RENAMED
File without changes
{sdk → includes}/freemius/languages/freemius-ru_RU.po RENAMED
File without changes
{sdk → includes}/freemius/languages/freemius.pot RENAMED
File without changes
{sdk → includes}/freemius/languages/index.php RENAMED
File without changes
{sdk → includes}/freemius/require.php RENAMED
File without changes
{sdk → includes}/freemius/start.php RENAMED
File without changes
{sdk → includes}/freemius/templates/account.php RENAMED
File without changes
{sdk → includes}/freemius/templates/account/billing.php RENAMED
File without changes
{sdk → includes}/freemius/templates/account/index.php RENAMED
File without changes
{sdk → includes}/freemius/templates/account/partials/activate-license-button.php RENAMED
File without changes
{sdk → includes}/freemius/templates/account/partials/addon.php RENAMED
File without changes
{sdk → includes}/freemius/templates/account/partials/deactivate-license-button.php RENAMED
File without changes
{sdk → includes}/freemius/templates/account/partials/index.php RENAMED
File without changes
{sdk → includes}/freemius/templates/account/partials/site.php RENAMED
File without changes
{sdk → includes}/freemius/templates/account/payments.php RENAMED
File without changes
{sdk → includes}/freemius/templates/add-ons.php RENAMED
File without changes
{sdk → includes}/freemius/templates/add-trial-to-pricing.php RENAMED
File without changes
{sdk → includes}/freemius/templates/admin-notice.php RENAMED
File without changes
{sdk → includes}/freemius/templates/ajax-loader.php RENAMED
File without changes
{sdk → includes}/freemius/templates/auto-installation.php RENAMED
File without changes
{sdk → includes}/freemius/templates/checkout.php RENAMED
File without changes
{sdk → includes}/freemius/templates/connect.php RENAMED
File without changes
{sdk → includes}/freemius/templates/contact.php RENAMED
File without changes
{sdk → includes}/freemius/templates/debug.php RENAMED
File without changes
{sdk → includes}/freemius/templates/debug/api-calls.php RENAMED
File without changes
{sdk → includes}/freemius/templates/debug/index.php RENAMED
File without changes
{sdk → includes}/freemius/templates/debug/logger.php RENAMED
File without changes
{sdk → includes}/freemius/templates/debug/plugins-themes-sync.php RENAMED
File without changes
{sdk → includes}/freemius/templates/debug/scheduled-crons.php RENAMED
File without changes
{sdk → includes}/freemius/templates/email.php RENAMED
File without changes
{sdk → includes}/freemius/templates/firewall-issues-js.php RENAMED
File without changes
{sdk → includes}/freemius/templates/forms/affiliation.php RENAMED
File without changes
{sdk → includes}/freemius/templates/forms/deactivation/contact.php RENAMED
File without changes
{sdk → includes}/freemius/templates/forms/deactivation/form.php RENAMED
File without changes
{sdk → includes}/freemius/templates/forms/deactivation/index.php RENAMED
File without changes
{sdk → includes}/freemius/templates/forms/deactivation/retry-skip.php RENAMED
File without changes
{sdk → includes}/freemius/templates/forms/index.php RENAMED
File without changes
{sdk → includes}/freemius/templates/forms/license-activation.php RENAMED
File without changes
{sdk → includes}/freemius/templates/forms/optout.php RENAMED
File without changes
{sdk → includes}/freemius/templates/forms/premium-versions-upgrade-handler.php RENAMED
File without changes
{sdk → includes}/freemius/templates/forms/premium-versions-upgrade-metadata.php RENAMED
File without changes
{sdk → includes}/freemius/templates/forms/resend-key.php RENAMED
File without changes
{sdk → includes}/freemius/templates/forms/trial-start.php RENAMED
File without changes
{sdk → includes}/freemius/templates/gdpr-optin-js.php RENAMED
File without changes
{sdk → includes}/freemius/templates/index.php RENAMED
File without changes
{sdk → includes}/freemius/templates/js/index.php RENAMED
File without changes
{sdk → includes}/freemius/templates/js/jquery.content-change.php RENAMED
File without changes
{sdk → includes}/freemius/templates/js/open-license-activation.php RENAMED
File without changes
{sdk → includes}/freemius/templates/js/style-premium-theme.php RENAMED
File without changes
{sdk → includes}/freemius/templates/partials/network-activation.php RENAMED
File without changes
{sdk → includes}/freemius/templates/plugin-icon.php RENAMED
File without changes
{sdk → includes}/freemius/templates/plugin-info/description.php RENAMED
File without changes
{sdk → includes}/freemius/templates/plugin-info/features.php RENAMED
File without changes
{sdk → includes}/freemius/templates/plugin-info/index.php RENAMED
File without changes
{sdk → includes}/freemius/templates/plugin-info/screenshots.php RENAMED
File without changes
{sdk → includes}/freemius/templates/powered-by.php RENAMED
File without changes
{sdk → includes}/freemius/templates/pricing.php RENAMED
File without changes
{sdk → includes}/freemius/templates/secure-https-header.php RENAMED
File without changes
{sdk → includes}/freemius/templates/sticky-admin-notice-js.php RENAMED
File without changes
{sdk → includes}/freemius/templates/tabs-capture-js.php RENAMED
File without changes
{sdk → includes}/freemius/templates/tabs.php RENAMED
File without changes
{sdk → includes}/wsal-freemius.php RENAMED
File without changes
js/auditlog.js CHANGED
@@ -86,6 +86,8 @@ function WsalAuditLogInit(_WsalData) {
86
  action: 'AjaxRefresh',
87
  logcount: WsalTkn
88
  }, function (data) {
 
 
89
  WsalAjx = null;
90
  if (data && data !== 'false') {
91
  WsalTkn = data;
@@ -344,3 +346,61 @@ function wsal_freemius_opt_in( element ) {
344
  }
345
  } );
346
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  action: 'AjaxRefresh',
87
  logcount: WsalTkn
88
  }, function (data) {
89
+ data = data.toString();
90
+ data = data.trim();
91
  WsalAjx = null;
92
  if (data && data !== 'false') {
93
  WsalTkn = data;
346
  }
347
  } );
348
  }
349
+
350
+ /**
351
+ * Onclick event handler to exclude URL.
352
+ *
353
+ * @param {string} element - Current element.
354
+ * @since 3.2.2
355
+ */
356
+ function wsal_exclude_url(element) {
357
+ var exclude_nonce = jQuery( element ).data( 'exclude-url-nonce' ); // Nonce.
358
+ var exclude_url = jQuery( element ).data( 'exclude-url' ); // Nonce.
359
+
360
+ if ( exclude_url ) {
361
+ jQuery.ajax( {
362
+ type: 'POST',
363
+ url: ajaxurl,
364
+ async: true,
365
+ data: {
366
+ action: 'wsal_exclude_url',
367
+ nonce: exclude_nonce,
368
+ url: exclude_url
369
+ },
370
+ success: function( data ) {
371
+ var notice = jQuery( '<div class="updated" data-notice-name="notifications-extension"></div>' ).html( data );
372
+ jQuery( 'h2:first' ).after( notice );
373
+ },
374
+ error: function( xhr, textStatus, error ) {
375
+ console.log( xhr.statusText );
376
+ console.log( textStatus );
377
+ console.log( error );
378
+ }
379
+ } );
380
+ }
381
+ }
382
+
383
+ jQuery( document ).ready( function() {
384
+ /**
385
+ * Dismiss DB disconnect issue notice.
386
+ */
387
+ jQuery( '#wsal-notice-connect-issue' ).click( function() {
388
+ jQuery.ajax( {
389
+ type: 'POST',
390
+ url: ajaxurl,
391
+ async: true,
392
+ data: {
393
+ action: 'wsal_dismiss_notice_disconnect',
394
+ nonce: jQuery( '#wsal-dismiss-notice-disconnect' ).val()
395
+ },
396
+ success: function( data ) {
397
+ console.log( data );
398
+ },
399
+ error: function( xhr, textStatus, error ) {
400
+ console.log( xhr.statusText );
401
+ console.log( textStatus );
402
+ console.log( error );
403
+ }
404
+ } );
405
+ } );
406
+ } );
js/settings.js CHANGED
@@ -15,32 +15,38 @@ jQuery(document).ready(function(){
15
  }
16
  } );
17
 
18
- jQuery( '#ViewerQueryAdd, #EditorQueryAdd, #ExRoleQueryAdd, #ExUserQueryAdd, #CustomQueryAdd, #IpAddrQueryAdd, #ExCPTsQueryAdd' ).click(function(){
19
- var type = jQuery(this).attr('id').substr(0, 6);
20
- var value = jQuery.trim(jQuery('#'+type+'QueryBox').val());
21
- var existing = jQuery('#'+type+'List input').filter(function() { return this.value === value; });
22
 
23
  if( ! value || existing.length ) return; // if value is empty or already used, stop here
24
 
25
- jQuery('#'+type+'QueryBox, #'+type+'QueryAdd').attr('disabled', true);
26
- jQuery.post(jQuery('#ajaxurl').val(), {action: 'AjaxCheckSecurityToken', token: value}, function(data){
27
- jQuery('#'+type+'QueryBox, #'+type+'QueryAdd').attr('disabled', false);
28
- if (type != 'Custom' && type != 'IpAddr') {
29
- if(data === 'other') {
30
- alert('The specified token is not a user nor a role!');
31
- jQuery('#'+type+'QueryBox').val('');
 
 
 
 
 
 
32
  return;
33
  }
34
  }
35
- jQuery('#'+type+'QueryBox').val('');
36
- jQuery('#'+type+'List').append(jQuery('<span class="sectoken-'+data+'"/>').text(value).append(
37
- jQuery('<input type="hidden" name="'+type+'s[]"/>').val(value),
38
- jQuery('<a href="javascript:;" title="Remove">&times;</a>').click(RemoveSecToken)
39
- ));
40
- });
41
  });
42
 
43
- jQuery( '#ViewerList>span>a, #EditorList>span>a, #ExRoleList>span>a, #ExUserList>span>a, #CustomList>span>a, #IpAddrList>span>a, #ExCPTsList>span>a' ).click( RemoveSecToken );
44
 
45
  jQuery('#RestrictAdmins').change(function(){
46
  var user = jQuery('#RestrictAdminsDefaultUser').val();
@@ -76,7 +82,6 @@ jQuery(document).ready(function(){
76
  });
77
 
78
  var cptsUrl = ajaxurl + "?action=AjaxGetAllCPT&wsal_nonce=" + wsal_data.wp_nonce;
79
- console.log( cptsUrl );
80
  jQuery( '#ExCPTsQueryBox' ).autocomplete( {
81
  source: cptsUrl,
82
  minLength: 1,
@@ -108,8 +113,12 @@ jQuery(document).ready(function(){
108
  jQuery( '#wsal_add_file_type_name' ),
109
  jQuery( '#wsal_add_file_type' ),
110
  jQuery( '#wsal_remove_exception_file_type' ),
 
 
 
111
  jQuery( '#wsal_files input[type=checkbox]' ),
112
  jQuery( '#wsal_files_types input[type=checkbox]' ),
 
113
  ];
114
 
115
  // Update settings of file changes on page load.
@@ -160,6 +169,11 @@ jQuery(document).ready(function(){
160
  }
161
  }
162
 
 
 
 
 
 
163
  // Add file to scan file exception list.
164
  jQuery( '#wsal_add_file' ).click( function() {
165
  wsal_add_scan_exception( 'file' );
@@ -182,18 +196,30 @@ jQuery(document).ready(function(){
182
  var setting_container = jQuery( '#wsal_files' );
183
  var setting_nonce = jQuery( '#wsal_scan_exception_file' ).val();
184
  var setting_error = jQuery( '#wsal_file_name_error' );
 
 
 
185
  } else if ( type === 'extension' ) {
186
  var setting_input = jQuery( '#wsal_add_file_type_name' );
187
  var setting_value = setting_input.val();
188
  var setting_container = jQuery( '#wsal_files_types' );
189
  var setting_nonce = jQuery( '#wsal_scan_exception_file_type' ).val();
190
  var setting_error = jQuery( '#wsal_file_type_error' );
 
 
 
 
 
 
 
 
 
 
 
 
191
  }
192
  setting_error.addClass( 'hide' );
193
 
194
- // Validate file name.
195
- var pattern = /^\s*[a-z-._\d,\s]+\s*$/i;
196
-
197
  if ( setting_value.match( pattern ) ) {
198
  // Ajax request to add file to scan file exception list.
199
  jQuery.ajax( {
@@ -241,10 +267,17 @@ jQuery(document).ready(function(){
241
  alert( 'Filename cannot be added because it contains invalid characters.' );
242
  } else if ( type === 'extension' ) {
243
  alert( 'File extension cannot be added because it contains invalid characters.' );
 
 
244
  }
245
  }
246
  }
247
 
 
 
 
 
 
248
  // Remove files from scan file exception list.
249
  jQuery( '#wsal_remove_exception_file' ).click( function() {
250
  wsal_remove_scan_exception( 'file' );
@@ -263,25 +296,20 @@ jQuery(document).ready(function(){
263
  function wsal_remove_scan_exception( type ) {
264
  if ( type === 'file' ) {
265
  var setting_values = jQuery( '#wsal_files input[type=checkbox]' ); // Get files.
266
- var removed_values = [];
267
  var setting_nonce = jQuery( '#wsal_scan_remove_exception_file' ).val(); // Nonce.
268
-
269
- // Make array of files which are checked.
270
- for ( var index = 0; index < setting_values.length; index++ ) {
271
- if ( jQuery( setting_values[ index ] ).is( ':checked' ) ) {
272
- removed_values.push( jQuery( setting_values[ index ] ).val() );
273
- }
274
- }
275
  } else if ( type === 'extension' ) {
276
  var setting_values = jQuery( '#wsal_files_types input[type=checkbox]' ); // Get files.
277
- var removed_values = [];
278
  var setting_nonce = jQuery( '#wsal_scan_remove_exception_file_type' ).val(); // Nonce.
 
 
 
 
279
 
280
- // Make array of files which are checked.
281
- for ( var index = 0; index < setting_values.length; index++ ) {
282
- if ( jQuery( setting_values[ index ] ).is( ':checked' ) ) {
283
- removed_values.push( jQuery( setting_values[ index ] ).val() );
284
- }
285
  }
286
  }
287
 
15
  }
16
  } );
17
 
18
+ jQuery( '#ViewerQueryAdd, #EditorQueryAdd, #ExRoleQueryAdd, #ExUserQueryAdd, #CustomQueryAdd, #IpAddrQueryAdd, #ExCPTsQueryAdd, #ExURLsQueryAdd' ).click(function(){
19
+ var type = jQuery(this).attr('id').substr(0, 6);
20
+ var value = jQuery.trim( jQuery( '#'+type+'QueryBox' ).val() );
21
+ var existing = jQuery('#'+type+'List input').filter( function() { return this.value === value; } );
22
 
23
  if( ! value || existing.length ) return; // if value is empty or already used, stop here
24
 
25
+ jQuery( '#'+type+'QueryBox, #'+type+'QueryAdd' ).attr('disabled', true);
26
+ jQuery.post( jQuery('#ajaxurl').val(), { action: 'AjaxCheckSecurityToken', token: value }, function(data) {
27
+ jQuery( '#'+type+'QueryBox, #'+type+'QueryAdd' ).attr('disabled', false);
28
+ if ( type === 'ExURLs') {
29
+ if ( data === 'other' ) {
30
+ alert( 'The specified token is not a valid URL!' );
31
+ jQuery( '#'+type+'QueryBox' ).val('');
32
+ return;
33
+ }
34
+ } else if ( type != 'Custom' && type != 'IpAddr' ) {
35
+ if ( data === 'other' ) {
36
+ alert( 'The specified token is not a user nor a role!' );
37
+ jQuery( '#'+type+'QueryBox' ).val('');
38
  return;
39
  }
40
  }
41
+ jQuery( '#'+type+'QueryBox' ).val('');
42
+ jQuery( '#'+type+'List' ).append( jQuery( '<span class="sectoken-'+data+'"/>' ).text(value).append(
43
+ jQuery( '<input type="hidden" name="'+type+'s[]"/>' ).val(value),
44
+ jQuery( '<a href="javascript:;" title="Remove">&times;</a>' ).click(RemoveSecToken)
45
+ ) );
46
+ } );
47
  });
48
 
49
+ jQuery( '#ViewerList>span>a, #EditorList>span>a, #ExRoleList>span>a, #ExUserList>span>a, #CustomList>span>a, #IpAddrList>span>a, #ExCPTsList>span>a, #ExURLsList>span>a' ).click( RemoveSecToken );
50
 
51
  jQuery('#RestrictAdmins').change(function(){
52
  var user = jQuery('#RestrictAdminsDefaultUser').val();
82
  });
83
 
84
  var cptsUrl = ajaxurl + "?action=AjaxGetAllCPT&wsal_nonce=" + wsal_data.wp_nonce;
 
85
  jQuery( '#ExCPTsQueryBox' ).autocomplete( {
86
  source: cptsUrl,
87
  minLength: 1,
113
  jQuery( '#wsal_add_file_type_name' ),
114
  jQuery( '#wsal_add_file_type' ),
115
  jQuery( '#wsal_remove_exception_file_type' ),
116
+ jQuery( '#wsal_add_dir_name' ),
117
+ jQuery( '#wsal_add_dir' ),
118
+ jQuery( '#wsal_remove_exception_dir' ),
119
  jQuery( '#wsal_files input[type=checkbox]' ),
120
  jQuery( '#wsal_files_types input[type=checkbox]' ),
121
+ jQuery( '#wsal_dirs input[type=checkbox]' ),
122
  ];
123
 
124
  // Update settings of file changes on page load.
169
  }
170
  }
171
 
172
+ // Add directory to scan file exception list.
173
+ jQuery( '#wsal_add_dir' ).click( function() {
174
+ wsal_add_scan_exception( 'dir' );
175
+ } );
176
+
177
  // Add file to scan file exception list.
178
  jQuery( '#wsal_add_file' ).click( function() {
179
  wsal_add_scan_exception( 'file' );
196
  var setting_container = jQuery( '#wsal_files' );
197
  var setting_nonce = jQuery( '#wsal_scan_exception_file' ).val();
198
  var setting_error = jQuery( '#wsal_file_name_error' );
199
+
200
+ // Validate file name.
201
+ var pattern = /^\s*[a-z-._\d,\s]+\s*$/i;
202
  } else if ( type === 'extension' ) {
203
  var setting_input = jQuery( '#wsal_add_file_type_name' );
204
  var setting_value = setting_input.val();
205
  var setting_container = jQuery( '#wsal_files_types' );
206
  var setting_nonce = jQuery( '#wsal_scan_exception_file_type' ).val();
207
  var setting_error = jQuery( '#wsal_file_type_error' );
208
+
209
+ // Validate file name.
210
+ var pattern = /^\s*[a-z-._\d,\s]+\s*$/i;
211
+ } else if ( type === 'dir' ) {
212
+ var setting_input = jQuery( '#wsal_add_dir_name' );
213
+ var setting_value = setting_input.val();
214
+ var setting_container = jQuery( '#wsal_dirs' );
215
+ var setting_nonce = jQuery( '#wsal_scan_exception_dir' ).val();
216
+ var setting_error = jQuery( '#wsal_dir_error' );
217
+
218
+ // Validate file name.
219
+ var pattern = /^\s*[a-z-._\d,\s/]+\s*$/i;
220
  }
221
  setting_error.addClass( 'hide' );
222
 
 
 
 
223
  if ( setting_value.match( pattern ) ) {
224
  // Ajax request to add file to scan file exception list.
225
  jQuery.ajax( {
267
  alert( 'Filename cannot be added because it contains invalid characters.' );
268
  } else if ( type === 'extension' ) {
269
  alert( 'File extension cannot be added because it contains invalid characters.' );
270
+ } else if ( type === 'dir' ) {
271
+ alert( 'Directory cannot be added because it contains invalid characters.' );
272
  }
273
  }
274
  }
275
 
276
+ // Remove directories from scan file exception list.
277
+ jQuery( '#wsal_remove_exception_dir' ).click( function() {
278
+ wsal_remove_scan_exception( 'dir' );
279
+ } );
280
+
281
  // Remove files from scan file exception list.
282
  jQuery( '#wsal_remove_exception_file' ).click( function() {
283
  wsal_remove_scan_exception( 'file' );
296
  function wsal_remove_scan_exception( type ) {
297
  if ( type === 'file' ) {
298
  var setting_values = jQuery( '#wsal_files input[type=checkbox]' ); // Get files.
 
299
  var setting_nonce = jQuery( '#wsal_scan_remove_exception_file' ).val(); // Nonce.
 
 
 
 
 
 
 
300
  } else if ( type === 'extension' ) {
301
  var setting_values = jQuery( '#wsal_files_types input[type=checkbox]' ); // Get files.
 
302
  var setting_nonce = jQuery( '#wsal_scan_remove_exception_file_type' ).val(); // Nonce.
303
+ } else if ( type === 'dir' ) {
304
+ var setting_values = jQuery( '#wsal_dirs input[type=checkbox]' ); // Get files.
305
+ var setting_nonce = jQuery( '#wsal_scan_remove_exception_dir' ).val(); // Nonce.
306
+ }
307
 
308
+ // Make array of files which are checked.
309
+ var removed_values = [];
310
+ for ( var index = 0; index < setting_values.length; index++ ) {
311
+ if ( jQuery( setting_values[ index ] ).is( ':checked' ) ) {
312
+ removed_values.push( jQuery( setting_values[ index ] ).val() );
313
  }
314
  }
315
 
readme.txt CHANGED
@@ -5,8 +5,8 @@ License: GPLv3
5
  License URI: http://www.gnu.org/licenses/gpl.html
6
  Tags: wordpress security plugin, wordpress security audit log, audit log, event log wordpress, wordpress user tracking, wordpress activity log, wordpress audit, security event log, audit trail, wordpress security monitor, wordpress admin, wordpress admin monitoring, user activity, admin, multisite, dashboard, notification, wordpress monitoring, email notification, wordpress email alerts, tracking, user tracking, user activity report, wordpress audit trail
7
  Requires at least: 3.6
8
- Tested up to: 4.9.6
9
- Stable tag: 3.2.1
10
  Requires PHP: 5.4.43
11
 
12
  An easy to use and comprehensive monitoring & activity log solution that keeps a log of all changes & user activity on your WordPress site.
@@ -114,12 +114,12 @@ WP Security Audit Log plugin also has a number of features that make WordPress a
114
  * [Techwibe](https://www.techwibe.com/wp-security-audit-log-wordpress-plugin/)
115
  * [KevinMuldoon.com](https://www.kevinmuldoon.com/wp-security-audit-log-review/)
116
  * [Cloudways](https://www.cloudways.com/blog/monitor-wordpress-with-wp-security-audit-log-plugin/)
117
- * [ManageWP Plugins of the month](https://managewp.com/free-wordpress-plugins-june-2014)
118
  * [MyWPExpert](http://www.mywpexpert.com/wp-security-audit-log/)
119
  * [BlogVault](https://blogvault.net/wp-security-audit-log-plugin-review/)
120
  * [Firewall.cx](http://www.firewall.cx/general-topics-reviews/security-articles/1146-wordpress-audit-monitor-log-site-security-alerts.html)
121
  * [Design Wall](http://www.designwall.com/blog/10-wordpress-multisite-plugins-you-shouldnt-live-without/)
122
- * [Tourqe News](http://torquemag.io/5-awesome-wordpress-plugins-you-may-not-have-heard-of/)
123
  * [Shout Me Loud](http://www.shoutmeloud.com/how-to-monitor-user-activities-wordpress-dashboard.html)
124
  * [Monster Post](http://blog.templatemonster.com/2015/12/15/wp-security-audit-log-plugin-review/)
125
  * [The Darknet](http://www.darknet.org.uk/2015/10/wp-security-audit-log-a-complete-audit-log-plugin-for-wordpress/)
@@ -179,38 +179,35 @@ Please refer to our [Support & Documentation pages](https://www.wpsecurityauditl
179
 
180
  == Changelog ==
181
 
182
- = 3.2.1(2018-06-05) =
183
 
184
- * **Improvements**
185
- * Improved connectivity checks of archiving and mirroring external databases.
186
- * Updated external database connection SSL code to support PHP 5.4.
187
- * Renamed Alerts to Events - [More information on WordPress activity log events](https://www.wpsecurityauditlog.com/support-documentation/what-are-alerts-and-alert-ids-in-the-wordpress-activity-log/)
188
-
189
- = 3.2.0(2018-06-05) =
190
 
191
- Release notes: [WordPress file changes warnings & more in WP Security Audit Log 3.2](https://www.wpsecurityauditlog.com/releases/3-2-website-file-changes-logs/)
 
 
192
 
193
  * **New Features**
194
- * [File Integrity scans & WordPress file changes warnings in the activity log](https://www.wpsecurityauditlog.com/support-documentation/wordpress-files-changes-warning-activity-logs/).
195
- * Support for SSL / Client certificates for [activity log external database connections](https://www.wpsecurityauditlog.com/premium-features/database-integration-tools-wordpress-activity-log/) (including archiving and mirroring).
196
-
197
- * **New Activity Log Event IDs**
198
- * 6028 - A file on the website has been modified
199
- * 6029 - New file has been created on the website
200
- * 6030 - A file was deleted from your website
201
 
202
  * **Improvements**
203
- * Performance enhancement - storing table names in sentients so they are note retrieved every time they are required.
204
- * Improved the built-in WordPress email notifications for content.
205
- * Changed the Freemius opt-in / opt-out screen to non compulsory.
206
- * Updated WhatIsMyIpAddress.com link to HTTPS so traffic is now encrypted.
207
- * Added notification on new installs to point out to users where to find the [WordPress activity logs](https://www.wpsecurityauditlog.com/support-documentation/what-wordpress-audit-trail/).
208
- * Updated Freemius SDK (now GDPR compliant)
209
-
 
 
210
  * **Bug Fixes**
211
- * Fixed issue in which the archive / live activity log database was not being saved properly.
212
- * Fixed issue in WooCommerce activity log - Alert 2053 was being reported instead of 9001 when a new product is published.
213
- * Fixed issue in WooCommerce product SEO change - wrong event was being reported.
214
- * Fixed issue where sorting activity logs events by IP address which tripled the entries displayed in the log.
215
-
216
- Refer to the [WP Security Audit Log change log](https://www.wpsecurityauditlog.com/plugin-change-log/) page for the complete change log.
5
  License URI: http://www.gnu.org/licenses/gpl.html
6
  Tags: wordpress security plugin, wordpress security audit log, audit log, event log wordpress, wordpress user tracking, wordpress activity log, wordpress audit, security event log, audit trail, wordpress security monitor, wordpress admin, wordpress admin monitoring, user activity, admin, multisite, dashboard, notification, wordpress monitoring, email notification, wordpress email alerts, tracking, user tracking, user activity report, wordpress audit trail
7
  Requires at least: 3.6
8
+ Tested up to: 4.9.7
9
+ Stable tag: 3.2.2
10
  Requires PHP: 5.4.43
11
 
12
  An easy to use and comprehensive monitoring & activity log solution that keeps a log of all changes & user activity on your WordPress site.
114
  * [Techwibe](https://www.techwibe.com/wp-security-audit-log-wordpress-plugin/)
115
  * [KevinMuldoon.com](https://www.kevinmuldoon.com/wp-security-audit-log-review/)
116
  * [Cloudways](https://www.cloudways.com/blog/monitor-wordpress-with-wp-security-audit-log-plugin/)
117
+ * [Collective Ray](https://www.collectiveray.com/wp/plugins/wordpress-security-audit-log)
118
  * [MyWPExpert](http://www.mywpexpert.com/wp-security-audit-log/)
119
  * [BlogVault](https://blogvault.net/wp-security-audit-log-plugin-review/)
120
  * [Firewall.cx](http://www.firewall.cx/general-topics-reviews/security-articles/1146-wordpress-audit-monitor-log-site-security-alerts.html)
121
  * [Design Wall](http://www.designwall.com/blog/10-wordpress-multisite-plugins-you-shouldnt-live-without/)
122
+ * [Tidy Repo](https://tidyrepo.com/wp-security-audit-log-wordpress-activity-log/)
123
  * [Shout Me Loud](http://www.shoutmeloud.com/how-to-monitor-user-activities-wordpress-dashboard.html)
124
  * [Monster Post](http://blog.templatemonster.com/2015/12/15/wp-security-audit-log-plugin-review/)
125
  * [The Darknet](http://www.darknet.org.uk/2015/10/wp-security-audit-log-a-complete-audit-log-plugin-for-wordpress/)
179
 
180
  == Changelog ==
181
 
182
+ = 3.2.2(2018-07-17) =
183
 
184
+ Release Notes: [click here](https://www.wpsecurityauditlog.com/releases/3-2-2-mainwp-integration/)
 
 
 
 
 
185
 
186
+ * **New Events**
187
+ * Event ID 9072: User opened WooCommerce product in editor
188
+ * Event ID 9073: User viewed WooCommernce product
189
 
190
  * **New Features**
191
+ * Support for MainWP - plugin now keeps a log of changes done on websites from MainWP dashboard.
192
+ * Added new option to allow users to trial the premium edition for free.
193
+ * Added built-in email notifications for [WordPress file changes](https://www.wpsecurityauditlog.com/support-documentation/wordpress-files-changes-warning-activity-logs/).
194
+ * Buffer for external database to cater for slow connections.
195
+ * Retention settings for [WordPress activity logs archiving](https://www.wpsecurityauditlog.com/support-documentation/archive-alerts-wordpress-audit-trail/).
196
+ * New setting to exclude non-existing URLs so they are not reported in the logs.
197
+ * System info module that captures diagnostic data required by support.
198
 
199
  * **Improvements**
200
+ * Ability to exclude directories from the WordPress file integrity scanner.
201
+ * Increased file size limit to 5MB in the WordPress file integrity scanner.
202
+ * Monitoring sensors now only loaded if source being monitored is active / installed (performance enhancement)
203
+ * Views will not be loaded unless accessed (performance enhancement)
204
+ * Updated 404 detection sensor to use $wp_query (fallback to $_SERVER global array)
205
+ * New setting to exclude the logging of automated changes to WooCommerce products' stock.
206
+ * Sub sites admins on multisite can now see who is logged in to the websites they administer.
207
+ * Updated exclusion settings to allow users to exclude any post type from the logs.
208
+
209
  * **Bug Fixes**
210
+ * Added a check on post type value to handle an unhandled error.
211
+ * Updated Search filters to handle role names and role slugs (e.g. shop-manager and shop manager).
212
+ * Fixed issue in which database selection (archive or live DB) was not stored properly.
213
+ * Fixed issue where audit log viewer was auto refreshing to page one automatically when browsing other pages.
 
 
sdk/freemius/templates/all-admin-notice.php DELETED
@@ -1,39 +0,0 @@
1
- <?php
2
- /**
3
- * @package Freemius
4
- * @copyright Copyright (c) 2015, Freemius, Inc.
5
- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
6
- * @since 1.0.3
7
- */
8
-
9
- if ( ! defined( 'ABSPATH' ) ) {
10
- exit;
11
- }
12
-
13
- /**
14
- * @var array $VARS
15
- */
16
- ?>
17
- <div class="<?php
18
- switch ($VARS['type']) {
19
- case 'error':
20
- echo 'error form-invalid';
21
- break;
22
- case 'update-nag':
23
- echo 'update-nag ';
24
- break;
25
- case 'update':
26
- case 'success':
27
- default:
28
- echo 'updated success';
29
- break;
30
- }
31
- ?> fs-notice">
32
- <?php if ('update-nag' !== $VARS['type']) : ?><p><?php endif ?>
33
- <?php if (!empty($VARS['title'])) : ?>
34
- <b><?php echo $VARS['title'] ?></b>
35
- <?php endif ?>
36
- <?php echo $VARS['message'] ?>
37
- <?php if ('update-nag' !== $VARS['type']) : ?></p><?php endif ?>
38
- <?php if ($VARS['sticky']) : ?><i class="dashicons dashicons-no"></i><?php endif ?>
39
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
sdk/freemius/templates/checkout-legacy.php DELETED
@@ -1,242 +0,0 @@
1
- <?php
2
- /**
3
- * @package Freemius
4
- * @copyright Copyright (c) 2015, Freemius, Inc.
5
- * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
6
- * @since 1.0.3
7
- */
8
-
9
- if ( ! defined( 'ABSPATH' ) ) {
10
- exit;
11
- }
12
-
13
- wp_enqueue_script( 'jquery' );
14
- wp_enqueue_script( 'json2' );
15
- fs_enqueue_local_script( 'postmessage', 'nojquery.ba-postmessage.min.js' );
16
- fs_enqueue_local_script( 'fs-postmessage', 'postmessage.js' );
17
- fs_enqueue_local_style( 'fs_common', '/admin/common.css' );
18
-
19
- /**
20
- * @var array $VARS
21
- */
22
- $slug = $VARS['slug'];
23
- $fs = freemius( $slug );
24
-
25
- $timestamp = time();
26
-
27
- $context_params = array(
28
- 'plugin_id' => $fs->get_id(),
29
- 'plugin_public_key' => $fs->get_public_key(),
30
- 'plugin_version' => $fs->get_plugin_version(),
31
- );
32
-
33
- // Get site context secure params.
34
- if ( $fs->is_registered() ) {
35
- $site = $fs->get_site();
36
- $plugin_id = fs_request_get( 'plugin_id', $fs->get_id() );
37
-
38
- if ( $plugin_id != $fs->get_id() ) {
39
- if ( $fs->is_addon_activated( $plugin_id ) ) {
40
- $fs_addon = Freemius::get_instance_by_id( $plugin_id );
41
- $site = $fs_addon->get_site();
42
- }
43
- }
44
-
45
- $context_params = array_merge( $context_params, FS_Security::instance()->get_context_params(
46
- $site,
47
- $timestamp,
48
- 'checkout'
49
- ) );
50
- } else {
51
- $current_user = Freemius::_get_current_wp_user();
52
-
53
- // Add site and user info to the request, this information
54
- // is NOT being stored unless the user complete the purchase
55
- // and agrees to the TOS.
56
- $context_params = array_merge( $context_params, array(
57
- 'user_firstname' => $current_user->user_firstname,
58
- 'user_lastname' => $current_user->user_lastname,
59
- 'user_email' => $current_user->user_email,
60
- 'home_url' => home_url(),
61
- ) );
62
-
63
- $fs_user = Freemius::_get_user_by_email( $current_user->user_email );
64
-
65
- if ( is_object( $fs_user ) ) {
66
- $context_params = array_merge( $context_params, FS_Security::instance()->get_context_params(
67
- $fs_user,
68
- $timestamp,
69
- 'checkout'
70
- ) );
71
- }
72
- }
73
-
74
- if ( $fs->is_payments_sandbox() ) {
75
- // Append plugin secure token for sandbox mode authentication.
76
- $context_params['sandbox'] = FS_Security::instance()->get_secure_token(
77
- $fs->get_plugin(),
78
- $timestamp,
79
- 'checkout'
80
- );
81
-
82
- /**
83
- * @since 1.1.7.3 Add security timestamp for sandbox even for anonymous user.
84
- */
85
- if ( empty( $context_params['s_ctx_ts'] ) ) {
86
- $context_params['s_ctx_ts'] = $timestamp;
87
- }
88
- }
89
-
90
- $return_url = $fs->_get_sync_license_url( isset( $_GET['plugin_id'] ) ? $_GET['plugin_id'] : $fs->get_id() );
91
-
92
- $query_params = array_merge( $context_params, $_GET, array(
93
- // Current plugin version.
94
- 'plugin_version' => $fs->get_plugin_version(),
95
- 'sdk_version' => WP_FS__SDK_VERSION,
96
- 'return_url' => $return_url,
97
- // Admin CSS URL for style/design competability.
98
- // 'wp_admin_css' => get_bloginfo('wpurl') . "/wp-admin/load-styles.php?c=1&load=buttons,wp-admin,dashicons",
99
- ) );
100
- ?>
101
- <div id="fs_checkout" class="wrap" style="margin: 0 0 -65px -20px;">
102
- <div id="iframe"></div>
103
- <script type="text/javascript">
104
- // http://stackoverflow.com/questions/4583703/jquery-post-request-not-ajax
105
- jQuery(function ($) {
106
- $.extend({
107
- form: function (url, data, method) {
108
- if (method == null) method = 'POST';
109
- if (data == null) data = {};
110
-
111
- var form = $('<form>').attr({
112
- method: method,
113
- action: url
114
- }).css({
115
- display: 'none'
116
- });
117
-
118
- var addData = function (name, data) {
119
- if ($.isArray(data)) {
120
- for (var i = 0; i < data.length; i++) {
121
- var value = data[i];
122
- addData(name + '[]', value);
123
- }
124
- } else if (typeof data === 'object') {
125
- for (var key in data) {
126
- if (data.hasOwnProperty(key)) {
127
- addData(name + '[' + key + ']', data[key]);
128
- }
129
- }
130
- } else if (data != null) {
131
- form.append($('<input>').attr({
132
- type : 'hidden',
133
- name : String(name),
134
- value: String(data)
135
- }));
136
- }
137
- };
138
-
139
- for (var key in data) {
140
- if (data.hasOwnProperty(key)) {
141
- addData(key, data[key]);
142
- }
143
- }
144
-
145
- return form.appendTo('body');
146
- }
147
- });
148
- });
149
-
150
- (function ($) {
151
- $(function () {
152
-
153
- var
154
- // Keep track of the iframe height.
155
- iframe_height = 800,
156
- base_url = '<?php echo WP_FS__ADDRESS ?>',
157
- // Pass the parent page URL into the Iframe in a meaningful way (this URL could be
158
- // passed via query string or hard coded into the child page, it depends on your needs).
159
- src = base_url + '/checkout/?<?php echo ( isset( $_REQUEST['XDEBUG_SESSION'] ) ? 'XDEBUG_SESSION=' . $_REQUEST['XDEBUG_SESSION'] . '&' : '' ) . http_build_query( $query_params ) ?>#' + encodeURIComponent(document.location.href),
160
-
161
- // Append the Iframe into the DOM.
162
- iframe = $('<iframe " src="' + src + '" width="100%" height="' + iframe_height + 'px" scrolling="no" frameborder="0" style="background: transparent;"><\/iframe>')
163
- .appendTo('#iframe');
164
-
165
- FS.PostMessage.init(base_url, [iframe[0]]);
166
- FS.PostMessage.receiveOnce('height', function (data) {
167
- var h = data.height;
168
- if (!isNaN(h) && h > 0 && h != iframe_height) {
169
- iframe_height = h;
170
- iframe.height(iframe_height + 'px');
171
-
172
- FS.PostMessage.postScroll(iframe[0]);
173
- }
174
- });
175
-
176
- FS.PostMessage.receiveOnce('install', function (data) {
177
- // Post data to activation URL.
178
- $.form('<?php echo fs_nonce_url( $fs->_get_admin_page_url( 'account', array(
179
- 'fs_action' => $slug . '_activate_new',
180
- 'plugin_id' => isset( $_GET['plugin_id'] ) ? $_GET['plugin_id'] : $fs->get_id()
181
- ) ), $slug . '_activate_new' ) ?>', {
182
- user_id : data.user.id,
183
- user_secret_key : data.user.secret_key,
184
- user_public_key : data.user.public_key,
185
- install_id : data.install.id,
186
- install_secret_key: data.install.secret_key,
187
- install_public_key: data.install.public_key
188
- }).submit();
189
- });
190
-
191
- FS.PostMessage.receiveOnce('pending_activation', function (data) {
192
- $.form('<?php echo fs_nonce_url( $fs->_get_admin_page_url( 'account', array(
193
- 'fs_action' => $slug . '_activate_new',
194
- 'plugin_id' => fs_request_get( 'plugin_id', $fs->get_id() ),
195
- 'pending_activation' => true,
196
- ) ), $slug . '_activate_new' ) ?>', {
197
- user_email: data.user_email
198
- }).submit();
199
- });
200
-
201
- FS.PostMessage.receiveOnce('get_context', function () {
202
- console.debug('receiveOnce', 'get_context');
203
-
204
- // If the user didn't connect his account with Freemius,
205
- // once he accepts the Terms of Service and Privacy Policy,
206
- // and then click the purchase button, the context information
207
- // of the user will be shared with Freemius in order to complete the
208
- // purchase workflow and activate the license for the right user.
209
- <?php $install_data = array_merge( $fs->get_opt_in_params(),
210
- array(
211
- 'activation_url' => fs_nonce_url( $fs->_get_admin_page_url( '',
212
- array(
213
- 'fs_action' => $slug . '_activate_new',
214
- 'plugin_id' => fs_request_get( 'plugin_id', $fs->get_id() ),
215
-
216
- ) ),
217
- $slug . '_activate_new' )
218
- ) ) ?>
219
- FS.PostMessage.post('context', <?php echo json_encode( $install_data ) ?>, iframe[0]);
220
- });
221
-
222
- FS.PostMessage.receiveOnce('get_dimensions', function (data) {
223
- console.debug('receiveOnce', 'get_dimensions');
224
-
225
- FS.PostMessage.post('dimensions', {
226
- height : $(document.body).height(),
227
- scrollTop: $(document).scrollTop()
228
- }, iframe[0]);
229
- });
230
- });
231
- })(jQuery);
232
- </script>
233
- </div>
234
- <?php
235
- $params = array(
236
- 'page' => 'checkout',
237
- 'module_id' => $fs->get_id(),
238
- 'module_slug' => $slug,
239
- 'module_version' => $fs->get_plugin_version(),
240
- );
241
- fs_require_template( 'powered-by.php', $params );
242
- ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
wp-security-audit-log.php CHANGED
@@ -4,7 +4,7 @@
4
  * Plugin URI: http://www.wpsecurityauditlog.com/
5
  * Description: Identify WordPress security issues before they become a problem. Keep track of everything happening on your WordPress including WordPress users activity. Similar to Windows Event Log and Linux Syslog, WP Security Audit Log generates a security alert for everything that happens on your WordPress blogs and websites. Use the Audit Log Viewer included in the plugin to see all the security alerts.
6
  * Author: WP White Security
7
- * Version: 3.2.1
8
  * Text Domain: wp-security-audit-log
9
  * Author URI: http://www.wpsecurityauditlog.com/
10
  * License: GPL2
@@ -38,8 +38,8 @@ if ( ! function_exists( 'wsal_freemius' ) ) {
38
  *
39
  * @since 2.7.0
40
  */
41
- if ( file_exists( plugin_dir_path( __FILE__ ) . '/sdk/wsal-freemius.php' ) ) {
42
- require_once( plugin_dir_path( __FILE__ ) . '/sdk/wsal-freemius.php' );
43
  }
44
 
45
  /**
@@ -54,7 +54,7 @@ if ( ! function_exists( 'wsal_freemius' ) ) {
54
  *
55
  * @var string
56
  */
57
- public $version = '3.2.1';
58
 
59
  // Plugin constants.
60
  const PLG_CLS_PRFX = 'WSAL_';
@@ -930,6 +930,9 @@ if ( ! function_exists( 'wsal_freemius' ) ) {
930
  public function SetGlobalOption( $option, $value, $prefix = self::OPT_PRFX ) {
931
  $this->options = new WSAL_Models_Option();
932
  $this->options->SetOptionValue( $prefix . $option, $value );
 
 
 
933
  }
934
 
935
  /**
4
  * Plugin URI: http://www.wpsecurityauditlog.com/
5
  * Description: Identify WordPress security issues before they become a problem. Keep track of everything happening on your WordPress including WordPress users activity. Similar to Windows Event Log and Linux Syslog, WP Security Audit Log generates a security alert for everything that happens on your WordPress blogs and websites. Use the Audit Log Viewer included in the plugin to see all the security alerts.
6
  * Author: WP White Security
7
+ * Version: 3.2.2
8
  * Text Domain: wp-security-audit-log
9
  * Author URI: http://www.wpsecurityauditlog.com/
10
  * License: GPL2
38
  *
39
  * @since 2.7.0
40
  */
41
+ if ( file_exists( plugin_dir_path( __FILE__ ) . '/includes/wsal-freemius.php' ) ) {
42
+ require_once( plugin_dir_path( __FILE__ ) . '/includes/wsal-freemius.php' );
43
  }
44
 
45
  /**
54
  *
55
  * @var string
56
  */
57
+ public $version = '3.2.2';
58
 
59
  // Plugin constants.
60
  const PLG_CLS_PRFX = 'WSAL_';
930
  public function SetGlobalOption( $option, $value, $prefix = self::OPT_PRFX ) {
931
  $this->options = new WSAL_Models_Option();
932
  $this->options->SetOptionValue( $prefix . $option, $value );
933
+
934
+ // Delete options transient.
935
+ delete_transient( 'wsal_options' );
936
  }
937
 
938
  /**