Simple History - Version 2.30

Version Description

(April 2019) =

  • Add better Gutenberg compatibility.
  • Don't log WooCommerce scheduled actions. Fixes https://wordpress.org/support/topic/cant-use-flooded-with-deleted-scheduled-action-woocommerce-webhooks/.
  • Store if post password has been set, unset, or changed.
  • Store if a log entry comes from the REST API. Stored in the event context as _rest_api_request.
  • Check that logger messages exists and is array before trying to use.
  • Bump required version in readme to 5.4. It's just to difficult to keep the plugin compatible with PHP less than PHP version 5.4.
  • Updates to some translation strings.
Download this release

Release Info

Developer eskapism
Plugin Icon 128x128 Simple History
Version 2.30
Comparing to
See all releases

Code changes from version 2.29.2 to 2.30

composer.json CHANGED
@@ -14,7 +14,7 @@
14
  "require": {
15
  "php": ">=5.3.0"
16
  },
17
- "version": "2.29.2",
18
  "authors": [
19
  {
20
  "name": "Pär Thernström",
14
  "require": {
15
  "php": ">=5.3.0"
16
  },
17
+ "version": "2.31",
18
  "authors": [
19
  {
20
  "name": "Pär Thernström",
composer.lock CHANGED
@@ -1,10 +1,10 @@
1
  {
2
  "_readme": [
3
  "This file locks the dependencies of your project to a known state",
4
- "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5
  "This file is @generated automatically"
6
  ],
7
- "content-hash": "3b0184bda47a45ddae0d5c8badfd4fe8",
8
  "packages": [],
9
  "packages-dev": [],
10
  "aliases": [],
1
  {
2
  "_readme": [
3
  "This file locks the dependencies of your project to a known state",
4
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5
  "This file is @generated automatically"
6
  ],
7
+ "content-hash": "59027ab3c002d867118ae3c2794d1066",
8
  "packages": [],
9
  "packages-dev": [],
10
  "aliases": [],
dropins/SimpleHistoryFilterDropin.php CHANGED
@@ -285,10 +285,10 @@ class SimpleHistoryFilterDropin {
285
 
286
  <label class="SimpleHistory__filters__filterLabel"><?php _ex( 'Log levels:', 'Filter label', 'simple-history' ) ?></label>
287
 
288
- <select
289
- name="loglevels"
290
- class="SimpleHistory__filters__filter SimpleHistory__filters__filter--loglevel"
291
- placeholder="<?php _e( 'All log levels', 'simple-history' ) ?>"
292
  multiple
293
  >
294
  <option <?php selected( in_array( 'debug', $arr_default_loglevels ) ) ?> value="debug" data-color="#CEF6D8"><?php echo $this->sh->getLogLevelTranslated( 'Debug' ) ?></option>
@@ -322,10 +322,10 @@ class SimpleHistoryFilterDropin {
322
 
323
  <label class="SimpleHistory__filters__filterLabel"><?php _ex( 'Message types:', 'Filter label', 'simple-history' ) ?></label>
324
 
325
- <select
326
- name="messages"
327
- class="SimpleHistory__filters__filter SimpleHistory__filters__filter--logger"
328
- placeholder="<?php _e( 'All messages', 'simple-history' ) ?>"
329
  multiple
330
  >
331
  <?php
@@ -421,7 +421,7 @@ class SimpleHistoryFilterDropin {
421
  value="<?php echo esc_attr( implode( ',', $default_user_ids ) ) ?>"
422
  data-default-user-data="<?php echo esc_attr( json_encode( $arr_default_user_data ) ) ?>"
423
  >
424
- </select>
425
  </p>
426
  <?php
427
  }
@@ -594,8 +594,8 @@ class SimpleHistoryFilterDropin {
594
 
595
  echo $prefix . '<br>';
596
 
597
- /* translators: 1: month, 2: day, 3: year, 4: hour, 5: minute */
598
- printf( __( '%1$s %2$s, %3$s ' ), $month, $day, $year );
599
 
600
  echo '</span>';
601
 
285
 
286
  <label class="SimpleHistory__filters__filterLabel"><?php _ex( 'Log levels:', 'Filter label', 'simple-history' ) ?></label>
287
 
288
+ <select
289
+ name="loglevels"
290
+ class="SimpleHistory__filters__filter SimpleHistory__filters__filter--loglevel"
291
+ placeholder="<?php _e( 'All log levels', 'simple-history' ) ?>"
292
  multiple
293
  >
294
  <option <?php selected( in_array( 'debug', $arr_default_loglevels ) ) ?> value="debug" data-color="#CEF6D8"><?php echo $this->sh->getLogLevelTranslated( 'Debug' ) ?></option>
322
 
323
  <label class="SimpleHistory__filters__filterLabel"><?php _ex( 'Message types:', 'Filter label', 'simple-history' ) ?></label>
324
 
325
+ <select
326
+ name="messages"
327
+ class="SimpleHistory__filters__filter SimpleHistory__filters__filter--logger"
328
+ placeholder="<?php _e( 'All messages', 'simple-history' ) ?>"
329
  multiple
330
  >
331
  <?php
421
  value="<?php echo esc_attr( implode( ',', $default_user_ids ) ) ?>"
422
  data-default-user-data="<?php echo esc_attr( json_encode( $arr_default_user_data ) ) ?>"
423
  >
424
+ </select>
425
  </p>
426
  <?php
427
  }
594
 
595
  echo $prefix . '<br>';
596
 
597
+ /* translators: 1: month, 2: day, 3: year */
598
+ printf( __( '%1$s %2$s, %3$s' ), $month, $day, $year );
599
 
600
  echo '</span>';
601
 
dropins/SimpleHistoryPluginPatchesDropin.php CHANGED
@@ -18,101 +18,24 @@ class SimpleHistoryPluginPatchesDropin {
18
 
19
  $this->patch_captcha_on_login();
20
 
21
- // $this->patch_nextgen_gallery();
22
- // $this->patch_aio_events_calendar();
23
- }
24
-
25
- /**
26
- * All-in-one events calendar imports ical/rss events with a cron job
27
- * which can lead to a lot of posts chnaged
28
- */
29
- function patch_aio_events_calendar() {
30
-
31
- // feature/fix-AIOEventsCalendar
32
- add_action( 'simple_history/log/do_log', array( $this, 'patch_aio_events_calendar_on_log' ), 10, 5 );
33
-
34
- }
35
-
36
-
37
- function patch_aio_events_calendar_on_log( $doLog, $level = null, $message = null, $context = null, $loggerInstance = null ) {
38
-
39
- // this happens when posts are updated
40
- if ( ! isset( $context['_message_key'] ) || $context['_message_key'] !== 'post_updated' ) {
41
- return $doLog;
42
- }
43
-
44
- // this happens when post type is ai1ec_event
45
- if ( ! isset( $context['post_type'] ) || $context['post_type'] !== 'ai1ec_event' ) {
46
- return $doLog;
47
- }
48
-
49
- // we don't log when is happens in admin, only when it's a cron job
50
- if ( ! defined( 'DOING_CRON' ) || ! DOING_CRON || is_admin() ) {
51
- return $doLog;
52
- }
53
-
54
- // ok, this is a non-admin, cron-running post update for the ai1ec_event post type, so cancel the logging
55
- $doLog = false;
56
-
57
- return $doLog;
58
-
59
  }
60
 
61
-
62
  /**
 
 
 
63
  *
64
- * Nextgen Gallery and Nextgen Gallery Plus updates posts every 30 minutes or so when accessing
65
- * posts with galleries on the front
66
- *
67
- * Logged messages are like "Updated nextgen gallery - display type "NextGen Pro Mosaic""
68
- * and it can be a lot of them.
69
- *
70
- * Support forum thread:
71
- * https://wordpress.org/support/topic/non-stop-logging-nextgen-gallery-items
72
- *
73
- * Note that Simple History does nothing wrong, the posts are updated, but it's just annoying
74
- * and unneeded/unwanted info.
75
- *
76
- * We solve this by canceling logging of these events.
77
  */
78
- function patch_nextgen_gallery() {
79
-
80
- add_action( 'simple_history/log/do_log', array( $this, 'patch_nextgen_gallery_on_log' ), 10, 5 );
81
-
82
  }
83
 
84
- function patch_nextgen_gallery_on_log( $doLog, $level = null, $message = null, $context = null, $loggerInstance = null ) {
85
-
86
- // Check that NextGen is installed
87
- if ( ! defined( 'NGG_PLUGIN' ) ) {
88
- return $doLog;
89
- }
90
-
91
- if ( ! isset( $context['_message_key'] ) || $context['_message_key'] !== 'post_updated' ) {
92
- return $doLog;
93
- }
94
-
95
- if ( ! isset( $context['post_type'] ) || $context['post_type'] !== 'display_type' ) {
96
- return $doLog;
97
- }
98
-
99
- // The log spamming thingie is happening on the front, so only continue if this is not in the admin area
100
- if ( is_admin() ) {
101
- return $doLog;
102
- }
103
-
104
- // The calls must come from logger SimplePostLogger
105
- if ( $loggerInstance->slug !== 'SimplePostLogger' ) {
106
- return $doLog;
107
- }
108
-
109
- // There. All checked. Now cancel the logging.
110
- $doLog = false;
111
-
112
- return $doLog;
113
- }
114
-
115
-
116
  /**
117
  * Captcha on Login
118
  *
@@ -244,25 +167,4 @@ class SimpleHistoryPluginPatchesDropin {
244
  return $doLog;
245
 
246
  }
247
-
248
- /**
249
- * Log misc useful things to the system log. Useful when developing/testing/debuging etc.
250
- */
251
- function system_debug_log() {
252
-
253
- error_log( '$_GET: ' . SimpleHistory::json_encode( $_GET ) );
254
- error_log( '$_POST: ' . SimpleHistory::json_encode( $_POST ) );
255
- error_log( '$_FILES: ' . SimpleHistory::json_encode( $_FILES ) );
256
- error_log( '$_SERVER: ' . SimpleHistory::json_encode( $_SERVER ) );
257
-
258
- $args = func_get_args();
259
- $i = 0;
260
-
261
- foreach ( $args as $arg ) {
262
- error_log( "\$arg $i: " . SimpleHistory::json_encode( $arg ) );
263
- $i++;
264
- }
265
-
266
- }
267
-
268
  } // end class
18
 
19
  $this->patch_captcha_on_login();
20
 
21
+ add_filter(
22
+ 'simple_history/post_logger/skip_posttypes',
23
+ array( $this, 'woocommerce_skip_scheduled_actions_posttype' )
24
+ );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  }
26
 
 
27
  /**
28
+ * Skip logging of WooCommerce scheduled actions/cron related things,
29
+ * stored in the scheduled-action"post type. If not disabled the log can be filled with
30
+ * a large amount of actions for this postype.
31
  *
32
+ * @since 2.3
 
 
 
 
 
 
 
 
 
 
 
 
33
  */
34
+ public function woocommerce_skip_scheduled_actions_posttype( $skip_posttypes ) {
35
+ $skip_posttypes[] = 'scheduled-action';
36
+ return $skip_posttypes;
 
37
  }
38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  /**
40
  * Captcha on Login
41
  *
167
  return $doLog;
168
 
169
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  } // end class
grumphp.yml DELETED
@@ -1,4 +0,0 @@
1
- parameters:
2
- git_dir: .
3
- bin_dir: vendor/bin
4
- tasks: { phpcs: null }
 
 
 
 
inc/SimpleHistory.php CHANGED
@@ -1,12 +1,12 @@
1
  <?php
2
 
3
- defined( 'ABSPATH' ) or die();
4
 
5
  /**
6
  * Main class for Simple History
7
  */
8
- class SimpleHistory {
9
-
10
  const NAME = 'Simple History';
11
 
12
  /**
@@ -69,17 +69,16 @@ class SimpleHistory {
69
  /** ID for the general settings section */
70
  const SETTINGS_SECTION_GENERAL_ID = 'simple_history_settings_section_general';
71
 
72
- function __construct() {
73
-
74
  $this->init();
75
-
76
  } // construct
77
 
78
  /**
79
  * @since 2.5.2
80
  */
81
- public function init() {
82
-
83
  /**
84
  * Fires before Simple History does it's init stuff
85
  *
@@ -87,35 +86,56 @@ class SimpleHistory {
87
  *
88
  * @param SimpleHistory $SimpleHistory This class.
89
  */
90
- do_action( 'simple_history/before_init', $this );
91
 
92
  $this->setup_variables();
93
 
94
  // Actions and filters, ordered by order specified in codex: http://codex.wordpress.org/Plugin_API/Action_Reference
95
- add_action( 'after_setup_theme', array( $this, 'load_plugin_textdomain' ) );
96
- add_action( 'after_setup_theme', array( $this, 'add_default_settings_tabs' ) );
 
 
 
97
 
98
  // Plugins and dropins are loaded using the "after_setup_theme" filter so
99
  // themes can use filters to modify the loading of them.
100
  // The drawback with this is that for example logouts done when plugins like
101
  // iThemes Security is installed is not logged, because those plugins fire wp_logout()
102
  // using filter "plugins_loaded", i.e. before simple history has loaded its filters.
103
- add_action( 'after_setup_theme', array( $this, 'load_loggers' ) );
104
- add_action( 'after_setup_theme', array( $this, 'load_dropins' ) );
105
 
106
  // Run before loading of loggers and before menu items are added.
107
- add_action( 'after_setup_theme', array( $this, 'check_for_upgrade' ), 5 );
108
 
109
- add_action( 'after_setup_theme', array( $this, 'setup_cron' ) );
110
 
111
  // Filters and actions not called during regular boot.
112
- add_filter( 'gettext', array( $this, 'filter_gettext' ), 20, 3 );
113
- add_filter( 'gettext_with_context', array( $this, 'filter_gettext_with_context' ), 20, 4 );
 
 
 
 
 
114
 
115
- add_filter( 'gettext', array( $this, 'filter_gettext_storeLatestTranslations' ), 10, 3 );
 
 
 
 
 
116
 
117
- add_action( 'admin_bar_menu', array( $this, 'add_admin_bar_network_menu_item' ), 40 );
118
- add_action( 'admin_bar_menu', array( $this, 'add_admin_bar_menu_item' ), 40 );
 
 
 
 
 
 
 
 
119
 
120
  /**
121
  * Filter that is used to log things, without the need to check that simple history is available
@@ -130,7 +150,12 @@ class SimpleHistory {
130
  *
131
  * @since 2.13
132
  */
133
- add_filter( 'simple_history_log', array( $this, 'on_filter_simple_history_log' ), 10, 3 );
 
 
 
 
 
134
 
135
  /**
136
  * Filter to log with specific log level, for example:
@@ -139,19 +164,57 @@ class SimpleHistory {
139
  *
140
  * @since 2.17
141
  */
142
- add_filter( 'simple_history_log_emergency', array( $this, 'on_filter_simple_history_log_emergency' ), 10, 3 );
143
- add_filter( 'simple_history_log_alert', array( $this, 'on_filter_simple_history_log_alert' ), 10, 2 );
144
- add_filter( 'simple_history_log_critical', array( $this, 'on_filter_simple_history_log_critical' ), 10, 2 );
145
- add_filter( 'simple_history_log_error', array( $this, 'on_filter_simple_history_log_error' ), 10, 2 );
146
- add_filter( 'simple_history_log_warning', array( $this, 'on_filter_simple_history_log_warning' ), 10, 2 );
147
- add_filter( 'simple_history_log_notice', array( $this, 'on_filter_simple_history_log_notice' ), 10, 2 );
148
- add_filter( 'simple_history_log_info', array( $this, 'on_filter_simple_history_log_info' ), 10, 2 );
149
- add_filter( 'simple_history_log_debug', array( $this, 'on_filter_simple_history_log_debug' ), 10, 2 );
150
-
151
- if ( is_admin() ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
152
 
 
153
  $this->add_admin_actions();
154
-
155
  }
156
 
157
  /**
@@ -161,47 +224,57 @@ class SimpleHistory {
161
  *
162
  * @param SimpleHistory $SimpleHistory This class.
163
  */
164
- do_action( 'simple_history/after_init', $this );
165
 
166
  // Add some extra info to each logged context when SIMPLE_HISTORY_LOG_DEBUG is set and true
167
- if ( defined( 'SIMPLE_HISTORY_LOG_DEBUG' ) && SIMPLE_HISTORY_LOG_DEBUG ) {
168
-
169
  add_filter(
170
- 'simple_history/log_argument/context', function( $context, $level, $message, $logger ) {
171
-
172
  $sh = SimpleHistory::get_instance();
173
- $context['_debug_get'] = $sh->json_encode( $_GET );
174
- $context['_debug_post'] = $sh->json_encode( $_POST );
175
- $context['_debug_server'] = $sh->json_encode( $_SERVER );
176
- $context['_debug_files'] = $sh->json_encode( $_FILES );
177
  $context['_debug_php_sapi_name'] = php_sapi_name();
178
 
179
  global $argv;
180
- $context['_debug_argv'] = $sh->json_encode( $argv );
181
 
182
- $consts = get_defined_constants( true );
183
  $consts = $consts['user'];
184
- $context['_debug_user_constants'] = $sh->json_encode( $consts );
 
 
185
 
186
- $postdata = file_get_contents( 'php://input' );
187
- $context['_debug_http_raw_post_data'] = $sh->json_encode( $postdata );
 
 
188
 
189
- $context['_debug_wp_debug_backtrace_summary'] = wp_debug_backtrace_summary();
190
- $context['_debug_is_admin'] = json_encode( is_admin() );
191
- $context['_debug_is_ajax'] = json_encode( defined( 'DOING_AJAX' ) && DOING_AJAX );
192
- $context['_debug_is_doing_cron'] = json_encode( defined( 'DOING_CRON' ) && DOING_CRON );
 
 
 
 
 
 
193
 
194
  global $wp_current_filter;
195
- $context['_debug_current_filter_array'] = $wp_current_filter;
 
 
196
  $context['_debug_current_filter'] = current_filter();
197
 
198
  return $context;
199
-
200
- }, 10, 4
 
201
  );
202
-
203
  }
204
-
205
  }
206
 
207
  /**
@@ -214,8 +287,12 @@ class SimpleHistory {
214
  * @param array $context Optional context to add to the logged data.
215
  * @param string $level The loglevel. Must be one of the existing ones. Defaults to "info".
216
  */
217
- public function on_filter_simple_history_log( $message = null, $context = null, $level = 'info' ) {
218
- SimpleLogger()->log( $level, $message, $context );
 
 
 
 
219
  }
220
 
221
  /**
@@ -224,8 +301,11 @@ class SimpleHistory {
224
  * @param string $message The message to log.
225
  * @param array $context The context (optional).
226
  */
227
- public function on_filter_simple_history_log_emergency( $message = null, $context = null ) {
228
- SimpleLogger()->log( 'emergency', $message, $context );
 
 
 
229
  }
230
 
231
  /**
@@ -234,8 +314,11 @@ class SimpleHistory {
234
  * @param string $message The message to log.
235
  * @param array $context The context (optional).
236
  */
237
- public function on_filter_simple_history_log_alert( $message = null, $context = null ) {
238
- SimpleLogger()->log( 'alert', $message, $context );
 
 
 
239
  }
240
 
241
  /**
@@ -244,8 +327,11 @@ class SimpleHistory {
244
  * @param string $message The message to log.
245
  * @param array $context The context (optional).
246
  */
247
- public function on_filter_simple_history_log_critical( $message = null, $context = null ) {
248
- SimpleLogger()->log( 'critical', $message, $context );
 
 
 
249
  }
250
 
251
  /**
@@ -254,8 +340,11 @@ class SimpleHistory {
254
  * @param string $message The message to log.
255
  * @param array $context The context (optional).
256
  */
257
- public function on_filter_simple_history_log_error( $message = null, $context = null ) {
258
- SimpleLogger()->log( 'error', $message, $context );
 
 
 
259
  }
260
 
261
  /**
@@ -264,8 +353,11 @@ class SimpleHistory {
264
  * @param string $message The message to log.
265
  * @param array $context The context (optional).
266
  */
267
- public function on_filter_simple_history_log_warning( $message = null, $context = null ) {
268
- SimpleLogger()->log( 'warning', $message, $context );
 
 
 
269
  }
270
 
271
  /**
@@ -274,8 +366,11 @@ class SimpleHistory {
274
  * @param string $message The message to log.
275
  * @param array $context The context (optional).
276
  */
277
- public function on_filter_simple_history_log_notice( $message = null, $context = null ) {
278
- SimpleLogger()->log( 'notice', $message, $context );
 
 
 
279
  }
280
 
281
  /**
@@ -284,8 +379,11 @@ class SimpleHistory {
284
  * @param string $message The message to log.
285
  * @param array $context The context (optional).
286
  */
287
- public function on_filter_simple_history_log_info( $message = null, $context = null ) {
288
- SimpleLogger()->log( 'info', $message, $context );
 
 
 
289
  }
290
 
291
  /**
@@ -294,34 +392,50 @@ class SimpleHistory {
294
  * @param string $message The message to log.
295
  * @param array $context The context (optional).
296
  */
297
- public function on_filter_simple_history_log_debug( $message = null, $context = null ) {
298
- SimpleLogger()->log( 'debug', $message, $context );
 
 
 
299
  }
300
 
301
  /**
302
  * @since 2.5.2
303
  */
304
- private function add_admin_actions() {
305
-
306
- add_action( 'admin_menu', array( $this, 'add_admin_pages' ) );
307
- add_action( 'admin_menu', array( $this, 'add_settings' ) );
308
-
309
- add_action( 'admin_footer', array( $this, 'add_js_templates' ) );
310
-
311
- add_action( 'wp_dashboard_setup', array( $this, 'add_dashboard_widget' ) );
312
-
313
- add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_scripts' ) );
314
-
315
- add_action( 'admin_head', array( $this, 'onAdminHead' ) );
316
- add_action( 'admin_footer', array( $this, 'onAdminFooter' ) );
317
-
318
- add_action( 'simple_history/history_page/before_gui', array( $this, 'output_quick_stats' ) );
319
- add_action( 'simple_history/dashboard/before_gui', array( $this, 'output_quick_stats' ) );
320
-
321
- add_action( 'wp_ajax_simple_history_api', array( $this, 'api' ) );
322
-
323
- add_filter( 'plugin_action_links_simple-history/index.php', array( $this, 'plugin_action_links' ), 10, 4 );
324
-
 
 
 
 
 
 
 
 
 
 
 
 
 
325
  }
326
 
327
  /**
@@ -331,8 +445,8 @@ class SimpleHistory {
331
  *
332
  * @since 2.7.1
333
  */
334
- function add_admin_bar_network_menu_item( $wp_admin_bar ) {
335
-
336
  /**
337
  * Filter to control if admin bar shortcut should be added
338
  *
@@ -340,70 +454,71 @@ class SimpleHistory {
340
  *
341
  * @param bool Add item
342
  */
343
- $add_items = apply_filters( 'simple_history/add_admin_bar_network_menu_item', true );
 
 
 
344
 
345
- if ( ! $add_items ) {
346
  return;
347
  }
348
 
349
  // Don't show for logged out users or single site mode.
350
- if ( ! is_user_logged_in() || ! is_multisite() ) {
351
  return;
352
  }
353
 
354
  // Show only when the user has at least one site, or they're a super admin.
355
- if ( count( $wp_admin_bar->user->blogs ) < 1 && ! is_super_admin() ) {
356
  return;
357
  }
358
 
359
  // Setting to show as page must be true
360
- if ( ! $this->setting_show_as_page() ) {
361
  return;
362
  }
363
 
364
  // User must have capability to view the history page
365
- if ( ! current_user_can( $this->get_view_history_capability() ) ) {
366
  return;
367
  }
368
 
369
  /*
370
  menu_page_url() is defined in the WordPress Plugin Administration API, which is not loaded here by default */
371
  /* dito for is_plugin_active() */
372
- require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
373
 
374
- foreach ( (array) $wp_admin_bar->user->blogs as $blog ) {
375
-
376
- switch_to_blog( $blog->userblog_id );
377
-
378
- if ( is_plugin_active( SIMPLE_HISTORY_BASENAME ) ) {
379
 
 
380
  $menu_id = 'simple-history-blog-' . $blog->userblog_id;
381
- $parent_menu_id = 'blog-' . $blog->userblog_id;
382
- $url = admin_url( 'index.php?page=simple_history_page' );
383
 
384
  // Each network site is added by WP core with id "blog-1", "blog-2" ... "blog-n"
385
  // https://codex.wordpress.org/Function_Reference/add_node
386
  $args = array(
387
- 'id' => $menu_id,
388
  'parent' => $parent_menu_id,
389
- 'title' => _x( 'View History', 'Admin bar network name', 'simple-history' ),
390
- 'href' => $url,
391
- 'meta' => array(
392
- 'class' => 'ab-item--simplehistory',
393
  ),
 
 
 
 
394
  );
395
 
396
- $wp_admin_bar->add_node( $args );
397
-
398
  } // End if().
399
 
400
  restore_current_blog();
401
-
402
  } // End foreach().
403
-
404
  } // func
405
 
406
-
407
  /**
408
  * Adds a "View history" item/shortcut to the admin bar
409
  *
@@ -411,8 +526,8 @@ class SimpleHistory {
411
  *
412
  * @since 2.7.1
413
  */
414
- function add_admin_bar_menu_item( $wp_admin_bar ) {
415
-
416
  /**
417
  * Filter to control if admin bar shortcut should be added
418
  *
@@ -420,48 +535,50 @@ class SimpleHistory {
420
  *
421
  * @param bool Add item
422
  */
423
- $add_item = apply_filters( 'simple_history/add_admin_bar_menu_item', true );
 
 
 
424
 
425
- if ( ! $add_item ) {
426
  return;
427
  }
428
 
429
  // Don't show for logged out users
430
- if ( ! is_user_logged_in() ) {
431
  return;
432
  }
433
 
434
  // Setting to show as page must be true
435
- if ( ! $this->setting_show_as_page() ) {
436
  return;
437
  }
438
 
439
  // User must have capability to view the history page
440
- if ( ! current_user_can( $this->get_view_history_capability() ) ) {
441
  return;
442
  }
443
 
444
  /*
445
  menu_page_url() is defined in the WordPress Plugin Administration API, which is not loaded here by default */
446
  /* dito for is_plugin_active() */
447
- require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
448
 
449
  $menu_id = 'simple-history-view-history';
450
- $parent_menu_id = 'site-name';
451
- $url = admin_url( 'index.php?page=simple_history_page' );
452
 
453
  $args = array(
454
- 'id' => $menu_id,
455
  'parent' => $parent_menu_id,
456
- 'title' => _x( 'Simple History', 'Admin bar name', 'simple-history' ),
457
- 'href' => $url,
458
- 'meta' => array(
459
- 'class' => 'ab-item--simplehistory',
460
- ),
461
  );
462
 
463
- $wp_admin_bar->add_node( $args );
464
-
465
  } // func
466
 
467
  /**
@@ -469,22 +586,22 @@ class SimpleHistory {
469
  *
470
  * @return SimpleHistory instance
471
  */
472
- public static function get_instance() {
473
-
474
- if ( ! isset( self::$instance ) ) {
475
-
476
  self::$instance = new SimpleHistory();
477
-
478
  }
479
 
480
  return self::$instance;
481
-
482
  }
483
 
484
- function filter_gettext_storeLatestTranslations( $translation, $text, $domain ) {
485
-
 
 
 
486
  // Check that translation is a string or integer, i.ex. the valid values for an array key
487
- if ( ! is_string( $translation ) || ! is_integer( $translation ) ) {
488
  return $translation;
489
  }
490
 
@@ -496,102 +613,104 @@ class SimpleHistory {
496
  // global $sh_latest_translations;
497
  $sh_latest_translations = $this->gettextLatestTranslations;
498
 
499
- $sh_latest_translations[ $translation ] = array(
500
  'translation' => $translation,
501
  'text' => $text,
502
- 'domain' => $domain,
503
  );
504
 
505
- $arr_length = sizeof( $sh_latest_translations );
506
- if ( $arr_length > $array_max_size ) {
507
- $sh_latest_translations = array_slice( $sh_latest_translations, $arr_length - $array_max_size );
 
 
 
508
  }
509
 
510
  $this->gettextLatestTranslations = $sh_latest_translations;
511
 
512
  return $translation;
513
-
514
  }
515
 
516
- function setup_cron() {
 
 
 
 
 
517
 
518
- add_filter( 'simple_history/maybe_purge_db', array( $this, 'maybe_purge_db' ) );
519
-
520
- if ( ! wp_next_scheduled( 'simple_history/maybe_purge_db' ) ) {
521
- wp_schedule_event( time(), 'daily', 'simple_history/maybe_purge_db' );
522
  } else {
523
  }
524
 
525
  // Remove old schedule (only author dev sites should have it)
526
- $old_next_scheduled = wp_next_scheduled( 'simple_history/purge_db' );
527
- if ( $old_next_scheduled ) {
528
- wp_unschedule_event( $old_next_scheduled, 'simple_history/purge_db' );
529
  }
530
-
531
  }
532
 
533
- public function testlog_old() {
534
-
535
  // Log that an email has been sent
536
- simple_history_add(
537
- array(
538
- 'object_type' => 'Email',
539
- 'object_name' => 'Hi there',
540
- 'action' => 'was sent',
541
- )
542
- );
543
 
544
  // Will show “Plugin your_plugin_name Edited” in the history log
545
- simple_history_add( 'action=edited&object_type=plugin&object_name=your_plugin_name' );
 
 
546
 
547
  // Will show the history item "Starship USS Enterprise repaired"
548
- simple_history_add( 'action=repaired&object_type=Starship&object_name=USS Enterprise' );
549
-
550
- // Log with some extra details about the email
551
  simple_history_add(
552
- array(
553
- 'object_type' => 'Email',
554
- 'object_name' => 'Hi there',
555
- 'action' => 'was sent',
556
- 'description' => 'The database query to generate the email took .3 seconds. This is email number 4 that is sent to this user',
557
- )
558
  );
559
 
 
 
 
 
 
 
 
 
560
  }
561
 
562
- public function onAdminHead() {
563
-
564
- if ( $this->is_on_our_own_pages() ) {
565
-
566
- do_action( 'simple_history/admin_head', $this );
567
-
568
  }
569
-
570
  }
571
 
572
- public function onAdminFooter() {
573
-
574
- if ( $this->is_on_our_own_pages() ) {
575
-
576
- do_action( 'simple_history/admin_footer', $this );
577
-
578
  }
579
-
580
  }
581
 
582
  /**
583
  * Output JS templated into footer
584
  */
585
- public function add_js_templates( $hook ) {
586
-
587
- if ( $this->is_on_our_own_pages() ) {
588
-
589
- ?>
590
  <script type="text/html" id="tmpl-simple-history-base">
591
 
592
  <div class="SimpleHistory__waitingForFirstLoad">
593
- <img src="<?php echo admin_url( '/images/spinner.gif' ); ?>" alt="" width="20" height="20">
594
- <?php echo _x( 'Loading history...', 'Message visible while waiting for log to load from server the first time', 'simple-history' ); ?>
 
 
 
 
 
 
595
  </div>
596
 
597
  <div class="SimpleHistoryLogitemsWrap">
@@ -628,7 +747,7 @@ class SimpleHistory {
628
  href="#">‹</a>
629
  <span class="SimpleHistoryPaginationInput">
630
  <input class="SimpleHistoryPaginationCurrentPage" title="{{ data.strings.currentPage }}" type="text" name="paged" value="{{ data.api_args.paged }}" size="4">
631
- <?php _x( 'of', 'page n of n', 'simple-history' ); ?>
632
  <span class="total-pages">{{ data.pages_count }}</span>
633
  </span>
634
  <a
@@ -652,7 +771,9 @@ class SimpleHistory {
652
  <div class="SimpleHistory-modal__background"></div>
653
  <div class="SimpleHistory-modal__content">
654
  <div class="SimpleHistory-modal__contentInner">
655
- <img class="SimpleHistory-modal__contentSpinner" src="<?php echo admin_url( '/images/spinner.gif' ); ?>" alt="">
 
 
656
  </div>
657
  <div class="SimpleHistory-modal__contentClose">
658
  <button class="button">✕</button>
@@ -671,7 +792,10 @@ class SimpleHistory {
671
  <div class="SimpleHistoryLogitem__firstcol"></div>
672
  <div class="SimpleHistoryLogitem__secondcol">
673
  <div class="SimpleHistoryLogitem__text">
674
- <?php _e( 'Sorry, but there are too many similar events to show.', 'simple-history' ); ?>
 
 
 
675
  <!-- <br>occasionsCount: {{ data.occasionsCount }}
676
  <br>occasionsCountMaxReturn: {{ data.occasionsCountMaxReturn }}
677
  <br>diff: {{ data.occasionsCount - data.occasionsCountMaxReturn }}
@@ -686,16 +810,12 @@ class SimpleHistory {
686
  </li>
687
  </script>
688
 
689
- <?php
690
-
691
- // Call plugins so they can add their js
692
- foreach ( $this->instantiatedLoggers as $one_logger ) {
693
- if ( method_exists( $one_logger['instance'], 'adminJS' ) ) {
694
- $one_logger['instance']->adminJS();
695
- }
696
- }
697
- }// End if().
698
-
699
  }
700
 
701
  /**
@@ -705,75 +825,69 @@ class SimpleHistory {
705
  * Examples:
706
  * http://playground-root.ep/wp-admin/admin-ajax.php?action=simple_history_api&posts_per_page=5&paged=1&format=html
707
  */
708
- public function api() {
709
-
710
  global $wpdb;
711
 
712
  // Fake slow answers
713
  // sleep(2);
714
  // sleep(rand(0,3));
715
  $args = $_GET;
716
- unset( $args['action'] );
717
 
718
  // Type = overview | ...
719
- $type = isset( $_GET['type'] ) ? $_GET['type'] : null;
720
-
721
- if ( empty( $args ) || ! $type ) {
722
-
723
- wp_send_json_error(
724
- array(
725
- _x( 'Not enough args specified', 'API: not enought arguments passed', 'simple-history' ),
 
726
  )
727
- );
728
-
729
  }
730
 
731
  // User must have capability to view the history page
732
- if ( ! current_user_can( $this->get_view_history_capability() ) ) {
733
- wp_send_json_error(
734
- array(
735
- 'error' => 'CAPABILITY_ERROR',
736
- )
737
- );
738
  }
739
 
740
- if ( isset( $args['id'] ) ) {
741
- $args['post__in'] = array(
742
- $args['id'],
743
- );
744
  }
745
 
746
  $data = array();
747
 
748
- switch ( $type ) {
749
-
750
  case 'overview':
751
  case 'occasions':
752
  case 'single':
753
  // API use SimpleHistoryLogQuery, so simply pass args on to that
754
  $logQuery = new SimpleHistoryLogQuery();
755
- $data = $logQuery->query( $args );
756
 
757
  $data['api_args'] = $args;
758
 
759
  // Output can be array or HMTL
760
- if ( isset( $args['format'] ) && 'html' === $args['format'] ) {
761
-
762
  $data['log_rows_raw'] = array();
763
 
764
- foreach ( $data['log_rows'] as $key => $oneLogRow ) {
765
-
766
  $args = array();
767
- if ( $type == 'single' ) {
768
  $args['type'] = 'single';
769
  }
770
 
771
- $data['log_rows'][ $key ] = $this->getLogRowHTMLOutput( $oneLogRow, $args );
 
 
 
772
  $data['num_queries'] = get_num_queries();
773
-
774
  }
775
  } else {
776
-
777
  // $data["logRows"] = $logRows;
778
  }
779
 
@@ -781,11 +895,9 @@ class SimpleHistory {
781
 
782
  default:
783
  $data[] = 'Nah.';
 
784
 
785
- }// End switch().
786
-
787
- wp_send_json_success( $data );
788
-
789
  }
790
 
791
  /**
@@ -793,41 +905,42 @@ class SimpleHistory {
793
  * to the untranslated text too, because that's the version we want to store
794
  * in the database.
795
  */
796
- public function filter_gettext( $translated_text, $untranslated_text, $domain ) {
797
-
798
- if ( isset( $this->doFilterGettext ) && $this->doFilterGettext ) {
799
-
 
 
800
  $this->doFilterGettext_currentLogger->messages[] = array(
801
  'untranslated_text' => $untranslated_text,
802
  'translated_text' => $translated_text,
803
  'domain' => $domain,
804
- 'context' => null,
805
  );
806
-
807
  }
808
 
809
  return $translated_text;
810
-
811
  }
812
 
813
  /**
814
  * Store messages with context
815
  */
816
- public function filter_gettext_with_context( $translated_text, $untranslated_text, $context, $domain ) {
817
-
818
- if ( isset( $this->doFilterGettext ) && $this->doFilterGettext ) {
819
-
 
 
 
820
  $this->doFilterGettext_currentLogger->messages[] = array(
821
  'untranslated_text' => $untranslated_text,
822
  'translated_text' => $translated_text,
823
  'domain' => $domain,
824
- 'context' => $context,
825
  );
826
-
827
  }
828
 
829
  return $translated_text;
830
-
831
  }
832
 
833
  /**
@@ -837,29 +950,34 @@ class SimpleHistory {
837
  *
838
  * @since 2.0
839
  */
840
- public function load_plugin_textdomain() {
841
-
842
  $domain = 'simple-history';
843
 
844
  // The "plugin_locale" filter is also used in load_plugin_textdomain()
845
- $locale = apply_filters( 'plugin_locale', get_locale(), $domain );
846
- load_textdomain( $domain, WP_LANG_DIR . '/simple-history/' . $domain . '-' . $locale . '.mo' );
847
- load_plugin_textdomain( $domain, false, dirname( $this->plugin_basename ) . '/languages/' );
848
-
 
 
 
 
 
 
849
  }
850
 
851
  /**
852
  * Setup variables and things
853
  */
854
- public function setup_variables() {
855
-
856
  $this->externalLoggers = array();
857
  $this->externalDropins = array();
858
  $this->instantiatedLoggers = array();
859
  $this->instantiatedDropins = array();
860
 
861
  $this->plugin_basename = SIMPLE_HISTORY_BASENAME;
862
-
863
  }
864
 
865
  /**
@@ -868,14 +986,19 @@ class SimpleHistory {
868
  * @since 2.1.5
869
  * @return string capability
870
  */
871
- public function get_view_history_capability() {
872
-
873
  $view_history_capability = 'edit_pages';
874
- $view_history_capability = apply_filters( 'simple_history_view_history_capability', $view_history_capability );
875
- $view_history_capability = apply_filters( 'simple_history/view_history_capability', $view_history_capability );
 
 
 
 
 
 
876
 
877
  return $view_history_capability;
878
-
879
  }
880
 
881
  /**
@@ -884,14 +1007,19 @@ class SimpleHistory {
884
  * @since 2.1.5
885
  * @return string capability
886
  */
887
- public function get_view_settings_capability() {
888
-
889
  $view_settings_capability = 'manage_options';
890
- $view_settings_capability = apply_filters( 'simple_history_view_settings_capability', $view_settings_capability );
891
- $view_settings_capability = apply_filters( 'simple_history/view_settings_capability', $view_settings_capability );
 
 
 
 
 
 
892
 
893
  return $view_settings_capability;
894
-
895
  }
896
 
897
  /**
@@ -900,8 +1028,12 @@ class SimpleHistory {
900
  * @since 2.19
901
  * @return bool
902
  */
903
- public function user_can_clear_log() {
904
- $user_can_clear_log = apply_filters( 'simple_history/user_can_clear_log', true );
 
 
 
 
905
 
906
  return $user_can_clear_log;
907
  }
@@ -909,39 +1041,36 @@ class SimpleHistory {
909
  /**
910
  * Adds default tabs to settings
911
  */
912
- public function add_default_settings_tabs() {
913
-
914
  // Add default settings tabs
915
  $this->arr_settings_tabs = array(
916
-
917
  array(
918
  'slug' => 'settings',
919
- 'name' => __( 'Settings', 'simple-history' ),
920
- 'function' => array( $this, 'settings_output_general' ),
921
- ),
922
-
923
  );
924
 
925
- if ( defined( 'SIMPLE_HISTORY_DEV' ) && SIMPLE_HISTORY_DEV ) {
926
-
927
  $arr_dev_tabs = array(
928
  array(
929
  'slug' => 'log',
930
- 'name' => __( 'Log (debug)', 'simple-history' ),
931
- 'function' => array( $this, 'settings_output_log' ),
932
  ),
933
  array(
934
  'slug' => 'styles-example',
935
- 'name' => __( 'Styles example (debug)', 'simple-history' ),
936
- 'function' => array( $this, 'settings_output_styles_example' ),
937
- ),
938
-
939
  );
940
 
941
- $this->arr_settings_tabs = array_merge( $this->arr_settings_tabs, $arr_dev_tabs );
942
-
 
 
943
  }
944
-
945
  }
946
 
947
  /**
@@ -952,10 +1081,9 @@ class SimpleHistory {
952
  *
953
  * @since 2.1
954
  */
955
- function register_logger( $loggerClassName ) {
956
-
957
  $this->externalLoggers[] = $loggerClassName;
958
-
959
  }
960
 
961
  /**
@@ -966,18 +1094,17 @@ class SimpleHistory {
966
  *
967
  * @since 2.1
968
  */
969
- function register_dropin( $dropinClassName ) {
970
-
971
  $this->externalDropins[] = $dropinClassName;
972
-
973
  }
974
 
975
  /**
976
  * Load built in loggers from all files in /loggers
977
  * and instantiates them
978
  */
979
- public function load_loggers() {
980
-
981
  $loggersDir = SIMPLE_HISTORY_PATH . 'loggers/';
982
 
983
  $loggersFiles = array(
@@ -1009,6 +1136,7 @@ class SimpleHistory {
1009
  $loggersDir . 'Plugin_Redirection.php',
1010
  $loggersDir . 'Plugin_DuplicatePost.php',
1011
  $loggersDir . 'Plugin_ACF.php',
 
1012
  );
1013
 
1014
  // SimpleLogger.php must be loaded first and always since the other loggers extend it.
@@ -1025,20 +1153,22 @@ class SimpleHistory {
1025
  *
1026
  * @param array $loggersFiles Array with filenames
1027
  */
1028
- $loggersFiles = apply_filters( 'simple_history/loggers_files', $loggersFiles );
 
 
 
1029
 
1030
  // Array with slug of loggers to instantiate.
1031
  // Slug of logger must also be the name of the logger class.
1032
  $arr_loggers_to_instantiate = array();
1033
 
1034
  // $one_logger_file = "SimpleCommentsLogger.php", "class-privacy-logger.php", and so on.
1035
- foreach ( $loggersFiles as $one_logger_file ) {
1036
-
1037
  $load_logger = true;
1038
 
1039
  // SimpleCommentsLogger.php -> SimpleCommentsLogger.
1040
  // class-privacy-logger.php -> class-privacy-logger.
1041
- $basename_no_suffix = basename( $one_logger_file, '.php' );
1042
 
1043
  /**
1044
  * Filter to completely skip loading of a logger
@@ -1048,22 +1178,25 @@ class SimpleHistory {
1048
  * @param bool if to load the logger. return false to not load it.
1049
  * @param string basename of logger, i.e. "SimpleCommentsLogger" or "class-privacy-logger"
1050
  */
1051
- $load_logger = apply_filters( 'simple_history/logger/load_logger', $load_logger, $basename_no_suffix );
 
 
 
 
1052
 
1053
  // If logger was SimpleLogger then force it to be loaded because for example
1054
  // custom extended plugins added later probably depends on it.
1055
- if ( 'SimpleLogger' === $basename_no_suffix ) {
1056
  $load_logger = true;
1057
  }
1058
 
1059
- if ( ! $load_logger ) {
1060
  continue;
1061
  }
1062
 
1063
  include_once $one_logger_file;
1064
 
1065
  $arr_loggers_to_instantiate[] = $basename_no_suffix;
1066
-
1067
  }
1068
 
1069
  /**
@@ -1074,9 +1207,12 @@ class SimpleHistory {
1074
  *
1075
  * @param SimpleHistory instance
1076
  */
1077
- do_action( 'simple_history/add_custom_logger', $this );
1078
 
1079
- $arr_loggers_to_instantiate = array_merge( $arr_loggers_to_instantiate, $this->externalLoggers );
 
 
 
1080
 
1081
  /**
1082
  * Filter the array with names of loggers to instantiate.
@@ -1085,45 +1221,54 @@ class SimpleHistory {
1085
  * (
1086
  * [0] => SimpleCommentsLogger
1087
  * [1] => SimpleCoreUpdatesLogger
1088
- * ...
1089
- * )
1090
  *
1091
  * @since 2.0
1092
  *
1093
  * @param array $arr_loggers_to_instantiate Array with class names
1094
  */
1095
- $arr_loggers_to_instantiate = apply_filters( 'simple_history/loggers_to_instantiate', $arr_loggers_to_instantiate );
 
 
 
1096
 
1097
  // Instantiate each logger.
1098
- foreach ( $arr_loggers_to_instantiate as $one_logger_name ) {
1099
-
1100
  // Detect logger class name.
1101
  $logger_class_name = null;
1102
 
1103
- if ( class_exists( $one_logger_name ) ) {
1104
  // Logger name is "SimpleCommentsLogger".
1105
  $logger_class_name = $one_logger_name;
1106
  } else {
1107
  // Check if class is "class-privacy-logger".
1108
- $logger_snaked_name = substr( $one_logger_name, 6 );
1109
  // "privacy-logger" -> "privacy_logger" -> Privacy_Logger
1110
- $logger_snaked_name = str_replace( '-', '_', $logger_snaked_name );
1111
- $logger_snaked_name = sh_ucwords( $logger_snaked_name, '_' );
 
 
 
 
1112
 
1113
- if ( class_exists( $logger_snaked_name ) ) {
1114
  $logger_class_name = $logger_snaked_name;
1115
  }
1116
  }
1117
 
1118
  // Continue to load next logger if no valid logger class found.
1119
- if ( ! $logger_class_name ) {
1120
  continue;
1121
  }
1122
 
1123
  // Init found logger class.
1124
- $logger_instance = new $logger_class_name( $this );
1125
 
1126
- if ( ! is_subclass_of( $logger_instance, 'SimpleLogger' ) && ! is_a( $logger_instance, 'SimpleLogger' ) ) {
 
 
 
1127
  continue;
1128
  }
1129
 
@@ -1137,8 +1282,11 @@ class SimpleHistory {
1137
 
1138
  // Check so no logger has a logger slug with more than 30 chars,
1139
  // because db column is only 30 chars.
1140
- if ( strlen( $logger_instance->slug ) > 30 ) {
1141
- add_action( 'admin_notices', array( $this, 'admin_notice_logger_slug_to_long' ) );
 
 
 
1142
  }
1143
 
1144
  // Un-tell gettext filter.
@@ -1151,14 +1299,28 @@ class SimpleHistory {
1151
 
1152
  $arr_messages_by_message_key = array();
1153
 
1154
- if ( isset( $logger_info['messages'] ) ) {
1155
-
1156
- foreach ( (array) $logger_info['messages'] as $message_key => $message_translated ) {
1157
-
 
 
 
 
1158
  // Find message in array with both translated and non translated strings.
1159
- foreach ( $logger_instance->messages as $one_message_with_translation_info ) {
1160
- if ( $message_translated == $one_message_with_translation_info['translated_text'] ) {
1161
- $arr_messages_by_message_key[ $message_key ] = $one_message_with_translation_info;
 
 
 
 
 
 
 
 
 
 
1162
  continue;
1163
  }
1164
  }
@@ -1168,23 +1330,21 @@ class SimpleHistory {
1168
  $logger_instance->messages = $arr_messages_by_message_key;
1169
 
1170
  // Add logger to array of loggers.
1171
- $this->instantiatedLoggers[ $logger_instance->slug ] = array(
1172
  'name' => $logger_info['name'],
1173
- 'instance' => $logger_instance,
1174
  );
 
1175
 
1176
- }// End foreach().
1177
-
1178
- do_action( 'simple_history/loggers_loaded' );
1179
-
1180
  }
1181
 
1182
  /**
1183
  * Load built in dropins from all files in /dropins
1184
  * and instantiates them
1185
  */
1186
- public function load_dropins() {
1187
-
1188
  $dropinsDir = SIMPLE_HISTORY_PATH . 'dropins/';
1189
 
1190
  $dropinsFiles = array(
@@ -1201,7 +1361,7 @@ class SimpleHistory {
1201
  $dropinsDir . 'SimpleHistorySidebarDropin.php',
1202
  $dropinsDir . 'SimpleHistorySidebarStats.php',
1203
  $dropinsDir . 'SimpleHistorySidebarSettings.php',
1204
- $dropinsDir . 'SimpleHistoryWPCLIDropin.php',
1205
  );
1206
 
1207
  /**
@@ -1213,14 +1373,16 @@ class SimpleHistory {
1213
  *
1214
  * @param array $dropinsFiles Array with filenames
1215
  */
1216
- $dropinsFiles = apply_filters( 'simple_history/dropins_files', $dropinsFiles );
 
 
 
1217
 
1218
  $arrDropinsToInstantiate = array();
1219
 
1220
- foreach ( $dropinsFiles as $oneDropinFile ) {
1221
-
1222
  // path/path/simplehistory/dropins/SimpleHistoryDonateDropin.php => SimpleHistoryDonateDropin
1223
- $oneDropinFileBasename = basename( $oneDropinFile, '.php' );
1224
 
1225
  $load_dropin = true;
1226
 
@@ -1233,7 +1395,10 @@ class SimpleHistory {
1233
  *
1234
  * @param bool if to load the dropin. return false to not load it.
1235
  */
1236
- $load_dropin = apply_filters( "simple_history/dropin/load_dropin_{$oneDropinFileBasename}", $load_dropin );
 
 
 
1237
 
1238
  /**
1239
  * Filter to completely skip loading of a dropin
@@ -1243,17 +1408,20 @@ class SimpleHistory {
1243
  * @param bool if to load the dropin. return false to not load it.
1244
  * @param string slug of dropin
1245
  */
1246
- $load_dropin = apply_filters( 'simple_history/dropin/load_dropin', $load_dropin, $oneDropinFileBasename );
 
 
 
 
1247
 
1248
- if ( ! $load_dropin ) {
1249
  continue;
1250
  }
1251
 
1252
  include_once $oneDropinFile;
1253
 
1254
  $arrDropinsToInstantiate[] = $oneDropinFileBasename;
1255
-
1256
- }// End foreach().
1257
 
1258
  /**
1259
  * Action that dropins can use to add their custom loggers.
@@ -1263,7 +1431,7 @@ class SimpleHistory {
1263
  *
1264
  * @param array $arrDropinsToInstantiate Array with class names
1265
  */
1266
- do_action( 'simple_history/add_custom_dropin', $this );
1267
 
1268
  /**
1269
  * Filter the array with names of dropin to instantiate.
@@ -1272,24 +1440,27 @@ class SimpleHistory {
1272
  *
1273
  * @param array $arrDropinsToInstantiate Array with class names
1274
  */
1275
- $arrDropinsToInstantiate = apply_filters( 'simple_history/dropins_to_instantiate', $arrDropinsToInstantiate );
 
 
 
1276
 
1277
- $arrDropinsToInstantiate = array_merge( $arrDropinsToInstantiate, $this->externalDropins );
 
 
 
1278
 
1279
  // Instantiate each dropin
1280
- foreach ( $arrDropinsToInstantiate as $oneDropinName ) {
1281
-
1282
- if ( ! class_exists( $oneDropinName ) ) {
1283
  continue;
1284
  }
1285
 
1286
- $this->instantiatedDropins[ $oneDropinName ] = array(
1287
  'name' => $oneDropinName,
1288
- 'instance' => new $oneDropinName( $this ),
1289
  );
1290
-
1291
  }
1292
-
1293
  }
1294
 
1295
  /**
@@ -1298,9 +1469,9 @@ class SimpleHistory {
1298
  *
1299
  * @return int
1300
  */
1301
- function get_pager_size() {
1302
-
1303
- $pager_size = get_option( 'simple_history_pager_size', 20 );
1304
 
1305
  /**
1306
  * Filter the pager size setting
@@ -1309,13 +1480,11 @@ class SimpleHistory {
1309
  *
1310
  * @param int $pager_size
1311
  */
1312
- $pager_size = apply_filters( 'simple_history/pager_size', $pager_size );
1313
 
1314
  return $pager_size;
1315
-
1316
  }
1317
 
1318
-
1319
  /**
1320
  * Gets the pager size,
1321
  * i.e. the number of items to show on each page in the history
@@ -1323,9 +1492,9 @@ class SimpleHistory {
1323
  * @since 2.12
1324
  * @return int
1325
  */
1326
- function get_pager_size_dashboard() {
1327
-
1328
- $pager_size = get_option( 'simple_history_pager_size_dashboard', 5 );
1329
 
1330
  /**
1331
  * Filter the pager size setting
@@ -1334,33 +1503,42 @@ class SimpleHistory {
1334
  *
1335
  * @param int $pager_size
1336
  */
1337
- $pager_size = apply_filters( 'simple_history/pager_size_dashboard', $pager_size );
 
 
 
1338
 
1339
  return $pager_size;
1340
-
1341
  }
1342
 
1343
  /**
1344
  * Show a link to our settings page on the Plugins -> Installed Plugins screen
1345
  */
1346
- function plugin_action_links( $actions, $b, $c, $d ) {
1347
-
1348
  // Only add link if user has the right to view the settings page
1349
- if ( ! current_user_can( $this->get_view_settings_capability() ) ) {
1350
  return $actions;
1351
  }
1352
 
1353
- $settings_page_url = menu_page_url( SimpleHistory::SETTINGS_MENU_SLUG, 0 );
 
 
 
1354
 
1355
- if ( empty( $actions ) ) { // Create array if actions is empty (and therefore is assumed to be a string by PHP & results in PHP 7.1+ fatal error due to trying to make array modifications on what's assumed to be a string)
 
1356
  $actions = array();
1357
- } elseif ( is_string( $actions ) ) { // Convert the string (which it might've been retrieved as) to an array for future use as an array
1358
- $actions = array( $actions );
 
1359
  }
1360
- $actions[] = "<a href='$settings_page_url'>" . __( 'Settings', 'simple-history' ) . '</a>';
 
 
 
1361
 
1362
  return $actions;
1363
-
1364
  }
1365
 
1366
  /**
@@ -1368,10 +1546,12 @@ class SimpleHistory {
1368
  * requires current user to have view history capability
1369
  * and a setting to show dashboard to be set
1370
  */
1371
- function add_dashboard_widget() {
1372
-
1373
- if ( $this->setting_show_on_dashboard() && current_user_can( $this->get_view_history_capability() ) ) {
1374
-
 
 
1375
  /**
1376
  * Filter to determine if history page should be added to page below dashboard or not
1377
  *
@@ -1379,10 +1559,17 @@ class SimpleHistory {
1379
  *
1380
  * @param bool Show the page or not
1381
  */
1382
- $show_dashboard_widget = apply_filters( 'simple_history/show_dashboard_widget', true );
 
 
 
1383
 
1384
- if ( $show_dashboard_widget ) {
1385
- wp_add_dashboard_widget( 'simple_history_dashboard_widget', __( 'Simple History', 'simple-history' ), array( $this, 'dashboard_widget_output' ) );
 
 
 
 
1386
  }
1387
  }
1388
  }
@@ -1390,8 +1577,8 @@ class SimpleHistory {
1390
  /**
1391
  * Output html for the dashboard widget
1392
  */
1393
- function dashboard_widget_output() {
1394
-
1395
  $pager_size = $this->get_pager_size_dashboard();
1396
 
1397
  /**
@@ -1401,38 +1588,47 @@ class SimpleHistory {
1401
  *
1402
  * @param int $pager_size
1403
  */
1404
- $pager_size = apply_filters( 'simple_history/dashboard_pager_size', $pager_size );
1405
-
1406
- do_action( 'simple_history/dashboard/before_gui', $this );
 
1407
 
 
1408
  ?>
1409
  <div class="SimpleHistoryGui"
1410
  data-pager-size='<?php echo $pager_size; ?>'
1411
  ></div>
1412
  <?php
1413
-
1414
  }
1415
 
1416
- function is_on_our_own_pages( $hook = '' ) {
1417
-
1418
  $current_screen = get_current_screen();
1419
 
1420
- if ( $current_screen && $current_screen->base == 'settings_page_' . SimpleHistory::SETTINGS_MENU_SLUG ) {
1421
-
 
 
 
1422
  return true;
1423
-
1424
- } elseif ( $current_screen && $current_screen->base == 'dashboard_page_simple_history_page' ) {
1425
-
 
1426
  return true;
1427
-
1428
- } elseif ( ( $hook == 'settings_page_' . SimpleHistory::SETTINGS_MENU_SLUG ) || ( $this->setting_show_on_dashboard() && $hook == 'index.php' ) || ( $this->setting_show_as_page() && $hook == 'dashboard_page_simple_history_page' ) ) {
1429
-
 
 
 
1430
  return true;
1431
-
1432
- } elseif ( $current_screen && $current_screen->base == 'dashboard' && $this->setting_show_on_dashboard() ) {
1433
-
 
 
1434
  return true;
1435
-
1436
  }
1437
 
1438
  return false;
@@ -1443,63 +1639,133 @@ class SimpleHistory {
1443
  *
1444
  * Only adds scripts to pages where the log is shown or the settings page.
1445
  */
1446
- function enqueue_admin_scripts( $hook ) {
1447
-
1448
- if ( $this->is_on_our_own_pages() ) {
1449
-
1450
  add_thickbox();
1451
 
1452
- wp_enqueue_style( 'simple_history_styles', SIMPLE_HISTORY_DIR_URL . 'css/styles.css', false, SIMPLE_HISTORY_VERSION );
1453
- wp_enqueue_script( 'simple_history_script', SIMPLE_HISTORY_DIR_URL . 'js/scripts.js', array( 'jquery', 'backbone', 'wp-util' ), SIMPLE_HISTORY_VERSION, true );
 
 
 
 
 
 
 
 
 
 
 
1454
 
1455
- wp_enqueue_script( 'select2', SIMPLE_HISTORY_DIR_URL . 'js/select2/select2.full.min.js', array( 'jquery' ) );
1456
- wp_enqueue_style( 'select2', SIMPLE_HISTORY_DIR_URL . 'js/select2/select2.min.css' );
 
 
 
 
 
 
 
1457
 
1458
  // Translations that we use in JavaScript
1459
  wp_localize_script(
1460
- 'simple_history_script', 'simple_history_script_vars', array(
1461
- 'settingsConfirmClearLog' => __( 'Remove all log items?', 'simple-history' ),
 
 
 
 
 
1462
  'pagination' => array(
1463
- 'goToTheFirstPage' => __( 'Go to the first page', 'simple-history' ),
1464
- 'goToThePrevPage' => __( 'Go to the previous page', 'simple-history' ),
1465
- 'goToTheNextPage' => __( 'Go to the next page', 'simple-history' ),
1466
- 'goToTheLastPage' => __( 'Go to the last page', 'simple-history' ),
1467
- 'currentPage' => __( 'Current page', 'simple-history' ),
 
 
 
 
 
 
 
 
 
 
 
 
1468
  ),
1469
- 'loadLogAPIError' => __( 'Oups, the log could not be loaded right now.', 'simple-history' ),
1470
- 'ajaxLoadError' => __( 'Hm, the log could not be loaded right now. Perhaps another plugin is giving some errors. Anyway, below is the output I got from the server.', 'simple-history' ),
1471
- 'logNoHits' => __( 'Your search did not match any history events.', 'simple-history' ),
 
 
 
 
 
 
 
 
 
1472
  )
1473
  );
1474
 
1475
  // Call plugins adminCSS-method, so they can add their CSS
1476
- foreach ( $this->instantiatedLoggers as $one_logger ) {
1477
- if ( method_exists( $one_logger['instance'], 'adminCSS' ) ) {
1478
  $one_logger['instance']->adminCSS();
1479
  }
1480
  }
1481
 
1482
  // Add timeago.js
1483
- wp_enqueue_script( 'timeago', SIMPLE_HISTORY_DIR_URL . 'js/timeago/jquery.timeago.js', array( 'jquery' ), '1.5.2', true );
 
 
 
 
 
 
1484
 
1485
  // Determine current locale to load timeago locale
1486
- $locale = strtolower( substr( get_locale(), 0, 2 ) );
1487
- $locale_url_path = SIMPLE_HISTORY_DIR_URL . 'js/timeago/locales/jquery.timeago.%s.js';
1488
- $locale_dir_path = SIMPLE_HISTORY_PATH . 'js/timeago/locales/jquery.timeago.%s.js';
 
 
 
1489
 
1490
  // Only enqueue if locale-file exists on file system
1491
- if ( file_exists( sprintf( $locale_dir_path, $locale ) ) ) {
1492
- wp_enqueue_script( 'timeago-locale', sprintf( $locale_url_path, $locale ), array( 'jquery' ), '1.5.2', true );
 
 
 
 
 
 
1493
  } else {
1494
- wp_enqueue_script( 'timeago-locale', sprintf( $locale_url_path, 'en' ), array( 'jquery' ), '1.5.2', true );
 
 
 
 
 
 
1495
  }
1496
  // end add timeago
1497
  // Load Select2 locale
1498
  $locale_url_path = SIMPLE_HISTORY_DIR_URL . 'js/select2/i18n/%s.js';
1499
  $locale_dir_path = SIMPLE_HISTORY_PATH . 'js/select2/i18n/%s.js';
1500
 
1501
- if ( file_exists( sprintf( $locale_dir_path, $locale ) ) ) {
1502
- wp_enqueue_script( 'select2-locale', sprintf( $locale_url_path, $locale ), array( 'jquery' ), '3.5.1', true );
 
 
 
 
 
 
1503
  }
1504
 
1505
  /**
@@ -1510,13 +1776,12 @@ class SimpleHistory {
1510
  *
1511
  * @param SimpleHistory $SimpleHistory This class.
1512
  */
1513
- do_action( 'simple_history/enqueue_admin_scripts', $this );
1514
-
1515
- }// End if().
1516
-
1517
  }
1518
 
1519
- function filter_option_page_capability( $capability ) {
 
1520
  return $capability;
1521
  }
1522
 
@@ -1524,11 +1789,11 @@ class SimpleHistory {
1524
  * Check if plugin version have changed, i.e. has been upgraded
1525
  * If upgrade is detected then maybe modify database and so on for that version
1526
  */
1527
- function check_for_upgrade() {
1528
-
1529
  global $wpdb;
1530
 
1531
- $db_version = get_option( 'simple_history_db_version' );
1532
  $table_name = $wpdb->prefix . SimpleHistory::DBTABLE;
1533
  $table_name_contexts = $wpdb->prefix . SimpleHistory::DBTABLE_CONTEXTS;
1534
  $first_install = false;
@@ -1537,47 +1802,46 @@ class SimpleHistory {
1537
  // is a version of Simple History < 0.4
1538
  // or it's a first install
1539
  // Fix database not using UTF-8
1540
- if ( false === $db_version || intval( $db_version ) == 0 ) {
1541
-
1542
  require_once ABSPATH . 'wp-admin/includes/upgrade.php';
1543
 
1544
  // Table creation, used to be in register_activation_hook
1545
  // We change the varchar size to add one num just to force update of encoding. dbdelta didn't see it otherwise.
1546
- $sql = 'CREATE TABLE ' . $table_name . ' (
 
 
 
1547
  id bigint(20) NOT NULL AUTO_INCREMENT,
1548
  date datetime NOT NULL,
1549
  PRIMARY KEY (id)
1550
  ) CHARACTER SET=utf8;';
1551
 
1552
  // Upgrade db / fix utf for varchars
1553
- dbDelta( $sql );
1554
 
1555
  // Fix UTF-8 for table
1556
- $sql = sprintf( 'alter table %1$s charset=utf8;', $table_name );
1557
- $wpdb->query( $sql );
1558
 
1559
  $db_version_prev = $db_version;
1560
  $db_version = 1;
1561
 
1562
- update_option( 'simple_history_db_version', $db_version );
1563
 
1564
  // We are not 100% sure that this is a first install,
1565
  // but it is at least a very old version that is being updated
1566
  $first_install = true;
1567
-
1568
  } // End if().
1569
 
1570
  // If db version is 1 then upgrade to 2
1571
  // Version 2 added the action_description column
1572
- if ( 1 == intval( $db_version ) ) {
1573
-
1574
  // V2 used to add column "action_description"
1575
  // but it's not used any more so don't do i
1576
  $db_version_prev = $db_version;
1577
  $db_version = 2;
1578
 
1579
- update_option( 'simple_history_db_version', $db_version );
1580
-
1581
  }
1582
 
1583
  // Check that all options we use are set to their defaults, if they miss value
@@ -1585,21 +1849,21 @@ class SimpleHistory {
1585
  $arr_options = array(
1586
  array(
1587
  'name' => 'simple_history_show_as_page',
1588
- 'default_value' => 1,
1589
  ),
1590
  array(
1591
  'name' => 'simple_history_show_on_dashboard',
1592
- 'default_value' => 1,
1593
- ),
1594
  );
1595
 
1596
- foreach ( $arr_options as $one_option ) {
1597
-
1598
- if ( false === ( $option_value = get_option( $one_option['name'] ) ) ) {
1599
-
1600
  // Value is not set in db, so set it to a default
1601
- update_option( $one_option['name'], $one_option['default_value'] );
1602
-
 
 
1603
  }
1604
  }
1605
 
@@ -1610,8 +1874,7 @@ class SimpleHistory {
1610
  *
1611
  * @since 2.0
1612
  */
1613
- if ( 2 == intval( $db_version ) ) {
1614
-
1615
  require_once ABSPATH . 'wp-admin/includes/upgrade.php';
1616
 
1617
  // Update old table
@@ -1629,7 +1892,7 @@ class SimpleHistory {
1629
  KEY loggerdate (logger,date)
1630
  ) CHARSET=utf8;";
1631
 
1632
- dbDelta( $sql );
1633
 
1634
  // Add context table
1635
  $sql = "
@@ -1644,11 +1907,11 @@ class SimpleHistory {
1644
  ) CHARSET=utf8;
1645
  ";
1646
 
1647
- $wpdb->query( $sql );
1648
 
1649
  $db_version_prev = $db_version;
1650
  $db_version = 3;
1651
- update_option( 'simple_history_db_version', $db_version );
1652
 
1653
  // Update possible old items to use SimpleLegacyLogger
1654
  $sql = sprintf(
@@ -1662,12 +1925,14 @@ class SimpleHistory {
1662
  $table_name
1663
  );
1664
 
1665
- $wpdb->query( $sql );
1666
 
1667
  // Say welcome, however loggers are not added this early so we need to
1668
  // use a filter to load it later
1669
- add_action( 'simple_history/loggers_loaded', array( $this, 'addWelcomeLogMessage' ) );
1670
-
 
 
1671
  } // End if().
1672
 
1673
  /**
@@ -1678,16 +1943,14 @@ class SimpleHistory {
1678
  *
1679
  * @since 2.0
1680
  */
1681
- if ( 3 == intval( $db_version ) ) {
1682
-
1683
  require_once ABSPATH . 'wp-admin/includes/upgrade.php';
1684
 
1685
  // If old columns exist = this is an old install, then modify the columns so we still can keep them
1686
  // we want to keep them because user may have logged items that they want to keep
1687
- $db_cools = $wpdb->get_col( "DESCRIBE $table_name" );
1688
-
1689
- if ( in_array( 'action', $db_cools ) ) {
1690
 
 
1691
  $sql = sprintf(
1692
  '
1693
  ALTER TABLE %1$s
@@ -1700,36 +1963,28 @@ class SimpleHistory {
1700
  ',
1701
  $table_name
1702
  );
1703
- $wpdb->query( $sql );
1704
-
1705
  }
1706
 
1707
  $db_version_prev = $db_version;
1708
  $db_version = 4;
1709
 
1710
- update_option( 'simple_history_db_version', $db_version );
1711
-
1712
  } // End if().
1713
 
1714
  // Some installs on 2.2.2 got failed installs
1715
  // We detect these by checking for db_version and then running the install stuff again
1716
- if ( 4 == intval( $db_version ) ) {
1717
-
1718
- if ( ! $this->does_database_have_data() ) {
1719
-
1720
  // not ok, decrease db number so installs will run again and hopefully fix things
1721
  $db_version = 0;
1722
-
1723
  } else {
1724
  // all looks ok, upgrade to db version 5, so this part is not done again
1725
  $db_version = 5;
1726
-
1727
  }
1728
 
1729
- update_option( 'simple_history_db_version', $db_version );
1730
-
1731
  }
1732
-
1733
  } // end check_for_upgrade
1734
 
1735
  /**
@@ -1738,8 +1993,8 @@ class SimpleHistory {
1738
  * @since 2.1.6
1739
  * @return bool True if database is not empty, false if database is empty = contains no data
1740
  */
1741
- function does_database_have_data() {
1742
-
1743
  global $wpdb;
1744
 
1745
  $tableprefix = $wpdb->prefix;
@@ -1748,10 +2003,9 @@ class SimpleHistory {
1748
  $simple_history_context_table = SimpleHistory::DBTABLE_CONTEXTS;
1749
 
1750
  $sql_data_exists = "SELECT id AS id_exists FROM {$tableprefix}{$simple_history_table} LIMIT 1";
1751
- $data_exists = (bool) $wpdb->get_var( $sql_data_exists, 0 );
1752
 
1753
  return $data_exists;
1754
-
1755
  }
1756
 
1757
  /**
@@ -1759,67 +2013,68 @@ class SimpleHistory {
1759
  * Is only called after database has been upgraded, so only on first install (or upgrade).
1760
  * Not called after only plugin activation.
1761
  */
1762
- public function addWelcomeLogMessage() {
1763
-
1764
  $db_data_exists = $this->does_database_have_data();
1765
  // $db_data_exists = false;
1766
- $pluginLogger = $this->getInstantiatedLoggerBySlug( 'SimplePluginLogger' );
1767
- if ( $pluginLogger ) {
1768
-
 
1769
  // Add plugin installed message
1770
  $context = array(
1771
  'plugin_name' => 'Simple History',
1772
- 'plugin_description' => 'Plugin that logs various things that occur in WordPress and then presents those events in a very nice GUI.',
 
1773
  'plugin_url' => 'http://simple-history.com',
1774
  'plugin_version' => SIMPLE_HISTORY_VERSION,
1775
- 'plugin_author' => 'Pär Thernström',
1776
  );
1777
 
1778
- $pluginLogger->infoMessage( 'plugin_installed', $context );
1779
 
1780
  // Add plugin activated message
1781
  $context['plugin_slug'] = 'simple-history';
1782
- $context['plugin_title'] = '<a href="http://simple-history.com/">Simple History</a>';
1783
-
1784
- $pluginLogger->infoMessage( 'plugin_activated', $context );
1785
 
 
1786
  }
1787
 
1788
- if ( ! $db_data_exists ) {
1789
-
1790
- $welcome_message_1 = __('
1791
  Welcome to Simple History!
1792
 
1793
  This is the main history feed. It will contain events that this plugin has logged.
1794
- ', 'simple-history');
 
 
1795
 
1796
- $welcome_message_2 = __('
 
1797
  Because Simple History was just recently installed, this feed does not contain much events yet. But keep the plugin activated and soon you will see detailed information about page edits, plugin updates, user logins, and much more.
1798
- ', 'simple-history');
1799
-
1800
- SimpleLogger()->info(
1801
- $welcome_message_2,
1802
- array(
1803
- '_initiator' => SimpleLoggerLogInitiators::WORDPRESS,
1804
- )
1805
  );
1806
 
1807
- SimpleLogger()->info(
1808
- $welcome_message_1,
1809
- array(
1810
- '_initiator' => SimpleLoggerLogInitiators::WORDPRESS,
1811
- )
1812
- );
1813
 
 
 
 
1814
  }
1815
-
1816
  }
1817
 
1818
- public function registerSettingsTab( $arr_tab_settings ) {
 
1819
  $this->arr_settings_tabs[] = $arr_tab_settings;
1820
  }
1821
 
1822
- public function getSettingsTabs() {
 
1823
  return $this->arr_settings_tabs;
1824
  }
1825
 
@@ -1827,101 +2082,91 @@ Because Simple History was just recently installed, this feed does not contain m
1827
  * Output HTML for the settings page
1828
  * Called from add_options_page
1829
  */
1830
- function settings_page_output() {
1831
- $arr_settings_tabs = $this->getSettingsTabs();
1832
- ?>
1833
  <div class="wrap">
1834
 
1835
  <h1 class="SimpleHistoryPageHeadline">
1836
  <div class="dashicons dashicons-backup SimpleHistoryPageHeadline__icon"></div>
1837
- <?php _e( 'Simple History Settings', 'simple-history' ); ?>
1838
  </h1>
1839
 
1840
  <?php
1841
- $active_tab = isset( $_GET['selected-tab'] ) ? $_GET['selected-tab'] : 'settings';
1842
- $settings_base_url = menu_page_url( SimpleHistory::SETTINGS_MENU_SLUG, 0 );
1843
- ?>
 
 
1844
 
1845
  <h2 class="nav-tab-wrapper">
1846
- <?php
1847
- foreach ( $arr_settings_tabs as $one_tab ) {
1848
-
1849
- $tab_slug = $one_tab['slug'];
1850
-
1851
- printf(
1852
- '<a href="%3$s" class="nav-tab %4$s">%1$s</a>',
1853
- $one_tab['name'], // 1
1854
- $tab_slug, // 2
1855
- esc_url( add_query_arg( 'selected-tab', $tab_slug, $settings_base_url ) ), // 3
1856
- $active_tab == $tab_slug ? 'nav-tab-active' : ''// 4
1857
- );
1858
-
1859
- }
1860
- ?>
1861
  </h2>
1862
 
1863
  <?php
 
 
 
 
 
1864
 
1865
- // Output contents for selected tab
1866
- $arr_active_tab = wp_filter_object_list(
1867
- $arr_settings_tabs, array(
1868
- 'slug' => $active_tab,
1869
- )
1870
- );
1871
- $arr_active_tab = current( $arr_active_tab );
1872
 
1873
- // We must have found an active tab and it must have a callable function
1874
- if ( ! $arr_active_tab || ! is_callable( $arr_active_tab['function'] ) ) {
1875
- wp_die( __( 'No valid callback found', 'simple-history' ) );
1876
- }
1877
-
1878
- $args = array(
1879
- 'arr_active_tab' => $arr_active_tab,
1880
- );
1881
-
1882
- call_user_func_array( $arr_active_tab['function'], $args );
1883
 
1884
- ?>
1885
 
1886
  </div>
1887
  <?php
1888
-
1889
  }
1890
 
1891
- public function settings_output_log() {
1892
-
1893
  include SIMPLE_HISTORY_PATH . 'templates/settings-log.php';
1894
-
1895
  }
1896
 
1897
- public function settings_output_general() {
1898
-
1899
  include SIMPLE_HISTORY_PATH . 'templates/settings-general.php';
1900
-
1901
  }
1902
 
1903
- public function settings_output_styles_example() {
1904
-
1905
  include SIMPLE_HISTORY_PATH . 'templates/settings-style-example.php';
1906
-
1907
  }
1908
 
1909
  /**
1910
  * Content for section intro. Leave it be, even if empty.
1911
  * Called from add_sections_setting.
1912
  */
1913
- function settings_section_output() {
1914
-
1915
  }
1916
 
1917
  /**
1918
  * Add pages (history page and settings page)
1919
  */
1920
- function add_admin_pages() {
1921
-
1922
  // Add a history page as a sub-page below the Dashboard menu item
1923
- if ( $this->setting_show_as_page() ) {
1924
-
1925
  /**
1926
  * Filter to determine if history page should be added to page below dashboard or not
1927
  *
@@ -1929,63 +2174,90 @@ Because Simple History was just recently installed, this feed does not contain m
1929
  *
1930
  * @param bool Show the page or not
1931
  */
1932
- $show_dashboard_page = apply_filters( 'simple_history/show_dashboard_page', true );
1933
-
1934
- if ( $show_dashboard_page ) {
 
1935
 
 
1936
  add_dashboard_page(
1937
- _x( 'Simple History', 'dashboard title name', 'simple-history' ),
1938
- _x( 'Simple History', 'dashboard menu name', 'simple-history' ),
 
 
 
 
 
 
 
 
1939
  $this->get_view_history_capability(),
1940
  'simple_history_page',
1941
- array( $this, 'history_page_output' )
1942
  );
1943
-
1944
  }
1945
  }
1946
 
1947
  // Add a settings page
1948
  $show_settings_page = true;
1949
- $show_settings_page = apply_filters( 'simple_history_show_settings_page', $show_settings_page );
1950
- $show_settings_page = apply_filters( 'simple_history/show_settings_page', $show_settings_page );
1951
-
1952
- if ( $show_settings_page ) {
 
 
 
 
1953
 
 
1954
  add_options_page(
1955
- __( 'Simple History Settings', 'simple-history' ),
1956
- _x( 'Simple History', 'Options page menu title', 'simple-history' ),
 
 
 
 
1957
  $this->get_view_settings_capability(),
1958
  SimpleHistory::SETTINGS_MENU_SLUG,
1959
- array( $this, 'settings_page_output' )
1960
  );
1961
-
1962
  }
1963
-
1964
  }
1965
 
1966
  /**
1967
  * Add setting sections and settings for the settings page
1968
  * Also maybe save some settings before outputing them
1969
  */
1970
- function add_settings() {
1971
-
1972
  // Clear the log if clear button was clicked in settings.
1973
- if ( isset( $_GET['simple_history_clear_log_nonce'] ) && wp_verify_nonce( $_GET['simple_history_clear_log_nonce'], 'simple_history_clear_log' ) ) {
1974
-
1975
- if ( $this->user_can_clear_log() ) {
 
 
 
 
 
1976
  $this->clear_log();
1977
  }
1978
 
1979
- $msg = __( 'Cleared database', 'simple-history' );
1980
 
1981
- add_settings_error( 'simple_history_rss_feed_regenerate_secret', 'simple_history_rss_feed_regenerate_secret', $msg, 'updated' );
 
 
 
 
 
1982
 
1983
- set_transient( 'settings_errors', get_settings_errors(), 30 );
1984
 
1985
- $goback = esc_url_raw( add_query_arg( 'settings-updated', 'true', wp_get_referer() ) );
1986
- wp_redirect( $goback );
 
 
1987
  exit();
1988
-
1989
  }
1990
 
1991
  // Section for general options.
@@ -1994,7 +2266,7 @@ Because Simple History was just recently installed, this feed does not contain m
1994
  add_settings_section(
1995
  $settings_section_general_id,
1996
  '',
1997
- array( $this, 'settings_section_output' ),
1998
  SimpleHistory::SETTINGS_MENU_SLUG // Same slug as for options menu page.
1999
  );
2000
 
@@ -2004,58 +2276,69 @@ Because Simple History was just recently installed, this feed does not contain m
2004
  // Checkboxes for where to show simple history
2005
  add_settings_field(
2006
  'simple_history_show_where',
2007
- __( 'Show history', 'simple-history' ),
2008
- array( $this, 'settings_field_where_to_show' ),
2009
  SimpleHistory::SETTINGS_MENU_SLUG,
2010
  $settings_section_general_id
2011
  );
2012
 
2013
  // Nonces for show where inputs.
2014
- register_setting( SimpleHistory::SETTINGS_GENERAL_OPTION_GROUP, 'simple_history_show_on_dashboard' );
2015
- register_setting( SimpleHistory::SETTINGS_GENERAL_OPTION_GROUP, 'simple_history_show_as_page' );
 
 
 
 
 
 
2016
 
2017
  // Number if items to show on the history page.
2018
  add_settings_field(
2019
  'simple_history_number_of_items',
2020
- __( 'Number of items per page on the log page', 'simple-history' ),
2021
- array( $this, 'settings_field_number_of_items' ),
2022
  SimpleHistory::SETTINGS_MENU_SLUG,
2023
  $settings_section_general_id
2024
  );
2025
 
2026
  // Nonces for number of items inputs.
2027
- register_setting( SimpleHistory::SETTINGS_GENERAL_OPTION_GROUP, 'simple_history_pager_size' );
 
 
 
2028
 
2029
  // Number if items to show on dashboard.
2030
  add_settings_field(
2031
  'simple_history_number_of_items_dashboard',
2032
- __( 'Number of items per page on the dashboard', 'simple-history' ),
2033
- array( $this, 'settings_field_number_of_items_dashboard' ),
2034
  SimpleHistory::SETTINGS_MENU_SLUG,
2035
  $settings_section_general_id
2036
  );
2037
 
2038
  // Nonces for number of items inputs.
2039
- register_setting( SimpleHistory::SETTINGS_GENERAL_OPTION_GROUP, 'simple_history_pager_size_dashboard' );
 
 
 
2040
 
2041
  // Link/button to clear log.
2042
- if ( $this->user_can_clear_log() ) {
2043
  add_settings_field(
2044
  'simple_history_clear_log',
2045
- __( 'Clear log', 'simple-history' ),
2046
- array( $this, 'settings_field_clear_log' ),
2047
  SimpleHistory::SETTINGS_MENU_SLUG,
2048
  $settings_section_general_id
2049
  );
2050
  }
2051
-
2052
  }
2053
 
2054
  /**
2055
  * Output for page with the history
2056
  */
2057
- function history_page_output() {
2058
-
2059
  // global $simple_history;
2060
  // $this->purge_db();
2061
  global $wpdb;
@@ -2069,27 +2352,27 @@ Because Simple History was just recently installed, this feed does not contain m
2069
  *
2070
  * @param int $pager_size
2071
  */
2072
- $pager_size = apply_filters( 'simple_history/page_pager_size', $pager_size );
2073
-
 
 
2074
  ?>
2075
 
2076
  <div class="wrap SimpleHistoryWrap">
2077
 
2078
  <h1 class="SimpleHistoryPageHeadline">
2079
  <div class="dashicons dashicons-backup SimpleHistoryPageHeadline__icon"></div>
2080
- <?php echo _x( 'Simple History', 'history page headline', 'simple-history' ); ?>
2081
  </h1>
2082
 
2083
- <?php
2084
- /**
2085
- * Fires before the gui div
2086
- *
2087
- * @since 2.0
2088
- *
2089
- * @param SimpleHistory $SimpleHistory This class.
2090
- */
2091
- do_action( 'simple_history/history_page/before_gui', $this );
2092
- ?>
2093
 
2094
  <div class="SimpleHistoryGuiWrap">
2095
 
@@ -2097,25 +2380,20 @@ Because Simple History was just recently installed, this feed does not contain m
2097
  data-pager-size='<?php echo $pager_size; ?>'
2098
  ></div>
2099
 
2100
- <?php
2101
-
2102
- /**
2103
- * Fires after the gui div
2104
- *
2105
- * @since 2.0
2106
- *
2107
- * @param SimpleHistory $SimpleHistory This class.
2108
- */
2109
- do_action( 'simple_history/history_page/after_gui', $this );
2110
-
2111
- ?>
2112
 
2113
  </div>
2114
 
2115
  </div>
2116
 
2117
  <?php
2118
-
2119
  }
2120
 
2121
  /**
@@ -2124,12 +2402,14 @@ Because Simple History was just recently installed, this feed does not contain m
2124
  *
2125
  * @return bool
2126
  */
2127
- function setting_show_on_dashboard() {
2128
-
2129
- $show_on_dashboard = get_option( 'simple_history_show_on_dashboard', 1 );
2130
- $show_on_dashboard = apply_filters( 'simple_history_show_on_dashboard', $show_on_dashboard );
 
 
 
2131
  return (bool) $show_on_dashboard;
2132
-
2133
  }
2134
 
2135
  /**
@@ -2138,80 +2418,122 @@ Because Simple History was just recently installed, this feed does not contain m
2138
  *
2139
  * @return bool
2140
  */
2141
- function setting_show_as_page() {
2142
-
2143
- $setting = get_option( 'simple_history_show_as_page', 1 );
2144
- $setting = apply_filters( 'simple_history_show_as_page', $setting );
2145
 
2146
  return (bool) $setting;
2147
-
2148
  }
2149
 
2150
  /**
2151
  * Settings field for how many rows/items to show in log on the log page
2152
  */
2153
- function settings_field_number_of_items() {
2154
-
2155
- $current_pager_size = $this->get_pager_size();
2156
-
2157
- ?>
2158
  <select name="simple_history_pager_size">
2159
- <option <?php echo $current_pager_size == 5 ? 'selected' : ''; ?> value="5">5</option>
2160
- <option <?php echo $current_pager_size == 10 ? 'selected' : ''; ?> value="10">10</option>
2161
- <option <?php echo $current_pager_size == 15 ? 'selected' : ''; ?> value="15">15</option>
2162
- <option <?php echo $current_pager_size == 20 ? 'selected' : ''; ?> value="20">20</option>
2163
- <option <?php echo $current_pager_size == 25 ? 'selected' : ''; ?> value="25">25</option>
2164
- <option <?php echo $current_pager_size == 30 ? 'selected' : ''; ?> value="30">30</option>
2165
- <option <?php echo $current_pager_size == 40 ? 'selected' : ''; ?> value="40">40</option>
2166
- <option <?php echo $current_pager_size == 50 ? 'selected' : ''; ?> value="50">50</option>
2167
- <option <?php echo $current_pager_size == 75 ? 'selected' : ''; ?> value="75">75</option>
2168
- <option <?php echo $current_pager_size == 100 ? 'selected' : ''; ?> value="100">100</option>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2169
  </select>
2170
  <?php
2171
-
2172
  }
2173
 
2174
  /**
2175
  * Settings field for how many rows/items to show in log on the dashboard
2176
  */
2177
- function settings_field_number_of_items_dashboard() {
2178
-
2179
- $current_pager_size = $this->get_pager_size_dashboard();
2180
-
2181
- ?>
2182
  <select name="simple_history_pager_size_dashboard">
2183
- <option <?php echo $current_pager_size == 5 ? 'selected' : ''; ?> value="5">5</option>
2184
- <option <?php echo $current_pager_size == 10 ? 'selected' : ''; ?> value="10">10</option>
2185
- <option <?php echo $current_pager_size == 15 ? 'selected' : ''; ?> value="15">15</option>
2186
- <option <?php echo $current_pager_size == 20 ? 'selected' : ''; ?> value="20">20</option>
2187
- <option <?php echo $current_pager_size == 25 ? 'selected' : ''; ?> value="25">25</option>
2188
- <option <?php echo $current_pager_size == 30 ? 'selected' : ''; ?> value="30">30</option>
2189
- <option <?php echo $current_pager_size == 40 ? 'selected' : ''; ?> value="40">40</option>
2190
- <option <?php echo $current_pager_size == 50 ? 'selected' : ''; ?> value="50">50</option>
2191
- <option <?php echo $current_pager_size == 75 ? 'selected' : ''; ?> value="75">75</option>
2192
- <option <?php echo $current_pager_size == 100 ? 'selected' : ''; ?> value="100">100</option>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2193
  </select>
2194
  <?php
2195
-
2196
  }
2197
 
2198
  /**
2199
  * Settings field for where to show the log, page or dashboard
2200
  */
2201
- function settings_field_where_to_show() {
2202
-
2203
  $show_on_dashboard = $this->setting_show_on_dashboard();
2204
  $show_as_page = $this->setting_show_as_page();
2205
-
2206
  ?>
2207
 
2208
- <input <?php echo $show_on_dashboard ? "checked='checked'" : ''; ?> type="checkbox" value="1" name="simple_history_show_on_dashboard" id="simple_history_show_on_dashboard" class="simple_history_show_on_dashboard" />
2209
- <label for="simple_history_show_on_dashboard"><?php _e( 'on the dashboard', 'simple-history' ); ?></label>
 
 
 
 
 
2210
 
2211
  <br />
2212
 
2213
- <input <?php echo $show_as_page ? "checked='checked'" : ''; ?> type="checkbox" value="1" name="simple_history_show_as_page" id="simple_history_show_as_page" class="simple_history_show_as_page" />
2214
- <label for="simple_history_show_as_page"><?php _e( 'as a page under the dashboard menu', 'simple-history' ); ?></label>
 
 
 
 
 
2215
 
2216
  <?php
2217
  }
@@ -2219,23 +2541,37 @@ Because Simple History was just recently installed, this feed does not contain m
2219
  /**
2220
  * Settings section to clear database
2221
  */
2222
- function settings_field_clear_log() {
2223
-
2224
- $clear_link = esc_url( add_query_arg( '', '' ) );
2225
- $clear_link = wp_nonce_url( $clear_link, 'simple_history_clear_log', 'simple_history_clear_log_nonce' );
 
 
 
 
2226
  $clear_days = $this->get_clear_history_interval();
2227
 
2228
  echo '<p>';
2229
 
2230
- if ( $clear_days > 0 ) {
2231
- echo sprintf( __( 'Items in the database are automatically removed after %1$s days.', 'simple-history' ), $clear_days );
 
 
 
 
 
 
2232
  } else {
2233
- _e( 'Items in the database are kept forever.', 'simple-history' );
2234
  }
2235
 
2236
  echo '</p>';
2237
 
2238
- printf( '<p><a class="button js-SimpleHistory-Settings-ClearLog" href="%2$s">%1$s</a></p>', __( 'Clear log now', 'simple-history' ), $clear_link );
 
 
 
 
2239
  }
2240
 
2241
  /**
@@ -2244,8 +2580,8 @@ Because Simple History was just recently installed, this feed does not contain m
2244
  *
2245
  * @return int Number of days.
2246
  */
2247
- function get_clear_history_interval() {
2248
-
2249
  $days = 60;
2250
 
2251
  /**
@@ -2254,18 +2590,23 @@ Because Simple History was just recently installed, this feed does not contain m
2254
  *
2255
  * @param $days Number of days of history to keep
2256
  */
2257
- $days = (int) apply_filters( 'simple_history_db_purge_days_interval', $days );
2258
- $days = (int) apply_filters( 'simple_history/db_purge_days_interval', $days );
 
 
 
 
 
 
2259
 
2260
  return $days;
2261
-
2262
  }
2263
 
2264
  /**
2265
  * Removes all items from the log
2266
  */
2267
- function clear_log() {
2268
-
2269
  global $wpdb;
2270
 
2271
  $tableprefix = $wpdb->prefix;
@@ -2275,25 +2616,27 @@ Because Simple History was just recently installed, this feed does not contain m
2275
 
2276
  // Get number of rows before delete.
2277
  $sql_num_rows = "SELECT count(id) AS num_rows FROM {$tableprefix}{$simple_history_table}";
2278
- $num_rows = $wpdb->get_var( $sql_num_rows, 0 );
2279
 
2280
  // Use truncate instead of delete because it's much faster (I think, writing this much later).
2281
  $sql = "TRUNCATE {$tableprefix}{$simple_history_table}";
2282
- $wpdb->query( $sql );
2283
 
2284
  $sql = "TRUNCATE {$tableprefix}{$simple_history_context_table}";
2285
- $wpdb->query( $sql );
2286
 
2287
  // Zero state sucks
2288
  SimpleLogger()->info(
2289
- __( 'The log for Simple History was cleared ({num_rows} rows were removed).', 'simple-history' ),
 
 
 
2290
  array(
2291
- 'num_rows' => $num_rows,
2292
  )
2293
  );
2294
 
2295
- $this->get_cache_incrementor( true );
2296
-
2297
  }
2298
 
2299
  /**
@@ -2302,39 +2645,42 @@ Because Simple History was just recently installed, this feed does not contain m
2302
  *
2303
  * @since 2.0.17
2304
  */
2305
- function maybe_purge_db() {
2306
-
2307
  // How often should we try to do this?
2308
  // Once a day = a bit tiresome.
2309
  // Let's go with sundays; purge the log on sundays.
2310
  // Day of week, 1 = mon, 7 = sun.
2311
- $day_of_week = date( 'N' );
2312
- if ( 7 === (int) $day_of_week ) {
2313
-
2314
  $this->purge_db();
2315
-
2316
  }
2317
-
2318
  }
2319
 
2320
  /**
2321
  * Removes old entries from the db
2322
  */
2323
- function purge_db() {
2324
-
2325
  $do_purge_history = true;
2326
 
2327
- $do_purge_history = apply_filters( 'simple_history_allow_db_purge', $do_purge_history );
2328
- $do_purge_history = apply_filters( 'simple_history/allow_db_purge', $do_purge_history );
 
 
 
 
 
 
2329
 
2330
- if ( ! $do_purge_history ) {
2331
  return;
2332
  }
2333
 
2334
  $days = $this->get_clear_history_interval();
2335
 
2336
  // Never clear log if days = 0.
2337
- if ( 0 == $days ) {
2338
  return;
2339
  }
2340
 
@@ -2343,53 +2689,49 @@ Because Simple History was just recently installed, this feed does not contain m
2343
  $table_name = $wpdb->prefix . SimpleHistory::DBTABLE;
2344
  $table_name_contexts = $wpdb->prefix . SimpleHistory::DBTABLE_CONTEXTS;
2345
 
2346
- while( 1 > 0 ) {
2347
  // Get id of rows to delete.
2348
  $sql = $wpdb->prepare(
2349
  "SELECT id FROM $table_name WHERE DATE_ADD(date, INTERVAL %d DAY) < now() LIMIT 100000",
2350
  $days
2351
  );
2352
 
2353
- $ids_to_delete = $wpdb->get_col( $sql );
2354
 
2355
- if ( empty( $ids_to_delete ) ) {
2356
  // Nothing to delete.
2357
  return;
2358
  }
2359
 
2360
- $sql_ids_in = implode( ',', $ids_to_delete );
2361
 
2362
  // Add number of deleted rows to total_rows option.
2363
- $prev_total_rows = (int) get_option( 'simple_history_total_rows', 0 );
2364
- $total_rows = $prev_total_rows + sizeof( $ids_to_delete );
2365
- update_option( 'simple_history_total_rows', $total_rows );
2366
 
2367
  // Remove rows + contexts.
2368
  $sql_delete_history = "DELETE FROM {$table_name} WHERE id IN ($sql_ids_in)";
2369
  $sql_delete_history_context = "DELETE FROM {$table_name_contexts} WHERE history_id IN ($sql_ids_in)";
2370
 
2371
- $wpdb->query( $sql_delete_history );
2372
- $wpdb->query( $sql_delete_history_context );
2373
 
2374
  $message = _nx(
2375
  'Simple History removed one event that were older than {days} days',
2376
  'Simple History removed {num_rows} events that were older than {days} days',
2377
- count( $ids_to_delete ),
2378
  'Database is being cleared automagically',
2379
  'simple-history'
2380
  );
2381
 
2382
- SimpleLogger()->info(
2383
- $message,
2384
- array(
2385
- 'days' => $days,
2386
- 'num_rows' => count( $ids_to_delete ),
2387
- )
2388
- );
2389
 
2390
- $this->get_cache_incrementor( true );
2391
  }
2392
-
2393
  }
2394
 
2395
  /**
@@ -2400,24 +2742,27 @@ Because Simple History was just recently installed, this feed does not contain m
2400
  * @param array $row
2401
  * @return string
2402
  */
2403
- public function getLogRowPlainTextOutput( $row ) {
2404
-
2405
  $row_logger = $row->logger;
2406
  $logger = null;
2407
- $row->context = isset( $row->context ) && is_array( $row->context ) ? $row->context : array();
 
 
 
2408
 
2409
- if ( ! isset( $row->context['_message_key'] ) ) {
2410
  $row->context['_message_key'] = null;
2411
  }
2412
 
2413
  // Fallback to SimpleLogger if no logger exists for row
2414
- if ( ! isset( $this->instantiatedLoggers[ $row_logger ] ) ) {
2415
  $row_logger = 'SimpleLogger';
2416
  }
2417
 
2418
- $logger = $this->instantiatedLoggers[ $row_logger ]['instance'];
2419
 
2420
- return $logger->getLogRowPlainTextOutput( $row );
2421
  }
2422
 
2423
  /**
@@ -2431,21 +2776,23 @@ Because Simple History was just recently installed, this feed does not contain m
2431
  * @param array $row
2432
  * @return string
2433
  */
2434
- public function getLogRowHeaderOutput( $row ) {
2435
-
2436
  $row_logger = $row->logger;
2437
  $logger = null;
2438
- $row->context = isset( $row->context ) && is_array( $row->context ) ? $row->context : array();
 
 
 
2439
 
2440
  // Fallback to SimpleLogger if no logger exists for row
2441
- if ( ! isset( $this->instantiatedLoggers[ $row_logger ] ) ) {
2442
  $row_logger = 'SimpleLogger';
2443
  }
2444
 
2445
- $logger = $this->instantiatedLoggers[ $row_logger ]['instance'];
2446
-
2447
- return $logger->getLogRowHeaderOutput( $row );
2448
 
 
2449
  }
2450
 
2451
  /**
@@ -2454,38 +2801,42 @@ Because Simple History was just recently installed, this feed does not contain m
2454
  * @param array $row
2455
  * @return string
2456
  */
2457
- private function getLogRowSenderImageOutput( $row ) {
2458
-
2459
  $row_logger = $row->logger;
2460
  $logger = null;
2461
- $row->context = isset( $row->context ) && is_array( $row->context ) ? $row->context : array();
 
 
 
2462
 
2463
  // Fallback to SimpleLogger if no logger exists for row
2464
- if ( ! isset( $this->instantiatedLoggers[ $row_logger ] ) ) {
2465
  $row_logger = 'SimpleLogger';
2466
  }
2467
 
2468
- $logger = $this->instantiatedLoggers[ $row_logger ]['instance'];
2469
-
2470
- return $logger->getLogRowSenderImageOutput( $row );
2471
 
 
2472
  }
2473
 
2474
- public function getLogRowDetailsOutput( $row ) {
2475
-
2476
  $row_logger = $row->logger;
2477
  $logger = null;
2478
- $row->context = isset( $row->context ) && is_array( $row->context ) ? $row->context : array();
 
 
 
2479
 
2480
  // Fallback to SimpleLogger if no logger exists for row
2481
- if ( ! isset( $this->instantiatedLoggers[ $row_logger ] ) ) {
2482
  $row_logger = 'SimpleLogger';
2483
  }
2484
 
2485
- $logger = $this->instantiatedLoggers[ $row_logger ]['instance'];
2486
-
2487
- return $logger->getLogRowDetailsOutput( $row );
2488
 
 
2489
  }
2490
 
2491
  /**
@@ -2494,10 +2845,11 @@ Because Simple History was just recently installed, this feed does not contain m
2494
  *
2495
  * @param mixed $value array|object|string|whatever that is json_encode'able.
2496
  */
2497
- public static function json_encode( $value ) {
2498
-
2499
- return version_compare( PHP_VERSION, '5.4.0' ) >= 0 ? json_encode( $value, JSON_PRETTY_PRINT ) : json_encode( $value );
2500
-
 
2501
  }
2502
 
2503
  /**
@@ -2506,8 +2858,9 @@ Because Simple History was just recently installed, this feed does not contain m
2506
  * @param string $haystack
2507
  * @param string $needle
2508
  */
2509
- public static function ends_with( $haystack, $needle ) {
2510
- return $needle === substr( $haystack, -strlen( $needle ) );
 
2511
  }
2512
 
2513
  /**
@@ -2516,95 +2869,138 @@ Because Simple History was just recently installed, this feed does not contain m
2516
  * @param array $oneLogRow SimpleHistoryLogQuery array with data from SimpleHistoryLogQuery
2517
  * @return string
2518
  */
2519
- public function getLogRowHTMLOutput( $oneLogRow, $args ) {
2520
-
2521
  $defaults = array(
2522
- 'type' => 'overview', // or "single" to include more stuff
2523
  );
2524
 
2525
- $args = wp_parse_args( $args, $defaults );
2526
 
2527
- $header_html = $this->getLogRowHeaderOutput( $oneLogRow );
2528
- $plain_text_html = $this->getLogRowPlainTextOutput( $oneLogRow );
2529
- $sender_image_html = $this->getLogRowSenderImageOutput( $oneLogRow );
2530
 
2531
  // Details = for example thumbnail of media
2532
- $details_html = trim( $this->getLogRowDetailsOutput( $oneLogRow ) );
2533
- if ( $details_html ) {
2534
-
2535
  $details_html = sprintf(
2536
  '<div class="SimpleHistoryLogitem__details">%1$s</div>',
2537
  $details_html
2538
  );
2539
-
2540
  }
2541
 
2542
  // subsequentOccasions = including the current one
2543
  $occasions_count = $oneLogRow->subsequentOccasions - 1;
2544
  $occasions_html = '';
2545
 
2546
- if ( $occasions_count > 0 ) {
2547
-
2548
  $occasions_html = '<div class="SimpleHistoryLogitem__occasions">';
2549
 
2550
- $occasions_html .= '<a href="#" class="SimpleHistoryLogitem__occasionsLink">';
 
2551
  $occasions_html .= sprintf(
2552
- _n( '+%1$s similar event', '+%1$s similar events', $occasions_count, 'simple-history' ),
 
 
 
 
 
2553
  $occasions_count
2554
  );
2555
  $occasions_html .= '</a>';
2556
 
2557
- $occasions_html .= '<span class="SimpleHistoryLogitem__occasionsLoading">';
 
2558
  $occasions_html .= sprintf(
2559
- __( 'Loading…', 'simple-history' ),
2560
  $occasions_count
2561
  );
2562
  $occasions_html .= '</span>';
2563
 
2564
- $occasions_html .= '<span class="SimpleHistoryLogitem__occasionsLoaded">';
 
2565
  $occasions_html .= sprintf(
2566
- __( 'Showing %1$s more', 'simple-history' ),
2567
  $occasions_count
2568
  );
2569
  $occasions_html .= '</span>';
2570
 
2571
  $occasions_html .= '</div>';
2572
-
2573
  }
2574
 
2575
  // Add data atributes to log row, so plugins can do stuff
2576
  $data_attrs = '';
2577
- $data_attrs .= sprintf( ' data-row-id="%1$d" ', $oneLogRow->id );
2578
- $data_attrs .= sprintf( ' data-occasions-count="%1$d" ', $occasions_count );
2579
- $data_attrs .= sprintf( ' data-occasions-id="%1$s" ', esc_attr( $oneLogRow->occasionsID ) );
 
 
 
 
 
 
2580
 
2581
- if ( isset( $oneLogRow->context['_server_remote_addr'] ) ) {
2582
- $data_attrs .= sprintf( ' data-ip-address="%1$s" ', esc_attr( $oneLogRow->context['_server_remote_addr'] ) );
 
 
 
2583
  }
2584
 
2585
- $arr_found_additional_ip_headers = $this->instantiatedLoggers['SimpleLogger']['instance']->get_event_ip_number_headers( $oneLogRow );
2586
- if ( $arr_found_additional_ip_headers ) {
2587
- $data_attrs .= sprintf( ' data-ip-address-multiple="1" ' );
 
 
2588
  }
2589
 
2590
- $data_attrs .= sprintf( ' data-logger="%1$s" ', esc_attr( $oneLogRow->logger ) );
2591
- $data_attrs .= sprintf( ' data-level="%1$s" ', esc_attr( $oneLogRow->level ) );
2592
- $data_attrs .= sprintf( ' data-date="%1$s" ', esc_attr( $oneLogRow->date ) );
2593
- $data_attrs .= sprintf( ' data-initiator="%1$s" ', esc_attr( $oneLogRow->initiator ) );
 
 
 
 
 
 
 
 
 
 
 
 
2594
 
2595
- if ( isset( $oneLogRow->context['_user_id'] ) ) {
2596
- $data_attrs .= sprintf( ' data-initiator-user-id="%1$d" ', $oneLogRow->context['_user_id'] );
 
 
 
2597
  }
2598
 
2599
  // If type is single then include more details
2600
  $more_details_html = '';
2601
- if ( $args['type'] == 'single' ) {
2602
-
2603
- $more_details_html = apply_filters( 'simple_history/log_html_output_details_single/html_before_context_table', $more_details_html, $oneLogRow );
 
 
 
2604
 
2605
- $more_details_html .= sprintf( '<h2 class="SimpleHistoryLogitem__moreDetailsHeadline">%1$s</h2>', __( 'Context data', 'simple-history' ) );
2606
- $more_details_html .= '<p>' . __( 'This is potentially useful meta data that a logger has saved.', 'simple-history' ) . '</p>';
2607
- $more_details_html .= "<table class='SimpleHistoryLogitem__moreDetailsContext'>";
 
 
 
 
 
 
 
 
 
 
2608
  $more_details_html .= sprintf(
2609
  '<tr>
2610
  <th>%1$s</th>
@@ -2614,27 +3010,34 @@ Because Simple History was just recently installed, this feed does not contain m
2614
  'Value'
2615
  );
2616
 
2617
- $logRowKeysToShow = array_fill_keys( array_keys( (array) $oneLogRow ), true );
 
 
 
2618
 
2619
  /**
2620
  * Filter what keys to show from oneLogRow
2621
  *
2622
  * Array is in format
2623
  *
2624
- * Array
2625
- * (
2626
- * [id] => 1
2627
- * [logger] => 1
2628
- * [level] => 1
2629
- * ...
2630
- * )
2631
  *
2632
  * @since 2.0.29
2633
  *
2634
  * @param array with keys to show. key to show = key. value = boolean to show or not.
2635
  * @param object log row to show details from
2636
  */
2637
- $logRowKeysToShow = apply_filters( 'simple_history/log_html_output_details_table/row_keys_to_show', $logRowKeysToShow, $oneLogRow );
 
 
 
 
2638
 
2639
  // Hide some keys by default
2640
  unset(
@@ -2647,15 +3050,17 @@ Because Simple History was just recently installed, this feed does not contain m
2647
  $logRowKeysToShow['type']
2648
  );
2649
 
2650
- foreach ( $oneLogRow as $rowKey => $rowVal ) {
2651
-
2652
  // Only columns from oneLogRow that exist in logRowKeysToShow will be outputed
2653
- if ( ! array_key_exists( $rowKey, $logRowKeysToShow ) || ! $logRowKeysToShow[ $rowKey ] ) {
 
 
 
2654
  continue;
2655
  }
2656
 
2657
  // skip arrays and objects and such
2658
- if ( is_array( $rowVal ) || is_object( $rowVal ) ) {
2659
  continue;
2660
  }
2661
 
@@ -2664,13 +3069,15 @@ Because Simple History was just recently installed, this feed does not contain m
2664
  <td>%1$s</td>
2665
  <td>%2$s</td>
2666
  </tr>',
2667
- esc_html( $rowKey ),
2668
- esc_html( $rowVal )
2669
  );
2670
-
2671
  }
2672
 
2673
- $logRowContextKeysToShow = array_fill_keys( array_keys( (array) $oneLogRow->context ), true );
 
 
 
2674
 
2675
  /**
2676
  * Filter what keys to show from the row context
@@ -2685,20 +3092,26 @@ Because Simple History was just recently installed, this feed does not contain m
2685
  * [plugin_description] => 1
2686
  * [plugin_author] => 1
2687
  * [plugin_version] => 1
2688
- * ...
2689
- * )
2690
  *
2691
  * @since 2.0.29
2692
  *
2693
  * @param array with keys to show. key to show = key. value = boolean to show or not.
2694
  * @param object log row to show details from
2695
  */
2696
- $logRowContextKeysToShow = apply_filters( 'simple_history/log_html_output_details_table/context_keys_to_show', $logRowContextKeysToShow, $oneLogRow );
2697
-
2698
- foreach ( $oneLogRow->context as $contextKey => $contextVal ) {
 
 
2699
 
 
2700
  // Only columns from context that exist in logRowContextKeysToShow will be outputed
2701
- if ( ! array_key_exists( $contextKey, $logRowContextKeysToShow ) || ! $logRowContextKeysToShow[ $contextKey ] ) {
 
 
 
2702
  continue;
2703
  }
2704
 
@@ -2707,35 +3120,38 @@ Because Simple History was just recently installed, this feed does not contain m
2707
  <td>%1$s</td>
2708
  <td>%2$s</td>
2709
  </tr>',
2710
- esc_html( $contextKey ),
2711
- esc_html( $contextVal )
2712
  );
2713
-
2714
  }
2715
 
2716
  $more_details_html .= '</table>';
2717
 
2718
- $more_details_html = apply_filters( 'simple_history/log_html_output_details_single/html_after_context_table', $more_details_html, $oneLogRow );
 
 
 
 
2719
 
2720
  $more_details_html = sprintf(
2721
  '<div class="SimpleHistoryLogitem__moreDetails">%1$s</div>',
2722
  $more_details_html
2723
  );
2724
-
2725
- }// End if().
2726
 
2727
  // Classes to add to log item li element
2728
  $classes = array(
2729
  'SimpleHistoryLogitem',
2730
  "SimpleHistoryLogitem--loglevel-{$oneLogRow->level}",
2731
- "SimpleHistoryLogitem--logger-{$oneLogRow->logger}",
2732
  );
2733
 
2734
- if ( isset( $oneLogRow->initiator ) && ! empty( $oneLogRow->initiator ) ) {
2735
- $classes[] = 'SimpleHistoryLogitem--initiator-' . $oneLogRow->initiator;
 
2736
  }
2737
 
2738
- if ( $arr_found_additional_ip_headers ) {
2739
  $classes[] = 'SimpleHistoryLogitem--IPAddress-multiple';
2740
  }
2741
 
@@ -2743,7 +3159,7 @@ Because Simple History was just recently installed, this feed does not contain m
2743
  $log_level_tag_html = sprintf(
2744
  ' <span class="SimpleHistoryLogitem--logleveltag SimpleHistoryLogitem--logleveltag-%1$s">%2$s</span>',
2745
  $oneLogRow->level,
2746
- $this->getLogLevelTranslated( $oneLogRow->level )
2747
  );
2748
 
2749
  $plain_text_html .= $log_level_tag_html;
@@ -2755,7 +3171,10 @@ Because Simple History was just recently installed, this feed does not contain m
2755
  *
2756
  * @param $classes Array with classes
2757
  */
2758
- $classes = apply_filters( 'simple_history/logrowhtmloutput/classes', $classes );
 
 
 
2759
 
2760
  // Generate the HTML output for a row
2761
  $output = sprintf(
@@ -2782,7 +3201,7 @@ Because Simple History was just recently installed, this feed does not contain m
2782
  $oneLogRow->logger, // 7
2783
  $data_attrs, // 8 data attributes
2784
  $more_details_html, // 9
2785
- esc_attr( join( ' ', $classes ) ) // 10
2786
  );
2787
 
2788
  // Get the main message row.
@@ -2792,8 +3211,7 @@ Because Simple History was just recently installed, this feed does not contain m
2792
  // Get detailed HTML-based output
2793
  // May include images, lists, any cool stuff needed to view
2794
  // SimpleLoggerFormatter::getRowHTMLOutput($oneLogRow);
2795
- return trim( $output );
2796
-
2797
  }
2798
 
2799
  /**
@@ -2803,119 +3221,175 @@ Because Simple History was just recently installed, this feed does not contain m
2803
  * @param string $loglevel
2804
  * @return string translated loglevel
2805
  */
2806
- function getLogLevelTranslated( $loglevel ) {
2807
-
2808
  $str_translated = '';
2809
 
2810
- switch ( $loglevel ) {
2811
-
2812
  // Lowercase
2813
  case 'emergency':
2814
- $str_translated = _x( 'emergency', 'Log level in gui', 'simple-history' );
 
 
 
 
2815
  break;
2816
 
2817
  case 'alert':
2818
- $str_translated = _x( 'alert', 'Log level in gui', 'simple-history' );
 
 
 
 
2819
  break;
2820
 
2821
  case 'critical':
2822
- $str_translated = _x( 'critical', 'Log level in gui', 'simple-history' );
 
 
 
 
2823
  break;
2824
 
2825
  case 'error':
2826
- $str_translated = _x( 'error', 'Log level in gui', 'simple-history' );
 
 
 
 
2827
  break;
2828
 
2829
  case 'warning':
2830
- $str_translated = _x( 'warning', 'Log level in gui', 'simple-history' );
 
 
 
 
2831
  break;
2832
 
2833
  case 'notice':
2834
- $str_translated = _x( 'notice', 'Log level in gui', 'simple-history' );
 
 
 
 
2835
  break;
2836
 
2837
  case 'info':
2838
- $str_translated = _x( 'info', 'Log level in gui', 'simple-history' );
 
 
 
 
2839
  break;
2840
 
2841
  case 'debug':
2842
- $str_translated = _x( 'debug', 'Log level in gui', 'simple-history' );
 
 
 
 
2843
  break;
2844
 
2845
  // Uppercase
2846
  case 'Emergency':
2847
- $str_translated = _x( 'Emergency', 'Log level in gui', 'simple-history' );
 
 
 
 
2848
  break;
2849
 
2850
  case 'Alert':
2851
- $str_translated = _x( 'Alert', 'Log level in gui', 'simple-history' );
 
 
 
 
2852
  break;
2853
 
2854
  case 'Critical':
2855
- $str_translated = _x( 'Critical', 'Log level in gui', 'simple-history' );
 
 
 
 
2856
  break;
2857
 
2858
  case 'Error':
2859
- $str_translated = _x( 'Error', 'Log level in gui', 'simple-history' );
 
 
 
 
2860
  break;
2861
 
2862
  case 'Warning':
2863
- $str_translated = _x( 'Warning', 'Log level in gui', 'simple-history' );
 
 
 
 
2864
  break;
2865
 
2866
  case 'Notice':
2867
- $str_translated = _x( 'Notice', 'Log level in gui', 'simple-history' );
 
 
 
 
2868
  break;
2869
 
2870
  case 'Info':
2871
- $str_translated = _x( 'Info', 'Log level in gui', 'simple-history' );
 
 
 
 
2872
  break;
2873
 
2874
  case 'Debug':
2875
- $str_translated = _x( 'Debug', 'Log level in gui', 'simple-history' );
 
 
 
 
2876
  break;
2877
 
2878
  default:
2879
  $str_translated = $loglevel;
2880
-
2881
- }// End switch().
2882
 
2883
  return $str_translated;
2884
-
2885
  }
2886
 
2887
- public function getInstantiatedLoggers() {
2888
-
2889
  return $this->instantiatedLoggers;
2890
-
2891
  }
2892
 
2893
- public function getInstantiatedDropins() {
2894
-
2895
  return $this->instantiatedDropins;
2896
-
2897
  }
2898
 
2899
-
2900
  /**
2901
  * @param string $slug
2902
  * @return mixed logger instance if found, bool false if logger not found
2903
  */
2904
- public function getInstantiatedLoggerBySlug( $slug = '' ) {
2905
-
2906
- if ( empty( $slug ) ) {
2907
  return false;
2908
  }
2909
 
2910
- foreach ( $this->getInstantiatedLoggers() as $one_logger ) {
2911
-
2912
- if ( $slug == $one_logger['instance']->slug ) {
2913
  return $one_logger['instance'];
2914
  }
2915
  }
2916
 
2917
  return false;
2918
-
2919
  }
2920
 
2921
  /**
@@ -2926,24 +3400,28 @@ Because Simple History was just recently installed, this feed does not contain m
2926
  * @param string $format format to return loggers in. Default is array. Can also be "sql"
2927
  * @return array
2928
  */
2929
- public function getLoggersThatUserCanRead( $user_id = '', $format = 'array' ) {
2930
-
2931
  $arr_loggers_user_can_view = array();
2932
 
2933
- if ( ! is_numeric( $user_id ) ) {
2934
  $user_id = get_current_user_id();
2935
  }
2936
 
2937
  $loggers = $this->getInstantiatedLoggers();
2938
- foreach ( $loggers as $one_logger ) {
2939
-
2940
  $logger_capability = $one_logger['instance']->getCapability();
2941
 
2942
  // $arr_loggers_user_can_view = apply_filters("simple_history/loggers_user_can_read", $user_id, $arr_loggers_user_can_view);
2943
- $user_can_read_logger = user_can( $user_id, $logger_capability );
2944
- $user_can_read_logger = apply_filters( 'simple_history/loggers_user_can_read/can_read_single_logger', $user_can_read_logger, $one_logger['instance'], $user_id );
 
 
 
 
 
2945
 
2946
- if ( $user_can_read_logger ) {
2947
  $arr_loggers_user_can_view[] = $one_logger;
2948
  }
2949
  }
@@ -2956,41 +3434,36 @@ Because Simple History was just recently installed, this feed does not contain m
2956
  * @param array $arr_loggers_user_can_view Array with loggers that user $user_id can read
2957
  * @param int user_id ID of user to check read capability for
2958
  */
2959
- $arr_loggers_user_can_view = apply_filters( 'simple_history/loggers_user_can_read', $arr_loggers_user_can_view, $user_id );
 
 
 
 
2960
 
2961
  // just return array with slugs in parenthesis suitable for sql-where
2962
- if ( 'sql' == $format ) {
2963
-
2964
  $str_return = '(';
2965
 
2966
- if ( sizeof( $arr_loggers_user_can_view ) ) {
2967
-
2968
- foreach ( $arr_loggers_user_can_view as $one_logger ) {
2969
-
2970
  $str_return .= sprintf(
2971
  '"%1$s", ',
2972
- esc_sql( $one_logger['instance']->slug )
2973
  );
2974
-
2975
  }
2976
 
2977
- $str_return = rtrim( $str_return, ' ,' );
2978
-
2979
  } else {
2980
-
2981
  // user was not allowed to read any loggers, return in (NULL) to return nothing
2982
  $str_return .= 'NULL';
2983
-
2984
  }
2985
 
2986
  $str_return .= ')';
2987
 
2988
  return $str_return;
2989
-
2990
  }
2991
 
2992
  return $arr_loggers_user_can_view;
2993
-
2994
  }
2995
 
2996
  /**
@@ -3006,81 +3479,82 @@ Because Simple History was just recently installed, this feed does not contain m
3006
  * @param string $alt Alternative text to use in image tag. Defaults to blank
3007
  * @return string <img> tag for the user's avatar
3008
  */
3009
- function get_avatar( $email, $size = '96', $default = '', $alt = false ) {
3010
-
3011
  // WP setting for avatars is to show, so just use the built in function
3012
- if ( get_option( 'show_avatars' ) ) {
3013
-
3014
- $avatar = get_avatar( $email, $size, $default, $alt );
3015
 
3016
  return $avatar;
3017
-
3018
  } else {
3019
-
3020
  // WP setting for avatar was to not show, but we do it anyway, using the same code as get_avatar() would have used
3021
- if ( false === $alt ) {
3022
  $safe_alt = '';
3023
  } else {
3024
- $safe_alt = esc_attr( $alt );
3025
  }
3026
 
3027
- if ( ! is_numeric( $size ) ) {
3028
  $size = '96';
3029
  }
3030
 
3031
- if ( empty( $default ) ) {
3032
- $avatar_default = get_option( 'avatar_default' );
3033
- if ( empty( $avatar_default ) ) {
3034
  $default = 'mystery';
3035
  } else {
3036
  $default = $avatar_default;
3037
  }
3038
  }
3039
 
3040
- if ( ! empty( $email ) ) {
3041
- $email_hash = md5( strtolower( trim( $email ) ) );
3042
  }
3043
 
3044
- if ( is_ssl() ) {
3045
  $host = 'https://secure.gravatar.com';
3046
  } else {
3047
- if ( ! empty( $email ) ) {
3048
- $host = sprintf( 'http://%d.gravatar.com', ( hexdec( $email_hash[0] ) % 2 ) );
 
 
 
3049
  } else {
3050
  $host = 'http://0.gravatar.com';
3051
  }
3052
  }
3053
 
3054
- if ( 'mystery' == $default ) {
3055
  $default = "$host/avatar/ad516503a11cd5ca435acc9bb6523536?s={$size}";
3056
- } // End if().
3057
- elseif ( 'blank' == $default ) {
3058
- $default = $email ? 'blank' : includes_url( 'images/blank.gif' );
3059
- } elseif ( ! empty( $email ) && 'gravatar_default' == $default ) {
 
3060
  $default = '';
3061
- } elseif ( 'gravatar_default' == $default ) {
3062
  $default = "$host/avatar/?s={$size}";
3063
- } elseif ( empty( $email ) ) {
3064
  $default = "$host/avatar/?d=$default&amp;s={$size}";
3065
- } elseif ( strpos( $default, 'http://' ) === 0 ) {
3066
- $default = add_query_arg( 's', $size, $default );
3067
  }
3068
 
3069
- if ( ! empty( $email ) ) {
3070
  $out = "$host/avatar/";
3071
  $out .= $email_hash;
3072
  $out .= '?s=' . $size;
3073
- $out .= '&amp;d=' . urlencode( $default );
3074
 
3075
- $rating = get_option( 'avatar_rating' );
3076
- if ( ! empty( $rating ) ) {
3077
  $out .= "&amp;r={$rating}";
3078
  }
3079
 
3080
- $out = str_replace( '&#038;', '&amp;', esc_url( $out ) );
3081
  $avatar = "<img alt='{$safe_alt}' src='{$out}' class='avatar avatar-{$size} photo' height='{$size}' width='{$size}' />";
3082
  } else {
3083
- $out = esc_url( $default );
3084
  $avatar = "<img alt='{$safe_alt}' src='{$out}' class='avatar avatar-{$size} photo avatar-default' height='{$size}' width='{$size}' />";
3085
  }
3086
 
@@ -3096,35 +3570,41 @@ Because Simple History was just recently installed, this feed does not contain m
3096
  * @param string $alt Alternative text to use in the avatar image tag.
3097
  * Default empty.
3098
  */
3099
- $avatar = apply_filters( 'get_avatar', $avatar, $email, $size, $default, $alt );
 
 
 
 
 
 
 
3100
 
3101
  return $avatar;
3102
-
3103
  } // End if().
3104
-
3105
  }
3106
 
3107
  /**
3108
  * Quick stats above the log
3109
  * Uses filter "simple_history/history_page/before_gui" to output its contents
3110
  */
3111
- public function output_quick_stats() {
3112
-
3113
  global $wpdb;
3114
 
3115
  // Get number of events today
3116
  $logQuery = new SimpleHistoryLogQuery();
3117
- $logResults = $logQuery->query(
3118
- array(
3119
- 'posts_per_page' => 1,
3120
- 'date_from' => strtotime( 'today' ),
3121
- )
3122
- );
3123
 
3124
  $total_row_count = (int) $logResults['total_row_count'];
3125
 
3126
  // Get sql query for where to read only loggers current user is allowed to read/view
3127
- $sql_loggers_in = $this->getLoggersThatUserCanRead( get_current_user_id(), 'sql' );
 
 
 
3128
 
3129
  // Get number of users today, i.e. events with wp_user as initiator
3130
  $sql_users_today = sprintf(
@@ -3141,21 +3621,22 @@ Because Simple History was just recently installed, this feed does not contain m
3141
  AND date > "%2$s"
3142
  ',
3143
  $sql_loggers_in,
3144
- date( 'Y-m-d H:i', strtotime( 'today' ) ),
3145
  $wpdb->prefix . SimpleHistory::DBTABLE,
3146
  $wpdb->prefix . SimpleHistory::DBTABLE_CONTEXTS
3147
  );
3148
 
3149
- $cache_key = 'quick_stats_users_today_' . md5( serialize( $sql_loggers_in ) );
 
3150
  $cache_group = 'simple-history-' . $this->get_cache_incrementor();
3151
- $results_users_today = wp_cache_get( $cache_key, $cache_group );
3152
 
3153
- if ( false === $results_users_today ) {
3154
- $results_users_today = $wpdb->get_results( $sql_users_today );
3155
- wp_cache_set( $cache_key, $results_users_today, $cache_group );
3156
  }
3157
 
3158
- $count_users_today = sizeof( $results_users_today );
3159
 
3160
  // Get number of other sources (not wp_user)
3161
  $sql_other_sources_where = sprintf(
@@ -3165,12 +3646,15 @@ Because Simple History was just recently installed, this feed does not contain m
3165
  AND date > "%2$s"
3166
  ',
3167
  $sql_loggers_in,
3168
- date( 'Y-m-d H:i', strtotime( 'today' ) ),
3169
  $wpdb->prefix . SimpleHistory::DBTABLE,
3170
  $wpdb->prefix . SimpleHistory::DBTABLE_CONTEXTS
3171
  );
3172
 
3173
- $sql_other_sources_where = apply_filters( 'simple_history/quick_stats_where', $sql_other_sources_where );
 
 
 
3174
 
3175
  $sql_other_sources = sprintf(
3176
  '
@@ -3181,23 +3665,29 @@ Because Simple History was just recently installed, this feed does not contain m
3181
  %5$s
3182
  ',
3183
  $sql_loggers_in,
3184
- date( 'Y-m-d H:i', strtotime( 'today' ) ),
3185
  $wpdb->prefix . SimpleHistory::DBTABLE,
3186
  $wpdb->prefix . SimpleHistory::DBTABLE_CONTEXTS,
3187
  $sql_other_sources_where // 5
3188
  );
3189
  // sf_d($sql_other_sources, '$sql_other_sources');
3190
- $cache_key = 'quick_stats_results_other_sources_today_' . md5( serialize( $sql_other_sources ) );
3191
- $results_other_sources_today = wp_cache_get( $cache_key, $cache_group );
3192
-
3193
- if ( false === $results_other_sources_today ) {
3194
-
3195
- $results_other_sources_today = $wpdb->get_results( $sql_other_sources );
3196
- wp_cache_set( $cache_key, $results_other_sources_today, $cache_group );
3197
-
 
 
 
 
 
 
3198
  }
3199
 
3200
- $count_other_sources = sizeof( $results_other_sources_today );
3201
 
3202
  // sf_d($logResults, '$logResults');
3203
  // sf_d($results_users_today, '$sql_users_today');
@@ -3206,17 +3696,13 @@ Because Simple History was just recently installed, this feed does not contain m
3206
  <div class="SimpleHistoryQuickStats">
3207
  <p>
3208
  <?php
 
3209
 
3210
- $msg_tmpl = '';
3211
-
3212
- // No results today at all
3213
- if ( $total_row_count == 0 ) {
3214
-
3215
- $msg_tmpl = __( 'No events today so far.', 'simple-history' );
3216
-
3217
- } else {
3218
-
3219
- /*
3220
  Type of results
3221
  x1 event today from 1 user.
3222
  x1 event today from 1 source.
@@ -3228,67 +3714,107 @@ Because Simple History was just recently installed, this feed does not contain m
3228
  x4 events today from 2 users and 2 other sources.
3229
  */
3230
 
3231
- // A single event existed and was from a user
3232
- // 1 event today from 1 user.
3233
- if ( $total_row_count == 1 && $count_users_today == 1 ) {
3234
- $msg_tmpl .= __( 'One event today from one user.', 'simple-history' );
3235
- }
3236
-
3237
- // A single event existed and was from another source
3238
- // 1 event today from 1 source.
3239
- if ( $total_row_count == 1 && ! $count_users_today ) {
3240
- $msg_tmpl .= __( 'One event today from one source.', 'simple-history' );
3241
- }
3242
-
3243
- // Multiple events from a single user
3244
- // 3 events today from one user.
3245
- if ( $total_row_count > 1 && $count_users_today == 1 && ! $count_other_sources ) {
3246
- $msg_tmpl .= __( '%1$d events today from one user.', 'simple-history' );
3247
- }
3248
-
3249
- // Multiple events from only users
3250
- // 2 events today from 2 users.
3251
- if ( $total_row_count > 1 && $count_users_today == $total_row_count ) {
3252
- $msg_tmpl .= __( '%1$d events today from %2$d users.', 'simple-history' );
3253
- }
3254
-
3255
- // Multiple events from 1 single user and 1 single other source
3256
- // 2 events today from 1 user and 1 other source.
3257
- if ( $total_row_count && 1 == $count_users_today && 1 == $count_other_sources ) {
3258
- $msg_tmpl .= __( '%1$d events today from one user and one other source.', 'simple-history' );
3259
- }
3260
-
3261
- // Multiple events from multple users but from only 1 single other source
3262
- // 3 events today from 2 users and 1 other source.
3263
- if ( $total_row_count > 1 && $count_users_today > 1 && $count_other_sources == 1 ) {
3264
- $msg_tmpl .= __( '%1$d events today from one user and one other source.', 'simple-history' );
3265
- }
3266
-
3267
- // Multiple events from 1 user but from multiple other source
3268
- // 3 events today from 1 user and 2 other sources.
3269
- if ( $total_row_count > 1 && 1 == $count_users_today && $count_other_sources > 1 ) {
3270
- $msg_tmpl .= __( '%1$d events today from one user and %3$d other sources.', 'simple-history' );
3271
- }
3272
-
3273
- // Multiple events from multiple user and from multiple other sources
3274
- // 4 events today from 2 users and 2 other sources.
3275
- if ( $total_row_count > 1 && $count_users_today > 1 && $count_other_sources > 1 ) {
3276
- $msg_tmpl .= __( '%1$s events today from %2$d users and %3$d other sources.', 'simple-history' );
3277
- }
3278
- }// End if().
3279
-
3280
- // only show stats if we have something to output
3281
- if ( $msg_tmpl ) {
3282
-
3283
- printf(
3284
- $msg_tmpl,
3285
- $logResults['total_row_count'], // 1
3286
- $count_users_today, // 2
3287
- $count_other_sources // 3
3288
- );
3289
-
3290
- // Space between texts
3291
- /*
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3292
  echo " ";
3293
 
3294
  // http://playground-root.ep/wp-admin/options-general.php?page=simple_history_settings_menu_slug&selected-tab=stats
@@ -3297,14 +3823,10 @@ Because Simple History was just recently installed, this feed does not contain m
3297
  add_query_arg("selected-tab", "stats", menu_page_url(SimpleHistory::SETTINGS_MENU_SLUG, 0))
3298
  );
3299
  */
3300
-
3301
- }
3302
-
3303
- ?>
3304
  </p>
3305
  </div>
3306
  <?php
3307
-
3308
  } // output_quick_stats
3309
 
3310
  /**
@@ -3313,34 +3835,34 @@ Because Simple History was just recently installed, this feed does not contain m
3313
  * @param $refresh bool
3314
  * @return string
3315
  */
3316
- public static function get_cache_incrementor( $refresh = false ) {
3317
-
3318
  $incrementor_key = 'simple_history_incrementor';
3319
- $incrementor_value = wp_cache_get( $incrementor_key );
3320
 
3321
- if ( false === $incrementor_value || true === $refresh ) {
3322
  $incrementor_value = time();
3323
- wp_cache_set( $incrementor_key, $incrementor_value );
3324
  }
3325
 
3326
  // echo "<br>incrementor_value: $incrementor_value";
3327
  return $incrementor_value;
3328
-
3329
  }
3330
 
3331
-
3332
  // Number of rows the last n days
3333
- function get_num_events_last_n_days( $period_days = 28 ) {
3334
-
3335
- $transient_key = 'sh_' . md5( __METHOD__ . $period_days . '_2' );
3336
-
3337
- $count = get_transient( $transient_key );
3338
 
3339
- if ( false === $count ) {
3340
 
 
3341
  global $wpdb;
3342
 
3343
- $sqlStringLoggersUserCanRead = $this->getLoggersThatUserCanRead( null, 'sql' );
 
 
 
3344
 
3345
  $sql = sprintf(
3346
  '
@@ -3350,32 +3872,31 @@ Because Simple History was just recently installed, this feed does not contain m
3350
  AND logger IN %3$s
3351
  ',
3352
  $wpdb->prefix . SimpleHistory::DBTABLE,
3353
- strtotime( "-$period_days days" ),
3354
  $sqlStringLoggersUserCanRead
3355
  );
3356
 
3357
- $count = $wpdb->get_var( $sql );
3358
-
3359
- set_transient( $transient_key, $count, HOUR_IN_SECONDS );
3360
 
 
3361
  }
3362
 
3363
  return $count;
3364
-
3365
  } // get_num_events_last_n_days
3366
 
 
 
 
3367
 
3368
- function get_num_events_per_day_last_n_days( $period_days = 28 ) {
3369
-
3370
- $transient_key = 'sh_' . md5( __METHOD__ . $period_days . '_2' );
3371
-
3372
- $dates = get_transient( $transient_key );
3373
-
3374
- if ( false === $dates ) {
3375
 
 
3376
  global $wpdb;
3377
 
3378
- $sqlStringLoggersUserCanRead = $this->getLoggersThatUserCanRead( null, 'sql' );
 
 
 
3379
 
3380
  $sql = sprintf(
3381
  '
@@ -3391,80 +3912,79 @@ Because Simple History was just recently installed, this feed does not contain m
3391
  ORDER BY yearDate ASC
3392
  ',
3393
  $wpdb->prefix . SimpleHistory::DBTABLE,
3394
- strtotime( "-$period_days days" ),
3395
  $sqlStringLoggersUserCanRead
3396
  );
3397
 
3398
- $dates = $wpdb->get_results( $sql );
3399
 
3400
- set_transient( $transient_key, $dates, HOUR_IN_SECONDS );
3401
  // echo "set";exit;
3402
  } else {
3403
  // echo "get";exit;
3404
  }
3405
 
3406
  return $dates;
3407
-
3408
  } // get_num_events_per_day_for_period
3409
 
3410
  // Number of unique events the last n days
3411
- public function get_unique_events_for_days( $days = 7 ) {
3412
-
3413
  global $wpdb;
3414
 
3415
  $days = (int) $days;
3416
 
3417
  $table_name = $wpdb->prefix . SimpleHistory::DBTABLE;
3418
 
3419
- $cache_key = 'sh_' . md5( __METHOD__ . $days );
3420
-
3421
- $numEvents = get_transient( $cache_key );
3422
 
3423
- if ( false == $numEvents ) {
3424
 
 
3425
  $sql = $wpdb->prepare(
3426
  "
3427
  SELECT count( DISTINCT occasionsID )
3428
  FROM $table_name
3429
  WHERE date >= DATE_ADD(CURDATE(), INTERVAL -%d DAY)
3430
- ", $days
 
3431
  );
3432
 
3433
- $numEvents = $wpdb->get_var( $sql );
3434
-
3435
- set_transient( $cache_key, $numEvents, HOUR_IN_SECONDS );
3436
 
 
3437
  }
3438
 
3439
  return $numEvents;
3440
-
3441
  } // get_unique_events_for_days
3442
 
3443
  /**
3444
  * Output an admin notice about logger slug being to long
3445
  */
3446
- public function admin_notice_logger_slug_to_long() {
 
3447
  ?>
3448
  <div class="error notice">
3449
- <p><?php echo esc_html__( 'The slug for a logger in Simple History can be max 30 chars long.', 'simple-history' ); ?></p>
 
 
 
3450
  </div>
3451
  <?php
3452
  }
3453
-
3454
  } // class
3455
 
3456
-
3457
  /**
3458
  * Helper function with same name as the SimpleLogger-class
3459
  *
3460
  * Makes call like this possible:
3461
  * SimpleLogger()->info("This is a message sent to the log");
3462
  */
3463
- function SimpleLogger() {
3464
- return new SimpleLogger( SimpleHistory::get_instance() );
 
3465
  }
3466
 
3467
-
3468
  /**
3469
  * Add event to history table
3470
  * This is here for backwards compatibility
@@ -3472,24 +3992,23 @@ function SimpleLogger() {
3472
  * SimpleHistory()->info();
3473
  * instead
3474
  */
3475
- function simple_history_add( $args ) {
3476
-
3477
  $defaults = array(
3478
- 'action' => null,
3479
- 'object_type' => null,
3480
  'object_subtype' => null,
3481
- 'object_id' => null,
3482
- 'object_name' => null,
3483
- 'user_id' => null,
3484
- 'description' => null,
3485
  );
3486
 
3487
- $context = wp_parse_args( $args, $defaults );
3488
 
3489
  $message = "{$context["object_type"]} {$context["object_name"]} {$context["action"]}";
3490
 
3491
- SimpleLogger()->info( $message, $context );
3492
-
3493
  } // simple_history_add
3494
 
3495
  /**
@@ -3524,36 +4043,36 @@ function simple_history_add( $args ) {
3524
  * @param string|array $args Optional. Change 'title', 'title_left', and 'title_right' defaults. And leading_context_lines and trailing_context_lines.
3525
  * @return string Empty string if strings are equivalent or HTML with differences.
3526
  */
3527
- function simple_history_text_diff( $left_string, $right_string, $args = null ) {
3528
-
3529
  $defaults = array(
3530
  'title' => '',
3531
  'title_left' => '',
3532
  'title_right' => '',
3533
  'leading_context_lines' => 1,
3534
- 'trailing_context_lines' => 1,
3535
  );
3536
 
3537
- $args = wp_parse_args( $args, $defaults );
3538
 
3539
- if ( ! class_exists( 'WP_Text_Diff_Renderer_Table' ) ) {
3540
  require ABSPATH . WPINC . '/wp-diff.php';
3541
  }
3542
 
3543
- $left_string = normalize_whitespace( $left_string );
3544
- $right_string = normalize_whitespace( $right_string );
3545
 
3546
- $left_lines = explode( "\n", $left_string );
3547
- $right_lines = explode( "\n", $right_string );
3548
- $text_diff = new Text_Diff( $left_lines, $right_lines );
3549
 
3550
- $renderer = new WP_Text_Diff_Renderer_Table( $args );
3551
  $renderer->_leading_context_lines = $args['leading_context_lines'];
3552
  $renderer->_trailing_context_lines = $args['trailing_context_lines'];
3553
 
3554
- $diff = $renderer->render( $text_diff );
3555
 
3556
- if ( ! $diff ) {
3557
  return '';
3558
  }
3559
 
@@ -3562,27 +4081,28 @@ function simple_history_text_diff( $left_string, $right_string, $args = null ) {
3562
  $r .= "<div class='SimpleHistory__diff__contents' tabindex='0'>";
3563
  $r .= "<div class='SimpleHistory__diff__contentsInner'>";
3564
 
3565
- $r .= "<table class='diff SimpleHistory__diff'>\n";
3566
 
3567
- if ( ! empty( $args['show_split_view'] ) ) {
3568
- $r .= "<col class='content diffsplit left' /><col class='content diffsplit middle' /><col class='content diffsplit right' />";
 
3569
  } else {
3570
  $r .= "<col class='content' />";
3571
  }
3572
 
3573
- if ( $args['title'] || $args['title_left'] || $args['title_right'] ) {
3574
  $r .= '<thead>';
3575
  }
3576
- if ( $args['title'] ) {
3577
  $r .= "<tr class='diff-title'><th colspan='4'>$args[title]</th></tr>\n";
3578
  }
3579
- if ( $args['title_left'] || $args['title_right'] ) {
3580
  $r .= "<tr class='diff-sub-title'>\n";
3581
  $r .= "\t<td></td><th>$args[title_left]</th>\n";
3582
  $r .= "\t<td></td><th>$args[title_right]</th>\n";
3583
  $r .= "</tr>\n";
3584
  }
3585
- if ( $args['title'] || $args['title_left'] || $args['title_right'] ) {
3586
  $r .= "</thead>\n";
3587
  }
3588
 
@@ -3607,15 +4127,16 @@ function simple_history_text_diff( $left_string, $right_string, $args = null ) {
3607
  * $handler['callback'][1]
3608
  * );
3609
  */
3610
- function sh_error_log() {
3611
- foreach ( func_get_args() as $var ) {
3612
- if ( is_bool( $var ) ) {
 
3613
  $bool_string = true === $var ? 'true' : 'false';
3614
- error_log( "$bool_string (boolean value)" );
3615
- } elseif ( is_null( $var ) ) {
3616
- error_log( 'null (null value)' );
3617
  } else {
3618
- error_log( print_r( $var, true ) );
3619
  }
3620
  }
3621
  }
@@ -3637,16 +4158,21 @@ function sh_error_log() {
3637
  * @param callable $callable The callable thing to check.
3638
  * @return string Name of callable.
3639
  */
3640
- function sh_get_callable_name( $callable ) {
3641
- if ( is_string( $callable ) ) {
3642
- return trim( $callable );
3643
- } else if ( is_array( $callable ) ) {
3644
- if ( is_object( $callable[0] ) ) {
3645
- return sprintf( '%s::%s', get_class( $callable[0] ), trim( $callable[1] ) );
 
 
 
 
 
3646
  } else {
3647
- return sprintf( '%s::%s', trim( $callable[0] ), trim( $callable[1] ) );
3648
  }
3649
- } else if ( $callable instanceof Closure ) {
3650
  return 'closure';
3651
  } else {
3652
  return 'unknown';
@@ -3662,9 +4188,10 @@ function sh_get_callable_name( $callable ) {
3662
  *
3663
  * @return string with words uppercased.
3664
  */
3665
- function sh_ucwords( $str, $separator = ' ' ) {
3666
- $str = str_replace( $separator, ' ', $str );
3667
- $str = ucwords( strtolower( $str ) );
3668
- $str = str_replace( ' ', $separator, $str );
 
3669
  return $str;
3670
  }
1
  <?php
2
 
3
+ defined('ABSPATH') or die();
4
 
5
  /**
6
  * Main class for Simple History
7
  */
8
+ class SimpleHistory
9
+ {
10
  const NAME = 'Simple History';
11
 
12
  /**
69
  /** ID for the general settings section */
70
  const SETTINGS_SECTION_GENERAL_ID = 'simple_history_settings_section_general';
71
 
72
+ function __construct()
73
+ {
74
  $this->init();
 
75
  } // construct
76
 
77
  /**
78
  * @since 2.5.2
79
  */
80
+ public function init()
81
+ {
82
  /**
83
  * Fires before Simple History does it's init stuff
84
  *
86
  *
87
  * @param SimpleHistory $SimpleHistory This class.
88
  */
89
+ do_action('simple_history/before_init', $this);
90
 
91
  $this->setup_variables();
92
 
93
  // Actions and filters, ordered by order specified in codex: http://codex.wordpress.org/Plugin_API/Action_Reference
94
+ add_action('after_setup_theme', array($this, 'load_plugin_textdomain'));
95
+ add_action('after_setup_theme', array(
96
+ $this,
97
+ 'add_default_settings_tabs'
98
+ ));
99
 
100
  // Plugins and dropins are loaded using the "after_setup_theme" filter so
101
  // themes can use filters to modify the loading of them.
102
  // The drawback with this is that for example logouts done when plugins like
103
  // iThemes Security is installed is not logged, because those plugins fire wp_logout()
104
  // using filter "plugins_loaded", i.e. before simple history has loaded its filters.
105
+ add_action('after_setup_theme', array($this, 'load_loggers'));
106
+ add_action('after_setup_theme', array($this, 'load_dropins'));
107
 
108
  // Run before loading of loggers and before menu items are added.
109
+ add_action('after_setup_theme', array($this, 'check_for_upgrade'), 5);
110
 
111
+ add_action('after_setup_theme', array($this, 'setup_cron'));
112
 
113
  // Filters and actions not called during regular boot.
114
+ add_filter('gettext', array($this, 'filter_gettext'), 20, 3);
115
+ add_filter(
116
+ 'gettext_with_context',
117
+ array($this, 'filter_gettext_with_context'),
118
+ 20,
119
+ 4
120
+ );
121
 
122
+ add_filter(
123
+ 'gettext',
124
+ array($this, 'filter_gettext_storeLatestTranslations'),
125
+ 10,
126
+ 3
127
+ );
128
 
129
+ add_action(
130
+ 'admin_bar_menu',
131
+ array($this, 'add_admin_bar_network_menu_item'),
132
+ 40
133
+ );
134
+ add_action(
135
+ 'admin_bar_menu',
136
+ array($this, 'add_admin_bar_menu_item'),
137
+ 40
138
+ );
139
 
140
  /**
141
  * Filter that is used to log things, without the need to check that simple history is available
150
  *
151
  * @since 2.13
152
  */
153
+ add_filter(
154
+ 'simple_history_log',
155
+ array($this, 'on_filter_simple_history_log'),
156
+ 10,
157
+ 3
158
+ );
159
 
160
  /**
161
  * Filter to log with specific log level, for example:
164
  *
165
  * @since 2.17
166
  */
167
+ add_filter(
168
+ 'simple_history_log_emergency',
169
+ array($this, 'on_filter_simple_history_log_emergency'),
170
+ 10,
171
+ 3
172
+ );
173
+ add_filter(
174
+ 'simple_history_log_alert',
175
+ array($this, 'on_filter_simple_history_log_alert'),
176
+ 10,
177
+ 2
178
+ );
179
+ add_filter(
180
+ 'simple_history_log_critical',
181
+ array($this, 'on_filter_simple_history_log_critical'),
182
+ 10,
183
+ 2
184
+ );
185
+ add_filter(
186
+ 'simple_history_log_error',
187
+ array($this, 'on_filter_simple_history_log_error'),
188
+ 10,
189
+ 2
190
+ );
191
+ add_filter(
192
+ 'simple_history_log_warning',
193
+ array($this, 'on_filter_simple_history_log_warning'),
194
+ 10,
195
+ 2
196
+ );
197
+ add_filter(
198
+ 'simple_history_log_notice',
199
+ array($this, 'on_filter_simple_history_log_notice'),
200
+ 10,
201
+ 2
202
+ );
203
+ add_filter(
204
+ 'simple_history_log_info',
205
+ array($this, 'on_filter_simple_history_log_info'),
206
+ 10,
207
+ 2
208
+ );
209
+ add_filter(
210
+ 'simple_history_log_debug',
211
+ array($this, 'on_filter_simple_history_log_debug'),
212
+ 10,
213
+ 2
214
+ );
215
 
216
+ if (is_admin()) {
217
  $this->add_admin_actions();
 
218
  }
219
 
220
  /**
224
  *
225
  * @param SimpleHistory $SimpleHistory This class.
226
  */
227
+ do_action('simple_history/after_init', $this);
228
 
229
  // Add some extra info to each logged context when SIMPLE_HISTORY_LOG_DEBUG is set and true
230
+ if (defined('SIMPLE_HISTORY_LOG_DEBUG') && SIMPLE_HISTORY_LOG_DEBUG) {
 
231
  add_filter(
232
+ 'simple_history/log_argument/context',
233
+ function ($context, $level, $message, $logger) {
234
  $sh = SimpleHistory::get_instance();
235
+ $context['_debug_get'] = $sh->json_encode($_GET);
236
+ $context['_debug_post'] = $sh->json_encode($_POST);
237
+ $context['_debug_server'] = $sh->json_encode($_SERVER);
238
+ $context['_debug_files'] = $sh->json_encode($_FILES);
239
  $context['_debug_php_sapi_name'] = php_sapi_name();
240
 
241
  global $argv;
242
+ $context['_debug_argv'] = $sh->json_encode($argv);
243
 
244
+ $consts = get_defined_constants(true);
245
  $consts = $consts['user'];
246
+ $context['_debug_user_constants'] = $sh->json_encode(
247
+ $consts
248
+ );
249
 
250
+ $postdata = file_get_contents('php://input');
251
+ $context['_debug_http_raw_post_data'] = $sh->json_encode(
252
+ $postdata
253
+ );
254
 
255
+ $context[
256
+ '_debug_wp_debug_backtrace_summary'
257
+ ] = wp_debug_backtrace_summary();
258
+ $context['_debug_is_admin'] = json_encode(is_admin());
259
+ $context['_debug_is_ajax'] = json_encode(
260
+ defined('DOING_AJAX') && DOING_AJAX
261
+ );
262
+ $context['_debug_is_doing_cron'] = json_encode(
263
+ defined('DOING_CRON') && DOING_CRON
264
+ );
265
 
266
  global $wp_current_filter;
267
+ $context[
268
+ '_debug_current_filter_array'
269
+ ] = $wp_current_filter;
270
  $context['_debug_current_filter'] = current_filter();
271
 
272
  return $context;
273
+ },
274
+ 10,
275
+ 4
276
  );
 
277
  }
 
278
  }
279
 
280
  /**
287
  * @param array $context Optional context to add to the logged data.
288
  * @param string $level The loglevel. Must be one of the existing ones. Defaults to "info".
289
  */
290
+ public function on_filter_simple_history_log(
291
+ $message = null,
292
+ $context = null,
293
+ $level = 'info'
294
+ ) {
295
+ SimpleLogger()->log($level, $message, $context);
296
  }
297
 
298
  /**
301
  * @param string $message The message to log.
302
  * @param array $context The context (optional).
303
  */
304
+ public function on_filter_simple_history_log_emergency(
305
+ $message = null,
306
+ $context = null
307
+ ) {
308
+ SimpleLogger()->log('emergency', $message, $context);
309
  }
310
 
311
  /**
314
  * @param string $message The message to log.
315
  * @param array $context The context (optional).
316
  */
317
+ public function on_filter_simple_history_log_alert(
318
+ $message = null,
319
+ $context = null
320
+ ) {
321
+ SimpleLogger()->log('alert', $message, $context);
322
  }
323
 
324
  /**
327
  * @param string $message The message to log.
328
  * @param array $context The context (optional).
329
  */
330
+ public function on_filter_simple_history_log_critical(
331
+ $message = null,
332
+ $context = null
333
+ ) {
334
+ SimpleLogger()->log('critical', $message, $context);
335
  }
336
 
337
  /**
340
  * @param string $message The message to log.
341
  * @param array $context The context (optional).
342
  */
343
+ public function on_filter_simple_history_log_error(
344
+ $message = null,
345
+ $context = null
346
+ ) {
347
+ SimpleLogger()->log('error', $message, $context);
348
  }
349
 
350
  /**
353
  * @param string $message The message to log.
354
  * @param array $context The context (optional).
355
  */
356
+ public function on_filter_simple_history_log_warning(
357
+ $message = null,
358
+ $context = null
359
+ ) {
360
+ SimpleLogger()->log('warning', $message, $context);
361
  }
362
 
363
  /**
366
  * @param string $message The message to log.
367
  * @param array $context The context (optional).
368
  */
369
+ public function on_filter_simple_history_log_notice(
370
+ $message = null,
371
+ $context = null
372
+ ) {
373
+ SimpleLogger()->log('notice', $message, $context);
374
  }
375
 
376
  /**
379
  * @param string $message The message to log.
380
  * @param array $context The context (optional).
381
  */
382
+ public function on_filter_simple_history_log_info(
383
+ $message = null,
384
+ $context = null
385
+ ) {
386
+ SimpleLogger()->log('info', $message, $context);
387
  }
388
 
389
  /**
392
  * @param string $message The message to log.
393
  * @param array $context The context (optional).
394
  */
395
+ public function on_filter_simple_history_log_debug(
396
+ $message = null,
397
+ $context = null
398
+ ) {
399
+ SimpleLogger()->log('debug', $message, $context);
400
  }
401
 
402
  /**
403
  * @since 2.5.2
404
  */
405
+ private function add_admin_actions()
406
+ {
407
+ add_action('admin_menu', array($this, 'add_admin_pages'));
408
+ add_action('admin_menu', array($this, 'add_settings'));
409
+
410
+ add_action('admin_footer', array($this, 'add_js_templates'));
411
+
412
+ add_action('wp_dashboard_setup', array($this, 'add_dashboard_widget'));
413
+
414
+ add_action('admin_enqueue_scripts', array(
415
+ $this,
416
+ 'enqueue_admin_scripts'
417
+ ));
418
+
419
+ add_action('admin_head', array($this, 'onAdminHead'));
420
+ add_action('admin_footer', array($this, 'onAdminFooter'));
421
+
422
+ add_action('simple_history/history_page/before_gui', array(
423
+ $this,
424
+ 'output_quick_stats'
425
+ ));
426
+ add_action('simple_history/dashboard/before_gui', array(
427
+ $this,
428
+ 'output_quick_stats'
429
+ ));
430
+
431
+ add_action('wp_ajax_simple_history_api', array($this, 'api'));
432
+
433
+ add_filter(
434
+ 'plugin_action_links_simple-history/index.php',
435
+ array($this, 'plugin_action_links'),
436
+ 10,
437
+ 4
438
+ );
439
  }
440
 
441
  /**
445
  *
446
  * @since 2.7.1
447
  */
448
+ function add_admin_bar_network_menu_item($wp_admin_bar)
449
+ {
450
  /**
451
  * Filter to control if admin bar shortcut should be added
452
  *
454
  *
455
  * @param bool Add item
456
  */
457
+ $add_items = apply_filters(
458
+ 'simple_history/add_admin_bar_network_menu_item',
459
+ true
460
+ );
461
 
462
+ if (!$add_items) {
463
  return;
464
  }
465
 
466
  // Don't show for logged out users or single site mode.
467
+ if (!is_user_logged_in() || !is_multisite()) {
468
  return;
469
  }
470
 
471
  // Show only when the user has at least one site, or they're a super admin.
472
+ if (count($wp_admin_bar->user->blogs) < 1 && !is_super_admin()) {
473
  return;
474
  }
475
 
476
  // Setting to show as page must be true
477
+ if (!$this->setting_show_as_page()) {
478
  return;
479
  }
480
 
481
  // User must have capability to view the history page
482
+ if (!current_user_can($this->get_view_history_capability())) {
483
  return;
484
  }
485
 
486
  /*
487
  menu_page_url() is defined in the WordPress Plugin Administration API, which is not loaded here by default */
488
  /* dito for is_plugin_active() */
489
+ require_once ABSPATH . 'wp-admin/includes/plugin.php';
490
 
491
+ foreach ((array) $wp_admin_bar->user->blogs as $blog) {
492
+ switch_to_blog($blog->userblog_id);
 
 
 
493
 
494
+ if (is_plugin_active(SIMPLE_HISTORY_BASENAME)) {
495
  $menu_id = 'simple-history-blog-' . $blog->userblog_id;
496
+ $parent_menu_id = 'blog-' . $blog->userblog_id;
497
+ $url = admin_url('index.php?page=simple_history_page');
498
 
499
  // Each network site is added by WP core with id "blog-1", "blog-2" ... "blog-n"
500
  // https://codex.wordpress.org/Function_Reference/add_node
501
  $args = array(
502
+ 'id' => $menu_id,
503
  'parent' => $parent_menu_id,
504
+ 'title' => _x(
505
+ 'View History',
506
+ 'Admin bar network name',
507
+ 'simple-history'
508
  ),
509
+ 'href' => $url,
510
+ 'meta' => array(
511
+ 'class' => 'ab-item--simplehistory'
512
+ )
513
  );
514
 
515
+ $wp_admin_bar->add_node($args);
 
516
  } // End if().
517
 
518
  restore_current_blog();
 
519
  } // End foreach().
 
520
  } // func
521
 
 
522
  /**
523
  * Adds a "View history" item/shortcut to the admin bar
524
  *
526
  *
527
  * @since 2.7.1
528
  */
529
+ function add_admin_bar_menu_item($wp_admin_bar)
530
+ {
531
  /**
532
  * Filter to control if admin bar shortcut should be added
533
  *
535
  *
536
  * @param bool Add item
537
  */
538
+ $add_item = apply_filters(
539
+ 'simple_history/add_admin_bar_menu_item',
540
+ true
541
+ );
542
 
543
+ if (!$add_item) {
544
  return;
545
  }
546
 
547
  // Don't show for logged out users
548
+ if (!is_user_logged_in()) {
549
  return;
550
  }
551
 
552
  // Setting to show as page must be true
553
+ if (!$this->setting_show_as_page()) {
554
  return;
555
  }
556
 
557
  // User must have capability to view the history page
558
+ if (!current_user_can($this->get_view_history_capability())) {
559
  return;
560
  }
561
 
562
  /*
563
  menu_page_url() is defined in the WordPress Plugin Administration API, which is not loaded here by default */
564
  /* dito for is_plugin_active() */
565
+ require_once ABSPATH . 'wp-admin/includes/plugin.php';
566
 
567
  $menu_id = 'simple-history-view-history';
568
+ $parent_menu_id = 'site-name';
569
+ $url = admin_url('index.php?page=simple_history_page');
570
 
571
  $args = array(
572
+ 'id' => $menu_id,
573
  'parent' => $parent_menu_id,
574
+ 'title' => _x('Simple History', 'Admin bar name', 'simple-history'),
575
+ 'href' => $url,
576
+ 'meta' => array(
577
+ 'class' => 'ab-item--simplehistory'
578
+ )
579
  );
580
 
581
+ $wp_admin_bar->add_node($args);
 
582
  } // func
583
 
584
  /**
586
  *
587
  * @return SimpleHistory instance
588
  */
589
+ public static function get_instance()
590
+ {
591
+ if (!isset(self::$instance)) {
 
592
  self::$instance = new SimpleHistory();
 
593
  }
594
 
595
  return self::$instance;
 
596
  }
597
 
598
+ function filter_gettext_storeLatestTranslations(
599
+ $translation,
600
+ $text,
601
+ $domain
602
+ ) {
603
  // Check that translation is a string or integer, i.ex. the valid values for an array key
604
+ if (!is_string($translation) || !is_integer($translation)) {
605
  return $translation;
606
  }
607
 
613
  // global $sh_latest_translations;
614
  $sh_latest_translations = $this->gettextLatestTranslations;
615
 
616
+ $sh_latest_translations[$translation] = array(
617
  'translation' => $translation,
618
  'text' => $text,
619
+ 'domain' => $domain
620
  );
621
 
622
+ $arr_length = sizeof($sh_latest_translations);
623
+ if ($arr_length > $array_max_size) {
624
+ $sh_latest_translations = array_slice(
625
+ $sh_latest_translations,
626
+ $arr_length - $array_max_size
627
+ );
628
  }
629
 
630
  $this->gettextLatestTranslations = $sh_latest_translations;
631
 
632
  return $translation;
 
633
  }
634
 
635
+ function setup_cron()
636
+ {
637
+ add_filter('simple_history/maybe_purge_db', array(
638
+ $this,
639
+ 'maybe_purge_db'
640
+ ));
641
 
642
+ if (!wp_next_scheduled('simple_history/maybe_purge_db')) {
643
+ wp_schedule_event(time(), 'daily', 'simple_history/maybe_purge_db');
 
 
644
  } else {
645
  }
646
 
647
  // Remove old schedule (only author dev sites should have it)
648
+ $old_next_scheduled = wp_next_scheduled('simple_history/purge_db');
649
+ if ($old_next_scheduled) {
650
+ wp_unschedule_event($old_next_scheduled, 'simple_history/purge_db');
651
  }
 
652
  }
653
 
654
+ public function testlog_old()
655
+ {
656
  // Log that an email has been sent
657
+ simple_history_add(array(
658
+ 'object_type' => 'Email',
659
+ 'object_name' => 'Hi there',
660
+ 'action' => 'was sent'
661
+ ));
 
 
662
 
663
  // Will show “Plugin your_plugin_name Edited” in the history log
664
+ simple_history_add(
665
+ 'action=edited&object_type=plugin&object_name=your_plugin_name'
666
+ );
667
 
668
  // Will show the history item "Starship USS Enterprise repaired"
 
 
 
669
  simple_history_add(
670
+ 'action=repaired&object_type=Starship&object_name=USS Enterprise'
 
 
 
 
 
671
  );
672
 
673
+ // Log with some extra details about the email
674
+ simple_history_add(array(
675
+ 'object_type' => 'Email',
676
+ 'object_name' => 'Hi there',
677
+ 'action' => 'was sent',
678
+ 'description' =>
679
+ 'The database query to generate the email took .3 seconds. This is email number 4 that is sent to this user'
680
+ ));
681
  }
682
 
683
+ public function onAdminHead()
684
+ {
685
+ if ($this->is_on_our_own_pages()) {
686
+ do_action('simple_history/admin_head', $this);
 
 
687
  }
 
688
  }
689
 
690
+ public function onAdminFooter()
691
+ {
692
+ if ($this->is_on_our_own_pages()) {
693
+ do_action('simple_history/admin_footer', $this);
 
 
694
  }
 
695
  }
696
 
697
  /**
698
  * Output JS templated into footer
699
  */
700
+ public function add_js_templates($hook)
701
+ {
702
+ if ($this->is_on_our_own_pages()) { ?>
 
 
703
  <script type="text/html" id="tmpl-simple-history-base">
704
 
705
  <div class="SimpleHistory__waitingForFirstLoad">
706
+ <img src="<?php echo admin_url(
707
+ '/images/spinner.gif'
708
+ ); ?>" alt="" width="20" height="20">
709
+ <?php echo _x(
710
+ 'Loading history...',
711
+ 'Message visible while waiting for log to load from server the first time',
712
+ 'simple-history'
713
+ ); ?>
714
  </div>
715
 
716
  <div class="SimpleHistoryLogitemsWrap">
747
  href="#">‹</a>
748
  <span class="SimpleHistoryPaginationInput">
749
  <input class="SimpleHistoryPaginationCurrentPage" title="{{ data.strings.currentPage }}" type="text" name="paged" value="{{ data.api_args.paged }}" size="4">
750
+ <?php _x('of', 'page n of n', 'simple-history'); ?>
751
  <span class="total-pages">{{ data.pages_count }}</span>
752
  </span>
753
  <a
771
  <div class="SimpleHistory-modal__background"></div>
772
  <div class="SimpleHistory-modal__content">
773
  <div class="SimpleHistory-modal__contentInner">
774
+ <img class="SimpleHistory-modal__contentSpinner" src="<?php echo admin_url(
775
+ '/images/spinner.gif'
776
+ ); ?>" alt="">
777
  </div>
778
  <div class="SimpleHistory-modal__contentClose">
779
  <button class="button">✕</button>
792
  <div class="SimpleHistoryLogitem__firstcol"></div>
793
  <div class="SimpleHistoryLogitem__secondcol">
794
  <div class="SimpleHistoryLogitem__text">
795
+ <?php _e(
796
+ 'Sorry, but there are too many similar events to show.',
797
+ 'simple-history'
798
+ ); ?>
799
  <!-- <br>occasionsCount: {{ data.occasionsCount }}
800
  <br>occasionsCountMaxReturn: {{ data.occasionsCountMaxReturn }}
801
  <br>diff: {{ data.occasionsCount - data.occasionsCountMaxReturn }}
810
  </li>
811
  </script>
812
 
813
+ <?php // Call plugins so they can add their js
814
+ foreach ($this->instantiatedLoggers as $one_logger) {
815
+ if (method_exists($one_logger['instance'], 'adminJS')) {
816
+ $one_logger['instance']->adminJS();
817
+ }
818
+ }} // End if().
 
 
 
 
819
  }
820
 
821
  /**
825
  * Examples:
826
  * http://playground-root.ep/wp-admin/admin-ajax.php?action=simple_history_api&posts_per_page=5&paged=1&format=html
827
  */
828
+ public function api()
829
+ {
830
  global $wpdb;
831
 
832
  // Fake slow answers
833
  // sleep(2);
834
  // sleep(rand(0,3));
835
  $args = $_GET;
836
+ unset($args['action']);
837
 
838
  // Type = overview | ...
839
+ $type = isset($_GET['type']) ? $_GET['type'] : null;
840
+
841
+ if (empty($args) || !$type) {
842
+ wp_send_json_error(array(
843
+ _x(
844
+ 'Not enough args specified',
845
+ 'API: not enought arguments passed',
846
+ 'simple-history'
847
  )
848
+ ));
 
849
  }
850
 
851
  // User must have capability to view the history page
852
+ if (!current_user_can($this->get_view_history_capability())) {
853
+ wp_send_json_error(array(
854
+ 'error' => 'CAPABILITY_ERROR'
855
+ ));
 
 
856
  }
857
 
858
+ if (isset($args['id'])) {
859
+ $args['post__in'] = array($args['id']);
 
 
860
  }
861
 
862
  $data = array();
863
 
864
+ switch ($type) {
 
865
  case 'overview':
866
  case 'occasions':
867
  case 'single':
868
  // API use SimpleHistoryLogQuery, so simply pass args on to that
869
  $logQuery = new SimpleHistoryLogQuery();
870
+ $data = $logQuery->query($args);
871
 
872
  $data['api_args'] = $args;
873
 
874
  // Output can be array or HMTL
875
+ if (isset($args['format']) && 'html' === $args['format']) {
 
876
  $data['log_rows_raw'] = array();
877
 
878
+ foreach ($data['log_rows'] as $key => $oneLogRow) {
 
879
  $args = array();
880
+ if ($type == 'single') {
881
  $args['type'] = 'single';
882
  }
883
 
884
+ $data['log_rows'][$key] = $this->getLogRowHTMLOutput(
885
+ $oneLogRow,
886
+ $args
887
+ );
888
  $data['num_queries'] = get_num_queries();
 
889
  }
890
  } else {
 
891
  // $data["logRows"] = $logRows;
892
  }
893
 
895
 
896
  default:
897
  $data[] = 'Nah.';
898
+ } // End switch().
899
 
900
+ wp_send_json_success($data);
 
 
 
901
  }
902
 
903
  /**
905
  * to the untranslated text too, because that's the version we want to store
906
  * in the database.
907
  */
908
+ public function filter_gettext(
909
+ $translated_text,
910
+ $untranslated_text,
911
+ $domain
912
+ ) {
913
+ if (isset($this->doFilterGettext) && $this->doFilterGettext) {
914
  $this->doFilterGettext_currentLogger->messages[] = array(
915
  'untranslated_text' => $untranslated_text,
916
  'translated_text' => $translated_text,
917
  'domain' => $domain,
918
+ 'context' => null
919
  );
 
920
  }
921
 
922
  return $translated_text;
 
923
  }
924
 
925
  /**
926
  * Store messages with context
927
  */
928
+ public function filter_gettext_with_context(
929
+ $translated_text,
930
+ $untranslated_text,
931
+ $context,
932
+ $domain
933
+ ) {
934
+ if (isset($this->doFilterGettext) && $this->doFilterGettext) {
935
  $this->doFilterGettext_currentLogger->messages[] = array(
936
  'untranslated_text' => $untranslated_text,
937
  'translated_text' => $translated_text,
938
  'domain' => $domain,
939
+ 'context' => $context
940
  );
 
941
  }
942
 
943
  return $translated_text;
 
944
  }
945
 
946
  /**
950
  *
951
  * @since 2.0
952
  */
953
+ public function load_plugin_textdomain()
954
+ {
955
  $domain = 'simple-history';
956
 
957
  // The "plugin_locale" filter is also used in load_plugin_textdomain()
958
+ $locale = apply_filters('plugin_locale', get_locale(), $domain);
959
+ load_textdomain(
960
+ $domain,
961
+ WP_LANG_DIR . '/simple-history/' . $domain . '-' . $locale . '.mo'
962
+ );
963
+ load_plugin_textdomain(
964
+ $domain,
965
+ false,
966
+ dirname($this->plugin_basename) . '/languages/'
967
+ );
968
  }
969
 
970
  /**
971
  * Setup variables and things
972
  */
973
+ public function setup_variables()
974
+ {
975
  $this->externalLoggers = array();
976
  $this->externalDropins = array();
977
  $this->instantiatedLoggers = array();
978
  $this->instantiatedDropins = array();
979
 
980
  $this->plugin_basename = SIMPLE_HISTORY_BASENAME;
 
981
  }
982
 
983
  /**
986
  * @since 2.1.5
987
  * @return string capability
988
  */
989
+ public function get_view_history_capability()
990
+ {
991
  $view_history_capability = 'edit_pages';
992
+ $view_history_capability = apply_filters(
993
+ 'simple_history_view_history_capability',
994
+ $view_history_capability
995
+ );
996
+ $view_history_capability = apply_filters(
997
+ 'simple_history/view_history_capability',
998
+ $view_history_capability
999
+ );
1000
 
1001
  return $view_history_capability;
 
1002
  }
1003
 
1004
  /**
1007
  * @since 2.1.5
1008
  * @return string capability
1009
  */
1010
+ public function get_view_settings_capability()
1011
+ {
1012
  $view_settings_capability = 'manage_options';
1013
+ $view_settings_capability = apply_filters(
1014
+ 'simple_history_view_settings_capability',
1015
+ $view_settings_capability
1016
+ );
1017
+ $view_settings_capability = apply_filters(
1018
+ 'simple_history/view_settings_capability',
1019
+ $view_settings_capability
1020
+ );
1021
 
1022
  return $view_settings_capability;
 
1023
  }
1024
 
1025
  /**
1028
  * @since 2.19
1029
  * @return bool
1030
  */
1031
+ public function user_can_clear_log()
1032
+ {
1033
+ $user_can_clear_log = apply_filters(
1034
+ 'simple_history/user_can_clear_log',
1035
+ true
1036
+ );
1037
 
1038
  return $user_can_clear_log;
1039
  }
1041
  /**
1042
  * Adds default tabs to settings
1043
  */
1044
+ public function add_default_settings_tabs()
1045
+ {
1046
  // Add default settings tabs
1047
  $this->arr_settings_tabs = array(
 
1048
  array(
1049
  'slug' => 'settings',
1050
+ 'name' => __('Settings', 'simple-history'),
1051
+ 'function' => array($this, 'settings_output_general')
1052
+ )
 
1053
  );
1054
 
1055
+ if (defined('SIMPLE_HISTORY_DEV') && SIMPLE_HISTORY_DEV) {
 
1056
  $arr_dev_tabs = array(
1057
  array(
1058
  'slug' => 'log',
1059
+ 'name' => __('Log (debug)', 'simple-history'),
1060
+ 'function' => array($this, 'settings_output_log')
1061
  ),
1062
  array(
1063
  'slug' => 'styles-example',
1064
+ 'name' => __('Styles example (debug)', 'simple-history'),
1065
+ 'function' => array($this, 'settings_output_styles_example')
1066
+ )
 
1067
  );
1068
 
1069
+ $this->arr_settings_tabs = array_merge(
1070
+ $this->arr_settings_tabs,
1071
+ $arr_dev_tabs
1072
+ );
1073
  }
 
1074
  }
1075
 
1076
  /**
1081
  *
1082
  * @since 2.1
1083
  */
1084
+ function register_logger($loggerClassName)
1085
+ {
1086
  $this->externalLoggers[] = $loggerClassName;
 
1087
  }
1088
 
1089
  /**
1094
  *
1095
  * @since 2.1
1096
  */
1097
+ function register_dropin($dropinClassName)
1098
+ {
1099
  $this->externalDropins[] = $dropinClassName;
 
1100
  }
1101
 
1102
  /**
1103
  * Load built in loggers from all files in /loggers
1104
  * and instantiates them
1105
  */
1106
+ public function load_loggers()
1107
+ {
1108
  $loggersDir = SIMPLE_HISTORY_PATH . 'loggers/';
1109
 
1110
  $loggersFiles = array(
1136
  $loggersDir . 'Plugin_Redirection.php',
1137
  $loggersDir . 'Plugin_DuplicatePost.php',
1138
  $loggersDir . 'Plugin_ACF.php',
1139
+ $loggersDir . 'Plugin_BeaverBuilder.php'
1140
  );
1141
 
1142
  // SimpleLogger.php must be loaded first and always since the other loggers extend it.
1153
  *
1154
  * @param array $loggersFiles Array with filenames
1155
  */
1156
+ $loggersFiles = apply_filters(
1157
+ 'simple_history/loggers_files',
1158
+ $loggersFiles
1159
+ );
1160
 
1161
  // Array with slug of loggers to instantiate.
1162
  // Slug of logger must also be the name of the logger class.
1163
  $arr_loggers_to_instantiate = array();
1164
 
1165
  // $one_logger_file = "SimpleCommentsLogger.php", "class-privacy-logger.php", and so on.
1166
+ foreach ($loggersFiles as $one_logger_file) {
 
1167
  $load_logger = true;
1168
 
1169
  // SimpleCommentsLogger.php -> SimpleCommentsLogger.
1170
  // class-privacy-logger.php -> class-privacy-logger.
1171
+ $basename_no_suffix = basename($one_logger_file, '.php');
1172
 
1173
  /**
1174
  * Filter to completely skip loading of a logger
1178
  * @param bool if to load the logger. return false to not load it.
1179
  * @param string basename of logger, i.e. "SimpleCommentsLogger" or "class-privacy-logger"
1180
  */
1181
+ $load_logger = apply_filters(
1182
+ 'simple_history/logger/load_logger',
1183
+ $load_logger,
1184
+ $basename_no_suffix
1185
+ );
1186
 
1187
  // If logger was SimpleLogger then force it to be loaded because for example
1188
  // custom extended plugins added later probably depends on it.
1189
+ if ('SimpleLogger' === $basename_no_suffix) {
1190
  $load_logger = true;
1191
  }
1192
 
1193
+ if (!$load_logger) {
1194
  continue;
1195
  }
1196
 
1197
  include_once $one_logger_file;
1198
 
1199
  $arr_loggers_to_instantiate[] = $basename_no_suffix;
 
1200
  }
1201
 
1202
  /**
1207
  *
1208
  * @param SimpleHistory instance
1209
  */
1210
+ do_action('simple_history/add_custom_logger', $this);
1211
 
1212
+ $arr_loggers_to_instantiate = array_merge(
1213
+ $arr_loggers_to_instantiate,
1214
+ $this->externalLoggers
1215
+ );
1216
 
1217
  /**
1218
  * Filter the array with names of loggers to instantiate.
1221
  * (
1222
  * [0] => SimpleCommentsLogger
1223
  * [1] => SimpleCoreUpdatesLogger
1224
+ * ...
1225
+ * )
1226
  *
1227
  * @since 2.0
1228
  *
1229
  * @param array $arr_loggers_to_instantiate Array with class names
1230
  */
1231
+ $arr_loggers_to_instantiate = apply_filters(
1232
+ 'simple_history/loggers_to_instantiate',
1233
+ $arr_loggers_to_instantiate
1234
+ );
1235
 
1236
  // Instantiate each logger.
1237
+ foreach ($arr_loggers_to_instantiate as $one_logger_name) {
 
1238
  // Detect logger class name.
1239
  $logger_class_name = null;
1240
 
1241
+ if (class_exists($one_logger_name)) {
1242
  // Logger name is "SimpleCommentsLogger".
1243
  $logger_class_name = $one_logger_name;
1244
  } else {
1245
  // Check if class is "class-privacy-logger".
1246
+ $logger_snaked_name = substr($one_logger_name, 6);
1247
  // "privacy-logger" -> "privacy_logger" -> Privacy_Logger
1248
+ $logger_snaked_name = str_replace(
1249
+ '-',
1250
+ '_',
1251
+ $logger_snaked_name
1252
+ );
1253
+ $logger_snaked_name = sh_ucwords($logger_snaked_name, '_');
1254
 
1255
+ if (class_exists($logger_snaked_name)) {
1256
  $logger_class_name = $logger_snaked_name;
1257
  }
1258
  }
1259
 
1260
  // Continue to load next logger if no valid logger class found.
1261
+ if (!$logger_class_name) {
1262
  continue;
1263
  }
1264
 
1265
  // Init found logger class.
1266
+ $logger_instance = new $logger_class_name($this);
1267
 
1268
+ if (
1269
+ !is_subclass_of($logger_instance, 'SimpleLogger') &&
1270
+ !is_a($logger_instance, 'SimpleLogger')
1271
+ ) {
1272
  continue;
1273
  }
1274
 
1282
 
1283
  // Check so no logger has a logger slug with more than 30 chars,
1284
  // because db column is only 30 chars.
1285
+ if (strlen($logger_instance->slug) > 30) {
1286
+ add_action('admin_notices', array(
1287
+ $this,
1288
+ 'admin_notice_logger_slug_to_long'
1289
+ ));
1290
  }
1291
 
1292
  // Un-tell gettext filter.
1299
 
1300
  $arr_messages_by_message_key = array();
1301
 
1302
+ if (
1303
+ isset($logger_info['messages']) &&
1304
+ is_array($logger_info['messages'])
1305
+ ) {
1306
+ foreach (
1307
+ (array) $logger_info['messages']
1308
+ as $message_key => $message_translated
1309
+ ) {
1310
  // Find message in array with both translated and non translated strings.
1311
+ foreach (
1312
+ $logger_instance->messages
1313
+ as $one_message_with_translation_info
1314
+ ) {
1315
+ if (
1316
+ $message_translated ==
1317
+ $one_message_with_translation_info[
1318
+ 'translated_text'
1319
+ ]
1320
+ ) {
1321
+ $arr_messages_by_message_key[
1322
+ $message_key
1323
+ ] = $one_message_with_translation_info;
1324
  continue;
1325
  }
1326
  }
1330
  $logger_instance->messages = $arr_messages_by_message_key;
1331
 
1332
  // Add logger to array of loggers.
1333
+ $this->instantiatedLoggers[$logger_instance->slug] = array(
1334
  'name' => $logger_info['name'],
1335
+ 'instance' => $logger_instance
1336
  );
1337
+ } // End foreach().
1338
 
1339
+ do_action('simple_history/loggers_loaded');
 
 
 
1340
  }
1341
 
1342
  /**
1343
  * Load built in dropins from all files in /dropins
1344
  * and instantiates them
1345
  */
1346
+ public function load_dropins()
1347
+ {
1348
  $dropinsDir = SIMPLE_HISTORY_PATH . 'dropins/';
1349
 
1350
  $dropinsFiles = array(
1361
  $dropinsDir . 'SimpleHistorySidebarDropin.php',
1362
  $dropinsDir . 'SimpleHistorySidebarStats.php',
1363
  $dropinsDir . 'SimpleHistorySidebarSettings.php',
1364
+ $dropinsDir . 'SimpleHistoryWPCLIDropin.php'
1365
  );
1366
 
1367
  /**
1373
  *
1374
  * @param array $dropinsFiles Array with filenames
1375
  */
1376
+ $dropinsFiles = apply_filters(
1377
+ 'simple_history/dropins_files',
1378
+ $dropinsFiles
1379
+ );
1380
 
1381
  $arrDropinsToInstantiate = array();
1382
 
1383
+ foreach ($dropinsFiles as $oneDropinFile) {
 
1384
  // path/path/simplehistory/dropins/SimpleHistoryDonateDropin.php => SimpleHistoryDonateDropin
1385
+ $oneDropinFileBasename = basename($oneDropinFile, '.php');
1386
 
1387
  $load_dropin = true;
1388
 
1395
  *
1396
  * @param bool if to load the dropin. return false to not load it.
1397
  */
1398
+ $load_dropin = apply_filters(
1399
+ "simple_history/dropin/load_dropin_{$oneDropinFileBasename}",
1400
+ $load_dropin
1401
+ );
1402
 
1403
  /**
1404
  * Filter to completely skip loading of a dropin
1408
  * @param bool if to load the dropin. return false to not load it.
1409
  * @param string slug of dropin
1410
  */
1411
+ $load_dropin = apply_filters(
1412
+ 'simple_history/dropin/load_dropin',
1413
+ $load_dropin,
1414
+ $oneDropinFileBasename
1415
+ );
1416
 
1417
+ if (!$load_dropin) {
1418
  continue;
1419
  }
1420
 
1421
  include_once $oneDropinFile;
1422
 
1423
  $arrDropinsToInstantiate[] = $oneDropinFileBasename;
1424
+ } // End foreach().
 
1425
 
1426
  /**
1427
  * Action that dropins can use to add their custom loggers.
1431
  *
1432
  * @param array $arrDropinsToInstantiate Array with class names
1433
  */
1434
+ do_action('simple_history/add_custom_dropin', $this);
1435
 
1436
  /**
1437
  * Filter the array with names of dropin to instantiate.
1440
  *
1441
  * @param array $arrDropinsToInstantiate Array with class names
1442
  */
1443
+ $arrDropinsToInstantiate = apply_filters(
1444
+ 'simple_history/dropins_to_instantiate',
1445
+ $arrDropinsToInstantiate
1446
+ );
1447
 
1448
+ $arrDropinsToInstantiate = array_merge(
1449
+ $arrDropinsToInstantiate,
1450
+ $this->externalDropins
1451
+ );
1452
 
1453
  // Instantiate each dropin
1454
+ foreach ($arrDropinsToInstantiate as $oneDropinName) {
1455
+ if (!class_exists($oneDropinName)) {
 
1456
  continue;
1457
  }
1458
 
1459
+ $this->instantiatedDropins[$oneDropinName] = array(
1460
  'name' => $oneDropinName,
1461
+ 'instance' => new $oneDropinName($this)
1462
  );
 
1463
  }
 
1464
  }
1465
 
1466
  /**
1469
  *
1470
  * @return int
1471
  */
1472
+ function get_pager_size()
1473
+ {
1474
+ $pager_size = get_option('simple_history_pager_size', 20);
1475
 
1476
  /**
1477
  * Filter the pager size setting
1480
  *
1481
  * @param int $pager_size
1482
  */
1483
+ $pager_size = apply_filters('simple_history/pager_size', $pager_size);
1484
 
1485
  return $pager_size;
 
1486
  }
1487
 
 
1488
  /**
1489
  * Gets the pager size,
1490
  * i.e. the number of items to show on each page in the history
1492
  * @since 2.12
1493
  * @return int
1494
  */
1495
+ function get_pager_size_dashboard()
1496
+ {
1497
+ $pager_size = get_option('simple_history_pager_size_dashboard', 5);
1498
 
1499
  /**
1500
  * Filter the pager size setting
1503
  *
1504
  * @param int $pager_size
1505
  */
1506
+ $pager_size = apply_filters(
1507
+ 'simple_history/pager_size_dashboard',
1508
+ $pager_size
1509
+ );
1510
 
1511
  return $pager_size;
 
1512
  }
1513
 
1514
  /**
1515
  * Show a link to our settings page on the Plugins -> Installed Plugins screen
1516
  */
1517
+ function plugin_action_links($actions, $b, $c, $d)
1518
+ {
1519
  // Only add link if user has the right to view the settings page
1520
+ if (!current_user_can($this->get_view_settings_capability())) {
1521
  return $actions;
1522
  }
1523
 
1524
+ $settings_page_url = menu_page_url(
1525
+ SimpleHistory::SETTINGS_MENU_SLUG,
1526
+ 0
1527
+ );
1528
 
1529
+ if (empty($actions)) {
1530
+ // Create array if actions is empty (and therefore is assumed to be a string by PHP & results in PHP 7.1+ fatal error due to trying to make array modifications on what's assumed to be a string)
1531
  $actions = array();
1532
+ } elseif (is_string($actions)) {
1533
+ // Convert the string (which it might've been retrieved as) to an array for future use as an array
1534
+ $actions = array($actions);
1535
  }
1536
+ $actions[] =
1537
+ "<a href='$settings_page_url'>" .
1538
+ __('Settings', 'simple-history') .
1539
+ '</a>';
1540
 
1541
  return $actions;
 
1542
  }
1543
 
1544
  /**
1546
  * requires current user to have view history capability
1547
  * and a setting to show dashboard to be set
1548
  */
1549
+ function add_dashboard_widget()
1550
+ {
1551
+ if (
1552
+ $this->setting_show_on_dashboard() &&
1553
+ current_user_can($this->get_view_history_capability())
1554
+ ) {
1555
  /**
1556
  * Filter to determine if history page should be added to page below dashboard or not
1557
  *
1559
  *
1560
  * @param bool Show the page or not
1561
  */
1562
+ $show_dashboard_widget = apply_filters(
1563
+ 'simple_history/show_dashboard_widget',
1564
+ true
1565
+ );
1566
 
1567
+ if ($show_dashboard_widget) {
1568
+ wp_add_dashboard_widget(
1569
+ 'simple_history_dashboard_widget',
1570
+ __('Simple History', 'simple-history'),
1571
+ array($this, 'dashboard_widget_output')
1572
+ );
1573
  }
1574
  }
1575
  }
1577
  /**
1578
  * Output html for the dashboard widget
1579
  */
1580
+ function dashboard_widget_output()
1581
+ {
1582
  $pager_size = $this->get_pager_size_dashboard();
1583
 
1584
  /**
1588
  *
1589
  * @param int $pager_size
1590
  */
1591
+ $pager_size = apply_filters(
1592
+ 'simple_history/dashboard_pager_size',
1593
+ $pager_size
1594
+ );
1595
 
1596
+ do_action('simple_history/dashboard/before_gui', $this);
1597
  ?>
1598
  <div class="SimpleHistoryGui"
1599
  data-pager-size='<?php echo $pager_size; ?>'
1600
  ></div>
1601
  <?php
 
1602
  }
1603
 
1604
+ function is_on_our_own_pages($hook = '')
1605
+ {
1606
  $current_screen = get_current_screen();
1607
 
1608
+ if (
1609
+ $current_screen &&
1610
+ $current_screen->base ==
1611
+ 'settings_page_' . SimpleHistory::SETTINGS_MENU_SLUG
1612
+ ) {
1613
  return true;
1614
+ } elseif (
1615
+ $current_screen &&
1616
+ $current_screen->base == 'dashboard_page_simple_history_page'
1617
+ ) {
1618
  return true;
1619
+ } elseif (
1620
+ $hook == 'settings_page_' . SimpleHistory::SETTINGS_MENU_SLUG ||
1621
+ ($this->setting_show_on_dashboard() && $hook == 'index.php') ||
1622
+ ($this->setting_show_as_page() &&
1623
+ $hook == 'dashboard_page_simple_history_page')
1624
+ ) {
1625
  return true;
1626
+ } elseif (
1627
+ $current_screen &&
1628
+ $current_screen->base == 'dashboard' &&
1629
+ $this->setting_show_on_dashboard()
1630
+ ) {
1631
  return true;
 
1632
  }
1633
 
1634
  return false;
1639
  *
1640
  * Only adds scripts to pages where the log is shown or the settings page.
1641
  */
1642
+ function enqueue_admin_scripts($hook)
1643
+ {
1644
+ if ($this->is_on_our_own_pages()) {
 
1645
  add_thickbox();
1646
 
1647
+ wp_enqueue_style(
1648
+ 'simple_history_styles',
1649
+ SIMPLE_HISTORY_DIR_URL . 'css/styles.css',
1650
+ false,
1651
+ SIMPLE_HISTORY_VERSION
1652
+ );
1653
+ wp_enqueue_script(
1654
+ 'simple_history_script',
1655
+ SIMPLE_HISTORY_DIR_URL . 'js/scripts.js',
1656
+ array('jquery', 'backbone', 'wp-util'),
1657
+ SIMPLE_HISTORY_VERSION,
1658
+ true
1659
+ );
1660
 
1661
+ wp_enqueue_script(
1662
+ 'select2',
1663
+ SIMPLE_HISTORY_DIR_URL . 'js/select2/select2.full.min.js',
1664
+ array('jquery')
1665
+ );
1666
+ wp_enqueue_style(
1667
+ 'select2',
1668
+ SIMPLE_HISTORY_DIR_URL . 'js/select2/select2.min.css'
1669
+ );
1670
 
1671
  // Translations that we use in JavaScript
1672
  wp_localize_script(
1673
+ 'simple_history_script',
1674
+ 'simple_history_script_vars',
1675
+ array(
1676
+ 'settingsConfirmClearLog' => __(
1677
+ 'Remove all log items?',
1678
+ 'simple-history'
1679
+ ),
1680
  'pagination' => array(
1681
+ 'goToTheFirstPage' => __(
1682
+ 'Go to the first page',
1683
+ 'simple-history'
1684
+ ),
1685
+ 'goToThePrevPage' => __(
1686
+ 'Go to the previous page',
1687
+ 'simple-history'
1688
+ ),
1689
+ 'goToTheNextPage' => __(
1690
+ 'Go to the next page',
1691
+ 'simple-history'
1692
+ ),
1693
+ 'goToTheLastPage' => __(
1694
+ 'Go to the last page',
1695
+ 'simple-history'
1696
+ ),
1697
+ 'currentPage' => __('Current page', 'simple-history')
1698
  ),
1699
+ 'loadLogAPIError' => __(
1700
+ 'Oups, the log could not be loaded right now.',
1701
+ 'simple-history'
1702
+ ),
1703
+ 'ajaxLoadError' => __(
1704
+ 'Hm, the log could not be loaded right now. Perhaps another plugin is giving some errors. Anyway, below is the output I got from the server.',
1705
+ 'simple-history'
1706
+ ),
1707
+ 'logNoHits' => __(
1708
+ 'Your search did not match any history events.',
1709
+ 'simple-history'
1710
+ )
1711
  )
1712
  );
1713
 
1714
  // Call plugins adminCSS-method, so they can add their CSS
1715
+ foreach ($this->instantiatedLoggers as $one_logger) {
1716
+ if (method_exists($one_logger['instance'], 'adminCSS')) {
1717
  $one_logger['instance']->adminCSS();
1718
  }
1719
  }
1720
 
1721
  // Add timeago.js
1722
+ wp_enqueue_script(
1723
+ 'timeago',
1724
+ SIMPLE_HISTORY_DIR_URL . 'js/timeago/jquery.timeago.js',
1725
+ array('jquery'),
1726
+ '1.5.2',
1727
+ true
1728
+ );
1729
 
1730
  // Determine current locale to load timeago locale
1731
+ $locale = strtolower(substr(get_locale(), 0, 2));
1732
+ $locale_url_path =
1733
+ SIMPLE_HISTORY_DIR_URL .
1734
+ 'js/timeago/locales/jquery.timeago.%s.js';
1735
+ $locale_dir_path =
1736
+ SIMPLE_HISTORY_PATH . 'js/timeago/locales/jquery.timeago.%s.js';
1737
 
1738
  // Only enqueue if locale-file exists on file system
1739
+ if (file_exists(sprintf($locale_dir_path, $locale))) {
1740
+ wp_enqueue_script(
1741
+ 'timeago-locale',
1742
+ sprintf($locale_url_path, $locale),
1743
+ array('jquery'),
1744
+ '1.5.2',
1745
+ true
1746
+ );
1747
  } else {
1748
+ wp_enqueue_script(
1749
+ 'timeago-locale',
1750
+ sprintf($locale_url_path, 'en'),
1751
+ array('jquery'),
1752
+ '1.5.2',
1753
+ true
1754
+ );
1755
  }
1756
  // end add timeago
1757
  // Load Select2 locale
1758
  $locale_url_path = SIMPLE_HISTORY_DIR_URL . 'js/select2/i18n/%s.js';
1759
  $locale_dir_path = SIMPLE_HISTORY_PATH . 'js/select2/i18n/%s.js';
1760
 
1761
+ if (file_exists(sprintf($locale_dir_path, $locale))) {
1762
+ wp_enqueue_script(
1763
+ 'select2-locale',
1764
+ sprintf($locale_url_path, $locale),
1765
+ array('jquery'),
1766
+ '3.5.1',
1767
+ true
1768
+ );
1769
  }
1770
 
1771
  /**
1776
  *
1777
  * @param SimpleHistory $SimpleHistory This class.
1778
  */
1779
+ do_action('simple_history/enqueue_admin_scripts', $this);
1780
+ } // End if().
 
 
1781
  }
1782
 
1783
+ function filter_option_page_capability($capability)
1784
+ {
1785
  return $capability;
1786
  }
1787
 
1789
  * Check if plugin version have changed, i.e. has been upgraded
1790
  * If upgrade is detected then maybe modify database and so on for that version
1791
  */
1792
+ function check_for_upgrade()
1793
+ {
1794
  global $wpdb;
1795
 
1796
+ $db_version = get_option('simple_history_db_version');
1797
  $table_name = $wpdb->prefix . SimpleHistory::DBTABLE;
1798
  $table_name_contexts = $wpdb->prefix . SimpleHistory::DBTABLE_CONTEXTS;
1799
  $first_install = false;
1802
  // is a version of Simple History < 0.4
1803
  // or it's a first install
1804
  // Fix database not using UTF-8
1805
+ if (false === $db_version || intval($db_version) == 0) {
 
1806
  require_once ABSPATH . 'wp-admin/includes/upgrade.php';
1807
 
1808
  // Table creation, used to be in register_activation_hook
1809
  // We change the varchar size to add one num just to force update of encoding. dbdelta didn't see it otherwise.
1810
+ $sql =
1811
+ 'CREATE TABLE ' .
1812
+ $table_name .
1813
+ ' (
1814
  id bigint(20) NOT NULL AUTO_INCREMENT,
1815
  date datetime NOT NULL,
1816
  PRIMARY KEY (id)
1817
  ) CHARACTER SET=utf8;';
1818
 
1819
  // Upgrade db / fix utf for varchars
1820
+ dbDelta($sql);
1821
 
1822
  // Fix UTF-8 for table
1823
+ $sql = sprintf('alter table %1$s charset=utf8;', $table_name);
1824
+ $wpdb->query($sql);
1825
 
1826
  $db_version_prev = $db_version;
1827
  $db_version = 1;
1828
 
1829
+ update_option('simple_history_db_version', $db_version);
1830
 
1831
  // We are not 100% sure that this is a first install,
1832
  // but it is at least a very old version that is being updated
1833
  $first_install = true;
 
1834
  } // End if().
1835
 
1836
  // If db version is 1 then upgrade to 2
1837
  // Version 2 added the action_description column
1838
+ if (1 == intval($db_version)) {
 
1839
  // V2 used to add column "action_description"
1840
  // but it's not used any more so don't do i
1841
  $db_version_prev = $db_version;
1842
  $db_version = 2;
1843
 
1844
+ update_option('simple_history_db_version', $db_version);
 
1845
  }
1846
 
1847
  // Check that all options we use are set to their defaults, if they miss value
1849
  $arr_options = array(
1850
  array(
1851
  'name' => 'simple_history_show_as_page',
1852
+ 'default_value' => 1
1853
  ),
1854
  array(
1855
  'name' => 'simple_history_show_on_dashboard',
1856
+ 'default_value' => 1
1857
+ )
1858
  );
1859
 
1860
+ foreach ($arr_options as $one_option) {
1861
+ if (false === ($option_value = get_option($one_option['name']))) {
 
 
1862
  // Value is not set in db, so set it to a default
1863
+ update_option(
1864
+ $one_option['name'],
1865
+ $one_option['default_value']
1866
+ );
1867
  }
1868
  }
1869
 
1874
  *
1875
  * @since 2.0
1876
  */
1877
+ if (2 == intval($db_version)) {
 
1878
  require_once ABSPATH . 'wp-admin/includes/upgrade.php';
1879
 
1880
  // Update old table
1892
  KEY loggerdate (logger,date)
1893
  ) CHARSET=utf8;";
1894
 
1895
+ dbDelta($sql);
1896
 
1897
  // Add context table
1898
  $sql = "
1907
  ) CHARSET=utf8;
1908
  ";
1909
 
1910
+ $wpdb->query($sql);
1911
 
1912
  $db_version_prev = $db_version;
1913
  $db_version = 3;
1914
+ update_option('simple_history_db_version', $db_version);
1915
 
1916
  // Update possible old items to use SimpleLegacyLogger
1917
  $sql = sprintf(
1925
  $table_name
1926
  );
1927
 
1928
+ $wpdb->query($sql);
1929
 
1930
  // Say welcome, however loggers are not added this early so we need to
1931
  // use a filter to load it later
1932
+ add_action('simple_history/loggers_loaded', array(
1933
+ $this,
1934
+ 'addWelcomeLogMessage'
1935
+ ));
1936
  } // End if().
1937
 
1938
  /**
1943
  *
1944
  * @since 2.0
1945
  */
1946
+ if (3 == intval($db_version)) {
 
1947
  require_once ABSPATH . 'wp-admin/includes/upgrade.php';
1948
 
1949
  // If old columns exist = this is an old install, then modify the columns so we still can keep them
1950
  // we want to keep them because user may have logged items that they want to keep
1951
+ $db_cools = $wpdb->get_col("DESCRIBE $table_name");
 
 
1952
 
1953
+ if (in_array('action', $db_cools)) {
1954
  $sql = sprintf(
1955
  '
1956
  ALTER TABLE %1$s
1963
  ',
1964
  $table_name
1965
  );
1966
+ $wpdb->query($sql);
 
1967
  }
1968
 
1969
  $db_version_prev = $db_version;
1970
  $db_version = 4;
1971
 
1972
+ update_option('simple_history_db_version', $db_version);
 
1973
  } // End if().
1974
 
1975
  // Some installs on 2.2.2 got failed installs
1976
  // We detect these by checking for db_version and then running the install stuff again
1977
+ if (4 == intval($db_version)) {
1978
+ if (!$this->does_database_have_data()) {
 
 
1979
  // not ok, decrease db number so installs will run again and hopefully fix things
1980
  $db_version = 0;
 
1981
  } else {
1982
  // all looks ok, upgrade to db version 5, so this part is not done again
1983
  $db_version = 5;
 
1984
  }
1985
 
1986
+ update_option('simple_history_db_version', $db_version);
 
1987
  }
 
1988
  } // end check_for_upgrade
1989
 
1990
  /**
1993
  * @since 2.1.6
1994
  * @return bool True if database is not empty, false if database is empty = contains no data
1995
  */
1996
+ function does_database_have_data()
1997
+ {
1998
  global $wpdb;
1999
 
2000
  $tableprefix = $wpdb->prefix;
2003
  $simple_history_context_table = SimpleHistory::DBTABLE_CONTEXTS;
2004
 
2005
  $sql_data_exists = "SELECT id AS id_exists FROM {$tableprefix}{$simple_history_table} LIMIT 1";
2006
+ $data_exists = (bool) $wpdb->get_var($sql_data_exists, 0);
2007
 
2008
  return $data_exists;
 
2009
  }
2010
 
2011
  /**
2013
  * Is only called after database has been upgraded, so only on first install (or upgrade).
2014
  * Not called after only plugin activation.
2015
  */
2016
+ public function addWelcomeLogMessage()
2017
+ {
2018
  $db_data_exists = $this->does_database_have_data();
2019
  // $db_data_exists = false;
2020
+ $pluginLogger = $this->getInstantiatedLoggerBySlug(
2021
+ 'SimplePluginLogger'
2022
+ );
2023
+ if ($pluginLogger) {
2024
  // Add plugin installed message
2025
  $context = array(
2026
  'plugin_name' => 'Simple History',
2027
+ 'plugin_description' =>
2028
+ 'Plugin that logs various things that occur in WordPress and then presents those events in a very nice GUI.',
2029
  'plugin_url' => 'http://simple-history.com',
2030
  'plugin_version' => SIMPLE_HISTORY_VERSION,
2031
+ 'plugin_author' => 'Pär Thernström'
2032
  );
2033
 
2034
+ $pluginLogger->infoMessage('plugin_installed', $context);
2035
 
2036
  // Add plugin activated message
2037
  $context['plugin_slug'] = 'simple-history';
2038
+ $context['plugin_title'] =
2039
+ '<a href="http://simple-history.com/">Simple History</a>';
 
2040
 
2041
+ $pluginLogger->infoMessage('plugin_activated', $context);
2042
  }
2043
 
2044
+ if (!$db_data_exists) {
2045
+ $welcome_message_1 = __(
2046
+ '
2047
  Welcome to Simple History!
2048
 
2049
  This is the main history feed. It will contain events that this plugin has logged.
2050
+ ',
2051
+ 'simple-history'
2052
+ );
2053
 
2054
+ $welcome_message_2 = __(
2055
+ '
2056
  Because Simple History was just recently installed, this feed does not contain much events yet. But keep the plugin activated and soon you will see detailed information about page edits, plugin updates, user logins, and much more.
2057
+ ',
2058
+ 'simple-history'
 
 
 
 
 
2059
  );
2060
 
2061
+ SimpleLogger()->info($welcome_message_2, array(
2062
+ '_initiator' => SimpleLoggerLogInitiators::WORDPRESS
2063
+ ));
 
 
 
2064
 
2065
+ SimpleLogger()->info($welcome_message_1, array(
2066
+ '_initiator' => SimpleLoggerLogInitiators::WORDPRESS
2067
+ ));
2068
  }
 
2069
  }
2070
 
2071
+ public function registerSettingsTab($arr_tab_settings)
2072
+ {
2073
  $this->arr_settings_tabs[] = $arr_tab_settings;
2074
  }
2075
 
2076
+ public function getSettingsTabs()
2077
+ {
2078
  return $this->arr_settings_tabs;
2079
  }
2080
 
2082
  * Output HTML for the settings page
2083
  * Called from add_options_page
2084
  */
2085
+ function settings_page_output()
2086
+ {
2087
+ $arr_settings_tabs = $this->getSettingsTabs(); ?>
2088
  <div class="wrap">
2089
 
2090
  <h1 class="SimpleHistoryPageHeadline">
2091
  <div class="dashicons dashicons-backup SimpleHistoryPageHeadline__icon"></div>
2092
+ <?php _e('Simple History Settings', 'simple-history'); ?>
2093
  </h1>
2094
 
2095
  <?php
2096
+ $active_tab = isset($_GET['selected-tab'])
2097
+ ? $_GET['selected-tab']
2098
+ : 'settings';
2099
+ $settings_base_url = menu_page_url(SimpleHistory::SETTINGS_MENU_SLUG, 0);
2100
+ ?>
2101
 
2102
  <h2 class="nav-tab-wrapper">
2103
+ <?php foreach ($arr_settings_tabs as $one_tab) {
2104
+ $tab_slug = $one_tab['slug'];
2105
+
2106
+ printf(
2107
+ '<a href="%3$s" class="nav-tab %4$s">%1$s</a>',
2108
+ $one_tab['name'], // 1
2109
+ $tab_slug, // 2
2110
+ esc_url(
2111
+ add_query_arg('selected-tab', $tab_slug, $settings_base_url)
2112
+ ), // 3
2113
+ $active_tab == $tab_slug ? 'nav-tab-active' : '' // 4
2114
+ );
2115
+ } ?>
 
 
2116
  </h2>
2117
 
2118
  <?php
2119
+ // Output contents for selected tab
2120
+ $arr_active_tab = wp_filter_object_list($arr_settings_tabs, array(
2121
+ 'slug' => $active_tab
2122
+ ));
2123
+ $arr_active_tab = current($arr_active_tab);
2124
 
2125
+ // We must have found an active tab and it must have a callable function
2126
+ if (!$arr_active_tab || !is_callable($arr_active_tab['function'])) {
2127
+ wp_die(__('No valid callback found', 'simple-history'));
2128
+ }
 
 
 
2129
 
2130
+ $args = array(
2131
+ 'arr_active_tab' => $arr_active_tab
2132
+ );
 
 
 
 
 
 
 
2133
 
2134
+ call_user_func_array($arr_active_tab['function'], $args);?>
2135
 
2136
  </div>
2137
  <?php
 
2138
  }
2139
 
2140
+ public function settings_output_log()
2141
+ {
2142
  include SIMPLE_HISTORY_PATH . 'templates/settings-log.php';
 
2143
  }
2144
 
2145
+ public function settings_output_general()
2146
+ {
2147
  include SIMPLE_HISTORY_PATH . 'templates/settings-general.php';
 
2148
  }
2149
 
2150
+ public function settings_output_styles_example()
2151
+ {
2152
  include SIMPLE_HISTORY_PATH . 'templates/settings-style-example.php';
 
2153
  }
2154
 
2155
  /**
2156
  * Content for section intro. Leave it be, even if empty.
2157
  * Called from add_sections_setting.
2158
  */
2159
+ function settings_section_output()
2160
+ {
2161
  }
2162
 
2163
  /**
2164
  * Add pages (history page and settings page)
2165
  */
2166
+ function add_admin_pages()
2167
+ {
2168
  // Add a history page as a sub-page below the Dashboard menu item
2169
+ if ($this->setting_show_as_page()) {
 
2170
  /**
2171
  * Filter to determine if history page should be added to page below dashboard or not
2172
  *
2174
  *
2175
  * @param bool Show the page or not
2176
  */
2177
+ $show_dashboard_page = apply_filters(
2178
+ 'simple_history/show_dashboard_page',
2179
+ true
2180
+ );
2181
 
2182
+ if ($show_dashboard_page) {
2183
  add_dashboard_page(
2184
+ _x(
2185
+ 'Simple History',
2186
+ 'dashboard title name',
2187
+ 'simple-history'
2188
+ ),
2189
+ _x(
2190
+ 'Simple History',
2191
+ 'dashboard menu name',
2192
+ 'simple-history'
2193
+ ),
2194
  $this->get_view_history_capability(),
2195
  'simple_history_page',
2196
+ array($this, 'history_page_output')
2197
  );
 
2198
  }
2199
  }
2200
 
2201
  // Add a settings page
2202
  $show_settings_page = true;
2203
+ $show_settings_page = apply_filters(
2204
+ 'simple_history_show_settings_page',
2205
+ $show_settings_page
2206
+ );
2207
+ $show_settings_page = apply_filters(
2208
+ 'simple_history/show_settings_page',
2209
+ $show_settings_page
2210
+ );
2211
 
2212
+ if ($show_settings_page) {
2213
  add_options_page(
2214
+ __('Simple History Settings', 'simple-history'),
2215
+ _x(
2216
+ 'Simple History',
2217
+ 'Options page menu title',
2218
+ 'simple-history'
2219
+ ),
2220
  $this->get_view_settings_capability(),
2221
  SimpleHistory::SETTINGS_MENU_SLUG,
2222
+ array($this, 'settings_page_output')
2223
  );
 
2224
  }
 
2225
  }
2226
 
2227
  /**
2228
  * Add setting sections and settings for the settings page
2229
  * Also maybe save some settings before outputing them
2230
  */
2231
+ function add_settings()
2232
+ {
2233
  // Clear the log if clear button was clicked in settings.
2234
+ if (
2235
+ isset($_GET['simple_history_clear_log_nonce']) &&
2236
+ wp_verify_nonce(
2237
+ $_GET['simple_history_clear_log_nonce'],
2238
+ 'simple_history_clear_log'
2239
+ )
2240
+ ) {
2241
+ if ($this->user_can_clear_log()) {
2242
  $this->clear_log();
2243
  }
2244
 
2245
+ $msg = __('Cleared database', 'simple-history');
2246
 
2247
+ add_settings_error(
2248
+ 'simple_history_rss_feed_regenerate_secret',
2249
+ 'simple_history_rss_feed_regenerate_secret',
2250
+ $msg,
2251
+ 'updated'
2252
+ );
2253
 
2254
+ set_transient('settings_errors', get_settings_errors(), 30);
2255
 
2256
+ $goback = esc_url_raw(
2257
+ add_query_arg('settings-updated', 'true', wp_get_referer())
2258
+ );
2259
+ wp_redirect($goback);
2260
  exit();
 
2261
  }
2262
 
2263
  // Section for general options.
2266
  add_settings_section(
2267
  $settings_section_general_id,
2268
  '',
2269
+ array($this, 'settings_section_output'),
2270
  SimpleHistory::SETTINGS_MENU_SLUG // Same slug as for options menu page.
2271
  );
2272
 
2276
  // Checkboxes for where to show simple history
2277
  add_settings_field(
2278
  'simple_history_show_where',
2279
+ __('Show history', 'simple-history'),
2280
+ array($this, 'settings_field_where_to_show'),
2281
  SimpleHistory::SETTINGS_MENU_SLUG,
2282
  $settings_section_general_id
2283
  );
2284
 
2285
  // Nonces for show where inputs.
2286
+ register_setting(
2287
+ SimpleHistory::SETTINGS_GENERAL_OPTION_GROUP,
2288
+ 'simple_history_show_on_dashboard'
2289
+ );
2290
+ register_setting(
2291
+ SimpleHistory::SETTINGS_GENERAL_OPTION_GROUP,
2292
+ 'simple_history_show_as_page'
2293
+ );
2294
 
2295
  // Number if items to show on the history page.
2296
  add_settings_field(
2297
  'simple_history_number_of_items',
2298
+ __('Number of items per page on the log page', 'simple-history'),
2299
+ array($this, 'settings_field_number_of_items'),
2300
  SimpleHistory::SETTINGS_MENU_SLUG,
2301
  $settings_section_general_id
2302
  );
2303
 
2304
  // Nonces for number of items inputs.
2305
+ register_setting(
2306
+ SimpleHistory::SETTINGS_GENERAL_OPTION_GROUP,
2307
+ 'simple_history_pager_size'
2308
+ );
2309
 
2310
  // Number if items to show on dashboard.
2311
  add_settings_field(
2312
  'simple_history_number_of_items_dashboard',
2313
+ __('Number of items per page on the dashboard', 'simple-history'),
2314
+ array($this, 'settings_field_number_of_items_dashboard'),
2315
  SimpleHistory::SETTINGS_MENU_SLUG,
2316
  $settings_section_general_id
2317
  );
2318
 
2319
  // Nonces for number of items inputs.
2320
+ register_setting(
2321
+ SimpleHistory::SETTINGS_GENERAL_OPTION_GROUP,
2322
+ 'simple_history_pager_size_dashboard'
2323
+ );
2324
 
2325
  // Link/button to clear log.
2326
+ if ($this->user_can_clear_log()) {
2327
  add_settings_field(
2328
  'simple_history_clear_log',
2329
+ __('Clear log', 'simple-history'),
2330
+ array($this, 'settings_field_clear_log'),
2331
  SimpleHistory::SETTINGS_MENU_SLUG,
2332
  $settings_section_general_id
2333
  );
2334
  }
 
2335
  }
2336
 
2337
  /**
2338
  * Output for page with the history
2339
  */
2340
+ function history_page_output()
2341
+ {
2342
  // global $simple_history;
2343
  // $this->purge_db();
2344
  global $wpdb;
2352
  *
2353
  * @param int $pager_size
2354
  */
2355
+ $pager_size = apply_filters(
2356
+ 'simple_history/page_pager_size',
2357
+ $pager_size
2358
+ );
2359
  ?>
2360
 
2361
  <div class="wrap SimpleHistoryWrap">
2362
 
2363
  <h1 class="SimpleHistoryPageHeadline">
2364
  <div class="dashicons dashicons-backup SimpleHistoryPageHeadline__icon"></div>
2365
+ <?php echo _x('Simple History', 'history page headline', 'simple-history'); ?>
2366
  </h1>
2367
 
2368
+ <?php /**
2369
+ * Fires before the gui div
2370
+ *
2371
+ * @since 2.0
2372
+ *
2373
+ * @param SimpleHistory $SimpleHistory This class.
2374
+ */
2375
+ do_action('simple_history/history_page/before_gui', $this); ?>
 
 
2376
 
2377
  <div class="SimpleHistoryGuiWrap">
2378
 
2380
  data-pager-size='<?php echo $pager_size; ?>'
2381
  ></div>
2382
 
2383
+ <?php /**
2384
+ * Fires after the gui div
2385
+ *
2386
+ * @since 2.0
2387
+ *
2388
+ * @param SimpleHistory $SimpleHistory This class.
2389
+ */
2390
+ do_action('simple_history/history_page/after_gui', $this); ?>
 
 
 
 
2391
 
2392
  </div>
2393
 
2394
  </div>
2395
 
2396
  <?php
 
2397
  }
2398
 
2399
  /**
2402
  *
2403
  * @return bool
2404
  */
2405
+ function setting_show_on_dashboard()
2406
+ {
2407
+ $show_on_dashboard = get_option('simple_history_show_on_dashboard', 1);
2408
+ $show_on_dashboard = apply_filters(
2409
+ 'simple_history_show_on_dashboard',
2410
+ $show_on_dashboard
2411
+ );
2412
  return (bool) $show_on_dashboard;
 
2413
  }
2414
 
2415
  /**
2418
  *
2419
  * @return bool
2420
  */
2421
+ function setting_show_as_page()
2422
+ {
2423
+ $setting = get_option('simple_history_show_as_page', 1);
2424
+ $setting = apply_filters('simple_history_show_as_page', $setting);
2425
 
2426
  return (bool) $setting;
 
2427
  }
2428
 
2429
  /**
2430
  * Settings field for how many rows/items to show in log on the log page
2431
  */
2432
+ function settings_field_number_of_items()
2433
+ {
2434
+ $current_pager_size = $this->get_pager_size(); ?>
 
 
2435
  <select name="simple_history_pager_size">
2436
+ <option <?php echo $current_pager_size == 5
2437
+ ? 'selected'
2438
+ : ''; ?> value="5">5</option>
2439
+ <option <?php echo $current_pager_size == 10
2440
+ ? 'selected'
2441
+ : ''; ?> value="10">10</option>
2442
+ <option <?php echo $current_pager_size == 15
2443
+ ? 'selected'
2444
+ : ''; ?> value="15">15</option>
2445
+ <option <?php echo $current_pager_size == 20
2446
+ ? 'selected'
2447
+ : ''; ?> value="20">20</option>
2448
+ <option <?php echo $current_pager_size == 25
2449
+ ? 'selected'
2450
+ : ''; ?> value="25">25</option>
2451
+ <option <?php echo $current_pager_size == 30
2452
+ ? 'selected'
2453
+ : ''; ?> value="30">30</option>
2454
+ <option <?php echo $current_pager_size == 40
2455
+ ? 'selected'
2456
+ : ''; ?> value="40">40</option>
2457
+ <option <?php echo $current_pager_size == 50
2458
+ ? 'selected'
2459
+ : ''; ?> value="50">50</option>
2460
+ <option <?php echo $current_pager_size == 75
2461
+ ? 'selected'
2462
+ : ''; ?> value="75">75</option>
2463
+ <option <?php echo $current_pager_size == 100
2464
+ ? 'selected'
2465
+ : ''; ?> value="100">100</option>
2466
  </select>
2467
  <?php
 
2468
  }
2469
 
2470
  /**
2471
  * Settings field for how many rows/items to show in log on the dashboard
2472
  */
2473
+ function settings_field_number_of_items_dashboard()
2474
+ {
2475
+ $current_pager_size = $this->get_pager_size_dashboard(); ?>
 
 
2476
  <select name="simple_history_pager_size_dashboard">
2477
+ <option <?php echo $current_pager_size == 5
2478
+ ? 'selected'
2479
+ : ''; ?> value="5">5</option>
2480
+ <option <?php echo $current_pager_size == 10
2481
+ ? 'selected'
2482
+ : ''; ?> value="10">10</option>
2483
+ <option <?php echo $current_pager_size == 15
2484
+ ? 'selected'
2485
+ : ''; ?> value="15">15</option>
2486
+ <option <?php echo $current_pager_size == 20
2487
+ ? 'selected'
2488
+ : ''; ?> value="20">20</option>
2489
+ <option <?php echo $current_pager_size == 25
2490
+ ? 'selected'
2491
+ : ''; ?> value="25">25</option>
2492
+ <option <?php echo $current_pager_size == 30
2493
+ ? 'selected'
2494
+ : ''; ?> value="30">30</option>
2495
+ <option <?php echo $current_pager_size == 40
2496
+ ? 'selected'
2497
+ : ''; ?> value="40">40</option>
2498
+ <option <?php echo $current_pager_size == 50
2499
+ ? 'selected'
2500
+ : ''; ?> value="50">50</option>
2501
+ <option <?php echo $current_pager_size == 75
2502
+ ? 'selected'
2503
+ : ''; ?> value="75">75</option>
2504
+ <option <?php echo $current_pager_size == 100
2505
+ ? 'selected'
2506
+ : ''; ?> value="100">100</option>
2507
  </select>
2508
  <?php
 
2509
  }
2510
 
2511
  /**
2512
  * Settings field for where to show the log, page or dashboard
2513
  */
2514
+ function settings_field_where_to_show()
2515
+ {
2516
  $show_on_dashboard = $this->setting_show_on_dashboard();
2517
  $show_as_page = $this->setting_show_as_page();
 
2518
  ?>
2519
 
2520
+ <input <?php echo $show_on_dashboard
2521
+ ? "checked='checked'"
2522
+ : ''; ?> type="checkbox" value="1" name="simple_history_show_on_dashboard" id="simple_history_show_on_dashboard" class="simple_history_show_on_dashboard" />
2523
+ <label for="simple_history_show_on_dashboard"><?php _e(
2524
+ 'on the dashboard',
2525
+ 'simple-history'
2526
+ ); ?></label>
2527
 
2528
  <br />
2529
 
2530
+ <input <?php echo $show_as_page
2531
+ ? "checked='checked'"
2532
+ : ''; ?> type="checkbox" value="1" name="simple_history_show_as_page" id="simple_history_show_as_page" class="simple_history_show_as_page" />
2533
+ <label for="simple_history_show_as_page"><?php _e(
2534
+ 'as a page under the dashboard menu',
2535
+ 'simple-history'
2536
+ ); ?></label>
2537
 
2538
  <?php
2539
  }
2541
  /**
2542
  * Settings section to clear database
2543
  */
2544
+ function settings_field_clear_log()
2545
+ {
2546
+ $clear_link = esc_url(add_query_arg('', ''));
2547
+ $clear_link = wp_nonce_url(
2548
+ $clear_link,
2549
+ 'simple_history_clear_log',
2550
+ 'simple_history_clear_log_nonce'
2551
+ );
2552
  $clear_days = $this->get_clear_history_interval();
2553
 
2554
  echo '<p>';
2555
 
2556
+ if ($clear_days > 0) {
2557
+ echo sprintf(
2558
+ __(
2559
+ 'Items in the database are automatically removed after %1$s days.',
2560
+ 'simple-history'
2561
+ ),
2562
+ $clear_days
2563
+ );
2564
  } else {
2565
+ _e('Items in the database are kept forever.', 'simple-history');
2566
  }
2567
 
2568
  echo '</p>';
2569
 
2570
+ printf(
2571
+ '<p><a class="button js-SimpleHistory-Settings-ClearLog" href="%2$s">%1$s</a></p>',
2572
+ __('Clear log now', 'simple-history'),
2573
+ $clear_link
2574
+ );
2575
  }
2576
 
2577
  /**
2580
  *
2581
  * @return int Number of days.
2582
  */
2583
+ function get_clear_history_interval()
2584
+ {
2585
  $days = 60;
2586
 
2587
  /**
2590
  *
2591
  * @param $days Number of days of history to keep
2592
  */
2593
+ $days = (int) apply_filters(
2594
+ 'simple_history_db_purge_days_interval',
2595
+ $days
2596
+ );
2597
+ $days = (int) apply_filters(
2598
+ 'simple_history/db_purge_days_interval',
2599
+ $days
2600
+ );
2601
 
2602
  return $days;
 
2603
  }
2604
 
2605
  /**
2606
  * Removes all items from the log
2607
  */
2608
+ function clear_log()
2609
+ {
2610
  global $wpdb;
2611
 
2612
  $tableprefix = $wpdb->prefix;
2616
 
2617
  // Get number of rows before delete.
2618
  $sql_num_rows = "SELECT count(id) AS num_rows FROM {$tableprefix}{$simple_history_table}";
2619
+ $num_rows = $wpdb->get_var($sql_num_rows, 0);
2620
 
2621
  // Use truncate instead of delete because it's much faster (I think, writing this much later).
2622
  $sql = "TRUNCATE {$tableprefix}{$simple_history_table}";
2623
+ $wpdb->query($sql);
2624
 
2625
  $sql = "TRUNCATE {$tableprefix}{$simple_history_context_table}";
2626
+ $wpdb->query($sql);
2627
 
2628
  // Zero state sucks
2629
  SimpleLogger()->info(
2630
+ __(
2631
+ 'The log for Simple History was cleared ({num_rows} rows were removed).',
2632
+ 'simple-history'
2633
+ ),
2634
  array(
2635
+ 'num_rows' => $num_rows
2636
  )
2637
  );
2638
 
2639
+ $this->get_cache_incrementor(true);
 
2640
  }
2641
 
2642
  /**
2645
  *
2646
  * @since 2.0.17
2647
  */
2648
+ function maybe_purge_db()
2649
+ {
2650
  // How often should we try to do this?
2651
  // Once a day = a bit tiresome.
2652
  // Let's go with sundays; purge the log on sundays.
2653
  // Day of week, 1 = mon, 7 = sun.
2654
+ $day_of_week = date('N');
2655
+ if (7 === (int) $day_of_week) {
 
2656
  $this->purge_db();
 
2657
  }
 
2658
  }
2659
 
2660
  /**
2661
  * Removes old entries from the db
2662
  */
2663
+ function purge_db()
2664
+ {
2665
  $do_purge_history = true;
2666
 
2667
+ $do_purge_history = apply_filters(
2668
+ 'simple_history_allow_db_purge',
2669
+ $do_purge_history
2670
+ );
2671
+ $do_purge_history = apply_filters(
2672
+ 'simple_history/allow_db_purge',
2673
+ $do_purge_history
2674
+ );
2675
 
2676
+ if (!$do_purge_history) {
2677
  return;
2678
  }
2679
 
2680
  $days = $this->get_clear_history_interval();
2681
 
2682
  // Never clear log if days = 0.
2683
+ if (0 == $days) {
2684
  return;
2685
  }
2686
 
2689
  $table_name = $wpdb->prefix . SimpleHistory::DBTABLE;
2690
  $table_name_contexts = $wpdb->prefix . SimpleHistory::DBTABLE_CONTEXTS;
2691
 
2692
+ while (1 > 0) {
2693
  // Get id of rows to delete.
2694
  $sql = $wpdb->prepare(
2695
  "SELECT id FROM $table_name WHERE DATE_ADD(date, INTERVAL %d DAY) < now() LIMIT 100000",
2696
  $days
2697
  );
2698
 
2699
+ $ids_to_delete = $wpdb->get_col($sql);
2700
 
2701
+ if (empty($ids_to_delete)) {
2702
  // Nothing to delete.
2703
  return;
2704
  }
2705
 
2706
+ $sql_ids_in = implode(',', $ids_to_delete);
2707
 
2708
  // Add number of deleted rows to total_rows option.
2709
+ $prev_total_rows = (int) get_option('simple_history_total_rows', 0);
2710
+ $total_rows = $prev_total_rows + sizeof($ids_to_delete);
2711
+ update_option('simple_history_total_rows', $total_rows);
2712
 
2713
  // Remove rows + contexts.
2714
  $sql_delete_history = "DELETE FROM {$table_name} WHERE id IN ($sql_ids_in)";
2715
  $sql_delete_history_context = "DELETE FROM {$table_name_contexts} WHERE history_id IN ($sql_ids_in)";
2716
 
2717
+ $wpdb->query($sql_delete_history);
2718
+ $wpdb->query($sql_delete_history_context);
2719
 
2720
  $message = _nx(
2721
  'Simple History removed one event that were older than {days} days',
2722
  'Simple History removed {num_rows} events that were older than {days} days',
2723
+ count($ids_to_delete),
2724
  'Database is being cleared automagically',
2725
  'simple-history'
2726
  );
2727
 
2728
+ SimpleLogger()->info($message, array(
2729
+ 'days' => $days,
2730
+ 'num_rows' => count($ids_to_delete)
2731
+ ));
 
 
 
2732
 
2733
+ $this->get_cache_incrementor(true);
2734
  }
 
2735
  }
2736
 
2737
  /**
2742
  * @param array $row
2743
  * @return string
2744
  */
2745
+ public function getLogRowPlainTextOutput($row)
2746
+ {
2747
  $row_logger = $row->logger;
2748
  $logger = null;
2749
+ $row->context =
2750
+ isset($row->context) && is_array($row->context)
2751
+ ? $row->context
2752
+ : array();
2753
 
2754
+ if (!isset($row->context['_message_key'])) {
2755
  $row->context['_message_key'] = null;
2756
  }
2757
 
2758
  // Fallback to SimpleLogger if no logger exists for row
2759
+ if (!isset($this->instantiatedLoggers[$row_logger])) {
2760
  $row_logger = 'SimpleLogger';
2761
  }
2762
 
2763
+ $logger = $this->instantiatedLoggers[$row_logger]['instance'];
2764
 
2765
+ return $logger->getLogRowPlainTextOutput($row);
2766
  }
2767
 
2768
  /**
2776
  * @param array $row
2777
  * @return string
2778
  */
2779
+ public function getLogRowHeaderOutput($row)
2780
+ {
2781
  $row_logger = $row->logger;
2782
  $logger = null;
2783
+ $row->context =
2784
+ isset($row->context) && is_array($row->context)
2785
+ ? $row->context
2786
+ : array();
2787
 
2788
  // Fallback to SimpleLogger if no logger exists for row
2789
+ if (!isset($this->instantiatedLoggers[$row_logger])) {
2790
  $row_logger = 'SimpleLogger';
2791
  }
2792
 
2793
+ $logger = $this->instantiatedLoggers[$row_logger]['instance'];
 
 
2794
 
2795
+ return $logger->getLogRowHeaderOutput($row);
2796
  }
2797
 
2798
  /**
2801
  * @param array $row
2802
  * @return string
2803
  */
2804
+ private function getLogRowSenderImageOutput($row)
2805
+ {
2806
  $row_logger = $row->logger;
2807
  $logger = null;
2808
+ $row->context =
2809
+ isset($row->context) && is_array($row->context)
2810
+ ? $row->context
2811
+ : array();
2812
 
2813
  // Fallback to SimpleLogger if no logger exists for row
2814
+ if (!isset($this->instantiatedLoggers[$row_logger])) {
2815
  $row_logger = 'SimpleLogger';
2816
  }
2817
 
2818
+ $logger = $this->instantiatedLoggers[$row_logger]['instance'];
 
 
2819
 
2820
+ return $logger->getLogRowSenderImageOutput($row);
2821
  }
2822
 
2823
+ public function getLogRowDetailsOutput($row)
2824
+ {
2825
  $row_logger = $row->logger;
2826
  $logger = null;
2827
+ $row->context =
2828
+ isset($row->context) && is_array($row->context)
2829
+ ? $row->context
2830
+ : array();
2831
 
2832
  // Fallback to SimpleLogger if no logger exists for row
2833
+ if (!isset($this->instantiatedLoggers[$row_logger])) {
2834
  $row_logger = 'SimpleLogger';
2835
  }
2836
 
2837
+ $logger = $this->instantiatedLoggers[$row_logger]['instance'];
 
 
2838
 
2839
+ return $logger->getLogRowDetailsOutput($row);
2840
  }
2841
 
2842
  /**
2845
  *
2846
  * @param mixed $value array|object|string|whatever that is json_encode'able.
2847
  */
2848
+ public static function json_encode($value)
2849
+ {
2850
+ return version_compare(PHP_VERSION, '5.4.0') >= 0
2851
+ ? json_encode($value, JSON_PRETTY_PRINT)
2852
+ : json_encode($value);
2853
  }
2854
 
2855
  /**
2858
  * @param string $haystack
2859
  * @param string $needle
2860
  */
2861
+ public static function ends_with($haystack, $needle)
2862
+ {
2863
+ return $needle === substr($haystack, -strlen($needle));
2864
  }
2865
 
2866
  /**
2869
  * @param array $oneLogRow SimpleHistoryLogQuery array with data from SimpleHistoryLogQuery
2870
  * @return string
2871
  */
2872
+ public function getLogRowHTMLOutput($oneLogRow, $args)
2873
+ {
2874
  $defaults = array(
2875
+ 'type' => 'overview' // or "single" to include more stuff
2876
  );
2877
 
2878
+ $args = wp_parse_args($args, $defaults);
2879
 
2880
+ $header_html = $this->getLogRowHeaderOutput($oneLogRow);
2881
+ $plain_text_html = $this->getLogRowPlainTextOutput($oneLogRow);
2882
+ $sender_image_html = $this->getLogRowSenderImageOutput($oneLogRow);
2883
 
2884
  // Details = for example thumbnail of media
2885
+ $details_html = trim($this->getLogRowDetailsOutput($oneLogRow));
2886
+ if ($details_html) {
 
2887
  $details_html = sprintf(
2888
  '<div class="SimpleHistoryLogitem__details">%1$s</div>',
2889
  $details_html
2890
  );
 
2891
  }
2892
 
2893
  // subsequentOccasions = including the current one
2894
  $occasions_count = $oneLogRow->subsequentOccasions - 1;
2895
  $occasions_html = '';
2896
 
2897
+ if ($occasions_count > 0) {
 
2898
  $occasions_html = '<div class="SimpleHistoryLogitem__occasions">';
2899
 
2900
+ $occasions_html .=
2901
+ '<a href="#" class="SimpleHistoryLogitem__occasionsLink">';
2902
  $occasions_html .= sprintf(
2903
+ _n(
2904
+ '+%1$s similar event',
2905
+ '+%1$s similar events',
2906
+ $occasions_count,
2907
+ 'simple-history'
2908
+ ),
2909
  $occasions_count
2910
  );
2911
  $occasions_html .= '</a>';
2912
 
2913
+ $occasions_html .=
2914
+ '<span class="SimpleHistoryLogitem__occasionsLoading">';
2915
  $occasions_html .= sprintf(
2916
+ __('Loading…', 'simple-history'),
2917
  $occasions_count
2918
  );
2919
  $occasions_html .= '</span>';
2920
 
2921
+ $occasions_html .=
2922
+ '<span class="SimpleHistoryLogitem__occasionsLoaded">';
2923
  $occasions_html .= sprintf(
2924
+ __('Showing %1$s more', 'simple-history'),
2925
  $occasions_count
2926
  );
2927
  $occasions_html .= '</span>';
2928
 
2929
  $occasions_html .= '</div>';
 
2930
  }
2931
 
2932
  // Add data atributes to log row, so plugins can do stuff
2933
  $data_attrs = '';
2934
+ $data_attrs .= sprintf(' data-row-id="%1$d" ', $oneLogRow->id);
2935
+ $data_attrs .= sprintf(
2936
+ ' data-occasions-count="%1$d" ',
2937
+ $occasions_count
2938
+ );
2939
+ $data_attrs .= sprintf(
2940
+ ' data-occasions-id="%1$s" ',
2941
+ esc_attr($oneLogRow->occasionsID)
2942
+ );
2943
 
2944
+ if (isset($oneLogRow->context['_server_remote_addr'])) {
2945
+ $data_attrs .= sprintf(
2946
+ ' data-ip-address="%1$s" ',
2947
+ esc_attr($oneLogRow->context['_server_remote_addr'])
2948
+ );
2949
  }
2950
 
2951
+ $arr_found_additional_ip_headers = $this->instantiatedLoggers[
2952
+ 'SimpleLogger'
2953
+ ]['instance']->get_event_ip_number_headers($oneLogRow);
2954
+ if ($arr_found_additional_ip_headers) {
2955
+ $data_attrs .= sprintf(' data-ip-address-multiple="1" ');
2956
  }
2957
 
2958
+ $data_attrs .= sprintf(
2959
+ ' data-logger="%1$s" ',
2960
+ esc_attr($oneLogRow->logger)
2961
+ );
2962
+ $data_attrs .= sprintf(
2963
+ ' data-level="%1$s" ',
2964
+ esc_attr($oneLogRow->level)
2965
+ );
2966
+ $data_attrs .= sprintf(
2967
+ ' data-date="%1$s" ',
2968
+ esc_attr($oneLogRow->date)
2969
+ );
2970
+ $data_attrs .= sprintf(
2971
+ ' data-initiator="%1$s" ',
2972
+ esc_attr($oneLogRow->initiator)
2973
+ );
2974
 
2975
+ if (isset($oneLogRow->context['_user_id'])) {
2976
+ $data_attrs .= sprintf(
2977
+ ' data-initiator-user-id="%1$d" ',
2978
+ $oneLogRow->context['_user_id']
2979
+ );
2980
  }
2981
 
2982
  // If type is single then include more details
2983
  $more_details_html = '';
2984
+ if ($args['type'] == 'single') {
2985
+ $more_details_html = apply_filters(
2986
+ 'simple_history/log_html_output_details_single/html_before_context_table',
2987
+ $more_details_html,
2988
+ $oneLogRow
2989
+ );
2990
 
2991
+ $more_details_html .= sprintf(
2992
+ '<h2 class="SimpleHistoryLogitem__moreDetailsHeadline">%1$s</h2>',
2993
+ __('Context data', 'simple-history')
2994
+ );
2995
+ $more_details_html .=
2996
+ '<p>' .
2997
+ __(
2998
+ 'This is potentially useful meta data that a logger has saved.',
2999
+ 'simple-history'
3000
+ ) .
3001
+ '</p>';
3002
+ $more_details_html .=
3003
+ "<table class='SimpleHistoryLogitem__moreDetailsContext'>";
3004
  $more_details_html .= sprintf(
3005
  '<tr>
3006
  <th>%1$s</th>
3010
  'Value'
3011
  );
3012
 
3013
+ $logRowKeysToShow = array_fill_keys(
3014
+ array_keys((array) $oneLogRow),
3015
+ true
3016
+ );
3017
 
3018
  /**
3019
  * Filter what keys to show from oneLogRow
3020
  *
3021
  * Array is in format
3022
  *
3023
+ * Array
3024
+ * (
3025
+ * [id] => 1
3026
+ * [logger] => 1
3027
+ * [level] => 1
3028
+ * ...
3029
+ * )
3030
  *
3031
  * @since 2.0.29
3032
  *
3033
  * @param array with keys to show. key to show = key. value = boolean to show or not.
3034
  * @param object log row to show details from
3035
  */
3036
+ $logRowKeysToShow = apply_filters(
3037
+ 'simple_history/log_html_output_details_table/row_keys_to_show',
3038
+ $logRowKeysToShow,
3039
+ $oneLogRow
3040
+ );
3041
 
3042
  // Hide some keys by default
3043
  unset(
3050
  $logRowKeysToShow['type']
3051
  );
3052
 
3053
+ foreach ($oneLogRow as $rowKey => $rowVal) {
 
3054
  // Only columns from oneLogRow that exist in logRowKeysToShow will be outputed
3055
+ if (
3056
+ !array_key_exists($rowKey, $logRowKeysToShow) ||
3057
+ !$logRowKeysToShow[$rowKey]
3058
+ ) {
3059
  continue;
3060
  }
3061
 
3062
  // skip arrays and objects and such
3063
+ if (is_array($rowVal) || is_object($rowVal)) {
3064
  continue;
3065
  }
3066
 
3069
  <td>%1$s</td>
3070
  <td>%2$s</td>
3071
  </tr>',
3072
+ esc_html($rowKey),
3073
+ esc_html($rowVal)
3074
  );
 
3075
  }
3076
 
3077
+ $logRowContextKeysToShow = array_fill_keys(
3078
+ array_keys((array) $oneLogRow->context),
3079
+ true
3080
+ );
3081
 
3082
  /**
3083
  * Filter what keys to show from the row context
3092
  * [plugin_description] => 1
3093
  * [plugin_author] => 1
3094
  * [plugin_version] => 1
3095
+ * ...
3096
+ * )
3097
  *
3098
  * @since 2.0.29
3099
  *
3100
  * @param array with keys to show. key to show = key. value = boolean to show or not.
3101
  * @param object log row to show details from
3102
  */
3103
+ $logRowContextKeysToShow = apply_filters(
3104
+ 'simple_history/log_html_output_details_table/context_keys_to_show',
3105
+ $logRowContextKeysToShow,
3106
+ $oneLogRow
3107
+ );
3108
 
3109
+ foreach ($oneLogRow->context as $contextKey => $contextVal) {
3110
  // Only columns from context that exist in logRowContextKeysToShow will be outputed
3111
+ if (
3112
+ !array_key_exists($contextKey, $logRowContextKeysToShow) ||
3113
+ !$logRowContextKeysToShow[$contextKey]
3114
+ ) {
3115
  continue;
3116
  }
3117
 
3120
  <td>%1$s</td>
3121
  <td>%2$s</td>
3122
  </tr>',
3123
+ esc_html($contextKey),
3124
+ esc_html($contextVal)
3125
  );
 
3126
  }
3127
 
3128
  $more_details_html .= '</table>';
3129
 
3130
+ $more_details_html = apply_filters(
3131
+ 'simple_history/log_html_output_details_single/html_after_context_table',
3132
+ $more_details_html,
3133
+ $oneLogRow
3134
+ );
3135
 
3136
  $more_details_html = sprintf(
3137
  '<div class="SimpleHistoryLogitem__moreDetails">%1$s</div>',
3138
  $more_details_html
3139
  );
3140
+ } // End if().
 
3141
 
3142
  // Classes to add to log item li element
3143
  $classes = array(
3144
  'SimpleHistoryLogitem',
3145
  "SimpleHistoryLogitem--loglevel-{$oneLogRow->level}",
3146
+ "SimpleHistoryLogitem--logger-{$oneLogRow->logger}"
3147
  );
3148
 
3149
+ if (isset($oneLogRow->initiator) && !empty($oneLogRow->initiator)) {
3150
+ $classes[] =
3151
+ 'SimpleHistoryLogitem--initiator-' . $oneLogRow->initiator;
3152
  }
3153
 
3154
+ if ($arr_found_additional_ip_headers) {
3155
  $classes[] = 'SimpleHistoryLogitem--IPAddress-multiple';
3156
  }
3157
 
3159
  $log_level_tag_html = sprintf(
3160
  ' <span class="SimpleHistoryLogitem--logleveltag SimpleHistoryLogitem--logleveltag-%1$s">%2$s</span>',
3161
  $oneLogRow->level,
3162
+ $this->getLogLevelTranslated($oneLogRow->level)
3163
  );
3164
 
3165
  $plain_text_html .= $log_level_tag_html;
3171
  *
3172
  * @param $classes Array with classes
3173
  */
3174
+ $classes = apply_filters(
3175
+ 'simple_history/logrowhtmloutput/classes',
3176
+ $classes
3177
+ );
3178
 
3179
  // Generate the HTML output for a row
3180
  $output = sprintf(
3201
  $oneLogRow->logger, // 7
3202
  $data_attrs, // 8 data attributes
3203
  $more_details_html, // 9
3204
+ esc_attr(join(' ', $classes)) // 10
3205
  );
3206
 
3207
  // Get the main message row.
3211
  // Get detailed HTML-based output
3212
  // May include images, lists, any cool stuff needed to view
3213
  // SimpleLoggerFormatter::getRowHTMLOutput($oneLogRow);
3214
+ return trim($output);
 
3215
  }
3216
 
3217
  /**
3221
  * @param string $loglevel
3222
  * @return string translated loglevel
3223
  */
3224
+ function getLogLevelTranslated($loglevel)
3225
+ {
3226
  $str_translated = '';
3227
 
3228
+ switch ($loglevel) {
 
3229
  // Lowercase
3230
  case 'emergency':
3231
+ $str_translated = _x(
3232
+ 'emergency',
3233
+ 'Log level in gui',
3234
+ 'simple-history'
3235
+ );
3236
  break;
3237
 
3238
  case 'alert':
3239
+ $str_translated = _x(
3240
+ 'alert',
3241
+ 'Log level in gui',
3242
+ 'simple-history'
3243
+ );
3244
  break;
3245
 
3246
  case 'critical':
3247
+ $str_translated = _x(
3248
+ 'critical',
3249
+ 'Log level in gui',
3250
+ 'simple-history'
3251
+ );
3252
  break;
3253
 
3254
  case 'error':
3255
+ $str_translated = _x(
3256
+ 'error',
3257
+ 'Log level in gui',
3258
+ 'simple-history'
3259
+ );
3260
  break;
3261
 
3262
  case 'warning':
3263
+ $str_translated = _x(
3264
+ 'warning',
3265
+ 'Log level in gui',
3266
+ 'simple-history'
3267
+ );
3268
  break;
3269
 
3270
  case 'notice':
3271
+ $str_translated = _x(
3272
+ 'notice',
3273
+ 'Log level in gui',
3274
+ 'simple-history'
3275
+ );
3276
  break;
3277
 
3278
  case 'info':
3279
+ $str_translated = _x(
3280
+ 'info',
3281
+ 'Log level in gui',
3282
+ 'simple-history'
3283
+ );
3284
  break;
3285
 
3286
  case 'debug':
3287
+ $str_translated = _x(
3288
+ 'debug',
3289
+ 'Log level in gui',
3290
+ 'simple-history'
3291
+ );
3292
  break;
3293
 
3294
  // Uppercase
3295
  case 'Emergency':
3296
+ $str_translated = _x(
3297
+ 'Emergency',
3298
+ 'Log level in gui',
3299
+ 'simple-history'
3300
+ );
3301
  break;
3302
 
3303
  case 'Alert':
3304
+ $str_translated = _x(
3305
+ 'Alert',
3306
+ 'Log level in gui',
3307
+ 'simple-history'
3308
+ );
3309
  break;
3310
 
3311
  case 'Critical':
3312
+ $str_translated = _x(
3313
+ 'Critical',
3314
+ 'Log level in gui',
3315
+ 'simple-history'
3316
+ );
3317
  break;
3318
 
3319
  case 'Error':
3320
+ $str_translated = _x(
3321
+ 'Error',
3322
+ 'Log level in gui',
3323
+ 'simple-history'
3324
+ );
3325
  break;
3326
 
3327
  case 'Warning':
3328
+ $str_translated = _x(
3329
+ 'Warning',
3330
+ 'Log level in gui',
3331
+ 'simple-history'
3332
+ );
3333
  break;
3334
 
3335
  case 'Notice':
3336
+ $str_translated = _x(
3337
+ 'Notice',
3338
+ 'Log level in gui',
3339
+ 'simple-history'
3340
+ );
3341
  break;
3342
 
3343
  case 'Info':
3344
+ $str_translated = _x(
3345
+ 'Info',
3346
+ 'Log level in gui',
3347
+ 'simple-history'
3348
+ );
3349
  break;
3350
 
3351
  case 'Debug':
3352
+ $str_translated = _x(
3353
+ 'Debug',
3354
+ 'Log level in gui',
3355
+ 'simple-history'
3356
+ );
3357
  break;
3358
 
3359
  default:
3360
  $str_translated = $loglevel;
3361
+ } // End switch().
 
3362
 
3363
  return $str_translated;
 
3364
  }
3365
 
3366
+ public function getInstantiatedLoggers()
3367
+ {
3368
  return $this->instantiatedLoggers;
 
3369
  }
3370
 
3371
+ public function getInstantiatedDropins()
3372
+ {
3373
  return $this->instantiatedDropins;
 
3374
  }
3375
 
 
3376
  /**
3377
  * @param string $slug
3378
  * @return mixed logger instance if found, bool false if logger not found
3379
  */
3380
+ public function getInstantiatedLoggerBySlug($slug = '')
3381
+ {
3382
+ if (empty($slug)) {
3383
  return false;
3384
  }
3385
 
3386
+ foreach ($this->getInstantiatedLoggers() as $one_logger) {
3387
+ if ($slug == $one_logger['instance']->slug) {
 
3388
  return $one_logger['instance'];
3389
  }
3390
  }
3391
 
3392
  return false;
 
3393
  }
3394
 
3395
  /**
3400
  * @param string $format format to return loggers in. Default is array. Can also be "sql"
3401
  * @return array
3402
  */
3403
+ public function getLoggersThatUserCanRead($user_id = '', $format = 'array')
3404
+ {
3405
  $arr_loggers_user_can_view = array();
3406
 
3407
+ if (!is_numeric($user_id)) {
3408
  $user_id = get_current_user_id();
3409
  }
3410
 
3411
  $loggers = $this->getInstantiatedLoggers();
3412
+ foreach ($loggers as $one_logger) {
 
3413
  $logger_capability = $one_logger['instance']->getCapability();
3414
 
3415
  // $arr_loggers_user_can_view = apply_filters("simple_history/loggers_user_can_read", $user_id, $arr_loggers_user_can_view);
3416
+ $user_can_read_logger = user_can($user_id, $logger_capability);
3417
+ $user_can_read_logger = apply_filters(
3418
+ 'simple_history/loggers_user_can_read/can_read_single_logger',
3419
+ $user_can_read_logger,
3420
+ $one_logger['instance'],
3421
+ $user_id
3422
+ );
3423
 
3424
+ if ($user_can_read_logger) {
3425
  $arr_loggers_user_can_view[] = $one_logger;
3426
  }
3427
  }
3434
  * @param array $arr_loggers_user_can_view Array with loggers that user $user_id can read
3435
  * @param int user_id ID of user to check read capability for
3436
  */
3437
+ $arr_loggers_user_can_view = apply_filters(
3438
+ 'simple_history/loggers_user_can_read',
3439
+ $arr_loggers_user_can_view,
3440
+ $user_id
3441
+ );
3442
 
3443
  // just return array with slugs in parenthesis suitable for sql-where
3444
+ if ('sql' == $format) {
 
3445
  $str_return = '(';
3446
 
3447
+ if (sizeof($arr_loggers_user_can_view)) {
3448
+ foreach ($arr_loggers_user_can_view as $one_logger) {
 
 
3449
  $str_return .= sprintf(
3450
  '"%1$s", ',
3451
+ esc_sql($one_logger['instance']->slug)
3452
  );
 
3453
  }
3454
 
3455
+ $str_return = rtrim($str_return, ' ,');
 
3456
  } else {
 
3457
  // user was not allowed to read any loggers, return in (NULL) to return nothing
3458
  $str_return .= 'NULL';
 
3459
  }
3460
 
3461
  $str_return .= ')';
3462
 
3463
  return $str_return;
 
3464
  }
3465
 
3466
  return $arr_loggers_user_can_view;
 
3467
  }
3468
 
3469
  /**
3479
  * @param string $alt Alternative text to use in image tag. Defaults to blank
3480
  * @return string <img> tag for the user's avatar
3481
  */
3482
+ function get_avatar($email, $size = '96', $default = '', $alt = false)
3483
+ {
3484
  // WP setting for avatars is to show, so just use the built in function
3485
+ if (get_option('show_avatars')) {
3486
+ $avatar = get_avatar($email, $size, $default, $alt);
 
3487
 
3488
  return $avatar;
 
3489
  } else {
 
3490
  // WP setting for avatar was to not show, but we do it anyway, using the same code as get_avatar() would have used
3491
+ if (false === $alt) {
3492
  $safe_alt = '';
3493
  } else {
3494
+ $safe_alt = esc_attr($alt);
3495
  }
3496
 
3497
+ if (!is_numeric($size)) {
3498
  $size = '96';
3499
  }
3500
 
3501
+ if (empty($default)) {
3502
+ $avatar_default = get_option('avatar_default');
3503
+ if (empty($avatar_default)) {
3504
  $default = 'mystery';
3505
  } else {
3506
  $default = $avatar_default;
3507
  }
3508
  }
3509
 
3510
+ if (!empty($email)) {
3511
+ $email_hash = md5(strtolower(trim($email)));
3512
  }
3513
 
3514
+ if (is_ssl()) {
3515
  $host = 'https://secure.gravatar.com';
3516
  } else {
3517
+ if (!empty($email)) {
3518
+ $host = sprintf(
3519
+ 'http://%d.gravatar.com',
3520
+ hexdec($email_hash[0]) % 2
3521
+ );
3522
  } else {
3523
  $host = 'http://0.gravatar.com';
3524
  }
3525
  }
3526
 
3527
+ if ('mystery' == $default) {
3528
  $default = "$host/avatar/ad516503a11cd5ca435acc9bb6523536?s={$size}";
3529
+ }
3530
+ // End if().
3531
+ elseif ('blank' == $default) {
3532
+ $default = $email ? 'blank' : includes_url('images/blank.gif');
3533
+ } elseif (!empty($email) && 'gravatar_default' == $default) {
3534
  $default = '';
3535
+ } elseif ('gravatar_default' == $default) {
3536
  $default = "$host/avatar/?s={$size}";
3537
+ } elseif (empty($email)) {
3538
  $default = "$host/avatar/?d=$default&amp;s={$size}";
3539
+ } elseif (strpos($default, 'http://') === 0) {
3540
+ $default = add_query_arg('s', $size, $default);
3541
  }
3542
 
3543
+ if (!empty($email)) {
3544
  $out = "$host/avatar/";
3545
  $out .= $email_hash;
3546
  $out .= '?s=' . $size;
3547
+ $out .= '&amp;d=' . urlencode($default);
3548
 
3549
+ $rating = get_option('avatar_rating');
3550
+ if (!empty($rating)) {
3551
  $out .= "&amp;r={$rating}";
3552
  }
3553
 
3554
+ $out = str_replace('&#038;', '&amp;', esc_url($out));
3555
  $avatar = "<img alt='{$safe_alt}' src='{$out}' class='avatar avatar-{$size} photo' height='{$size}' width='{$size}' />";
3556
  } else {
3557
+ $out = esc_url($default);
3558
  $avatar = "<img alt='{$safe_alt}' src='{$out}' class='avatar avatar-{$size} photo avatar-default' height='{$size}' width='{$size}' />";
3559
  }
3560
 
3570
  * @param string $alt Alternative text to use in the avatar image tag.
3571
  * Default empty.
3572
  */
3573
+ $avatar = apply_filters(
3574
+ 'get_avatar',
3575
+ $avatar,
3576
+ $email,
3577
+ $size,
3578
+ $default,
3579
+ $alt
3580
+ );
3581
 
3582
  return $avatar;
 
3583
  } // End if().
 
3584
  }
3585
 
3586
  /**
3587
  * Quick stats above the log
3588
  * Uses filter "simple_history/history_page/before_gui" to output its contents
3589
  */
3590
+ public function output_quick_stats()
3591
+ {
3592
  global $wpdb;
3593
 
3594
  // Get number of events today
3595
  $logQuery = new SimpleHistoryLogQuery();
3596
+ $logResults = $logQuery->query(array(
3597
+ 'posts_per_page' => 1,
3598
+ 'date_from' => strtotime('today')
3599
+ ));
 
 
3600
 
3601
  $total_row_count = (int) $logResults['total_row_count'];
3602
 
3603
  // Get sql query for where to read only loggers current user is allowed to read/view
3604
+ $sql_loggers_in = $this->getLoggersThatUserCanRead(
3605
+ get_current_user_id(),
3606
+ 'sql'
3607
+ );
3608
 
3609
  // Get number of users today, i.e. events with wp_user as initiator
3610
  $sql_users_today = sprintf(
3621
  AND date > "%2$s"
3622
  ',
3623
  $sql_loggers_in,
3624
+ date('Y-m-d H:i', strtotime('today')),
3625
  $wpdb->prefix . SimpleHistory::DBTABLE,
3626
  $wpdb->prefix . SimpleHistory::DBTABLE_CONTEXTS
3627
  );
3628
 
3629
+ $cache_key =
3630
+ 'quick_stats_users_today_' . md5(serialize($sql_loggers_in));
3631
  $cache_group = 'simple-history-' . $this->get_cache_incrementor();
3632
+ $results_users_today = wp_cache_get($cache_key, $cache_group);
3633
 
3634
+ if (false === $results_users_today) {
3635
+ $results_users_today = $wpdb->get_results($sql_users_today);
3636
+ wp_cache_set($cache_key, $results_users_today, $cache_group);
3637
  }
3638
 
3639
+ $count_users_today = sizeof($results_users_today);
3640
 
3641
  // Get number of other sources (not wp_user)
3642
  $sql_other_sources_where = sprintf(
3646
  AND date > "%2$s"
3647
  ',
3648
  $sql_loggers_in,
3649
+ date('Y-m-d H:i', strtotime('today')),
3650
  $wpdb->prefix . SimpleHistory::DBTABLE,
3651
  $wpdb->prefix . SimpleHistory::DBTABLE_CONTEXTS
3652
  );
3653
 
3654
+ $sql_other_sources_where = apply_filters(
3655
+ 'simple_history/quick_stats_where',
3656
+ $sql_other_sources_where
3657
+ );
3658
 
3659
  $sql_other_sources = sprintf(
3660
  '
3665
  %5$s
3666
  ',
3667
  $sql_loggers_in,
3668
+ date('Y-m-d H:i', strtotime('today')),
3669
  $wpdb->prefix . SimpleHistory::DBTABLE,
3670
  $wpdb->prefix . SimpleHistory::DBTABLE_CONTEXTS,
3671
  $sql_other_sources_where // 5
3672
  );
3673
  // sf_d($sql_other_sources, '$sql_other_sources');
3674
+ $cache_key =
3675
+ 'quick_stats_results_other_sources_today_' .
3676
+ md5(serialize($sql_other_sources));
3677
+ $results_other_sources_today = wp_cache_get($cache_key, $cache_group);
3678
+
3679
+ if (false === $results_other_sources_today) {
3680
+ $results_other_sources_today = $wpdb->get_results(
3681
+ $sql_other_sources
3682
+ );
3683
+ wp_cache_set(
3684
+ $cache_key,
3685
+ $results_other_sources_today,
3686
+ $cache_group
3687
+ );
3688
  }
3689
 
3690
+ $count_other_sources = sizeof($results_other_sources_today);
3691
 
3692
  // sf_d($logResults, '$logResults');
3693
  // sf_d($results_users_today, '$sql_users_today');
3696
  <div class="SimpleHistoryQuickStats">
3697
  <p>
3698
  <?php
3699
+ $msg_tmpl = '';
3700
 
3701
+ // No results today at all
3702
+ if ($total_row_count == 0) {
3703
+ $msg_tmpl = __('No events today so far.', 'simple-history');
3704
+ } else {
3705
+ /*
 
 
 
 
 
3706
  Type of results
3707
  x1 event today from 1 user.
3708
  x1 event today from 1 source.
3714
  x4 events today from 2 users and 2 other sources.
3715
  */
3716
 
3717
+ // A single event existed and was from a user
3718
+ // 1 event today from 1 user.
3719
+ if ($total_row_count == 1 && $count_users_today == 1) {
3720
+ $msg_tmpl .= __('One event today from one user.', 'simple-history');
3721
+ }
3722
+
3723
+ // A single event existed and was from another source
3724
+ // 1 event today from 1 source.
3725
+ if ($total_row_count == 1 && !$count_users_today) {
3726
+ $msg_tmpl .= __(
3727
+ 'One event today from one source.',
3728
+ 'simple-history'
3729
+ );
3730
+ }
3731
+
3732
+ // Multiple events from a single user
3733
+ // 3 events today from one user.
3734
+ if (
3735
+ $total_row_count > 1 &&
3736
+ $count_users_today == 1 &&
3737
+ !$count_other_sources
3738
+ ) {
3739
+ $msg_tmpl .= __(
3740
+ '%1$d events today from one user.',
3741
+ 'simple-history'
3742
+ );
3743
+ }
3744
+
3745
+ // Multiple events from only users
3746
+ // 2 events today from 2 users.
3747
+ if ($total_row_count > 1 && $count_users_today == $total_row_count) {
3748
+ $msg_tmpl .= __(
3749
+ '%1$d events today from %2$d users.',
3750
+ 'simple-history'
3751
+ );
3752
+ }
3753
+
3754
+ // Multiple events from 1 single user and 1 single other source
3755
+ // 2 events today from 1 user and 1 other source.
3756
+ if (
3757
+ $total_row_count &&
3758
+ 1 == $count_users_today &&
3759
+ 1 == $count_other_sources
3760
+ ) {
3761
+ $msg_tmpl .= __(
3762
+ '%1$d events today from one user and one other source.',
3763
+ 'simple-history'
3764
+ );
3765
+ }
3766
+
3767
+ // Multiple events from multple users but from only 1 single other source
3768
+ // 3 events today from 2 users and 1 other source.
3769
+ if (
3770
+ $total_row_count > 1 &&
3771
+ $count_users_today > 1 &&
3772
+ $count_other_sources == 1
3773
+ ) {
3774
+ $msg_tmpl .= __(
3775
+ '%1$d events today from one user and one other source.',
3776
+ 'simple-history'
3777
+ );
3778
+ }
3779
+
3780
+ // Multiple events from 1 user but from multiple other source
3781
+ // 3 events today from 1 user and 2 other sources.
3782
+ if (
3783
+ $total_row_count > 1 &&
3784
+ 1 == $count_users_today &&
3785
+ $count_other_sources > 1
3786
+ ) {
3787
+ $msg_tmpl .= __(
3788
+ '%1$d events today from one user and %3$d other sources.',
3789
+ 'simple-history'
3790
+ );
3791
+ }
3792
+
3793
+ // Multiple events from multiple user and from multiple other sources
3794
+ // 4 events today from 2 users and 2 other sources.
3795
+ if (
3796
+ $total_row_count > 1 &&
3797
+ $count_users_today > 1 &&
3798
+ $count_other_sources > 1
3799
+ ) {
3800
+ $msg_tmpl .= __(
3801
+ '%1$s events today from %2$d users and %3$d other sources.',
3802
+ 'simple-history'
3803
+ );
3804
+ }
3805
+ } // End if().
3806
+
3807
+ // only show stats if we have something to output
3808
+ if ($msg_tmpl) {
3809
+ printf(
3810
+ $msg_tmpl,
3811
+ $logResults['total_row_count'], // 1
3812
+ $count_users_today, // 2
3813
+ $count_other_sources // 3
3814
+ );
3815
+
3816
+ // Space between texts
3817
+ /*
3818
  echo " ";
3819
 
3820
  // http://playground-root.ep/wp-admin/options-general.php?page=simple_history_settings_menu_slug&selected-tab=stats
3823
  add_query_arg("selected-tab", "stats", menu_page_url(SimpleHistory::SETTINGS_MENU_SLUG, 0))
3824
  );
3825
  */
3826
+ }?>
 
 
 
3827
  </p>
3828
  </div>
3829
  <?php
 
3830
  } // output_quick_stats
3831
 
3832
  /**
3835
  * @param $refresh bool
3836
  * @return string
3837
  */
3838
+ public static function get_cache_incrementor($refresh = false)
3839
+ {
3840
  $incrementor_key = 'simple_history_incrementor';
3841
+ $incrementor_value = wp_cache_get($incrementor_key);
3842
 
3843
+ if (false === $incrementor_value || true === $refresh) {
3844
  $incrementor_value = time();
3845
+ wp_cache_set($incrementor_key, $incrementor_value);
3846
  }
3847
 
3848
  // echo "<br>incrementor_value: $incrementor_value";
3849
  return $incrementor_value;
 
3850
  }
3851
 
 
3852
  // Number of rows the last n days
3853
+ function get_num_events_last_n_days($period_days = 28)
3854
+ {
3855
+ $transient_key = 'sh_' . md5(__METHOD__ . $period_days . '_2');
 
 
3856
 
3857
+ $count = get_transient($transient_key);
3858
 
3859
+ if (false === $count) {
3860
  global $wpdb;
3861
 
3862
+ $sqlStringLoggersUserCanRead = $this->getLoggersThatUserCanRead(
3863
+ null,
3864
+ 'sql'
3865
+ );
3866
 
3867
  $sql = sprintf(
3868
  '
3872
  AND logger IN %3$s
3873
  ',
3874
  $wpdb->prefix . SimpleHistory::DBTABLE,
3875
+ strtotime("-$period_days days"),
3876
  $sqlStringLoggersUserCanRead
3877
  );
3878
 
3879
+ $count = $wpdb->get_var($sql);
 
 
3880
 
3881
+ set_transient($transient_key, $count, HOUR_IN_SECONDS);
3882
  }
3883
 
3884
  return $count;
 
3885
  } // get_num_events_last_n_days
3886
 
3887
+ function get_num_events_per_day_last_n_days($period_days = 28)
3888
+ {
3889
+ $transient_key = 'sh_' . md5(__METHOD__ . $period_days . '_2');
3890
 
3891
+ $dates = get_transient($transient_key);
 
 
 
 
 
 
3892
 
3893
+ if (false === $dates) {
3894
  global $wpdb;
3895
 
3896
+ $sqlStringLoggersUserCanRead = $this->getLoggersThatUserCanRead(
3897
+ null,
3898
+ 'sql'
3899
+ );
3900
 
3901
  $sql = sprintf(
3902
  '
3912
  ORDER BY yearDate ASC
3913
  ',
3914
  $wpdb->prefix . SimpleHistory::DBTABLE,
3915
+ strtotime("-$period_days days"),
3916
  $sqlStringLoggersUserCanRead
3917
  );
3918
 
3919
+ $dates = $wpdb->get_results($sql);
3920
 
3921
+ set_transient($transient_key, $dates, HOUR_IN_SECONDS);
3922
  // echo "set";exit;
3923
  } else {
3924
  // echo "get";exit;
3925
  }
3926
 
3927
  return $dates;
 
3928
  } // get_num_events_per_day_for_period
3929
 
3930
  // Number of unique events the last n days
3931
+ public function get_unique_events_for_days($days = 7)
3932
+ {
3933
  global $wpdb;
3934
 
3935
  $days = (int) $days;
3936
 
3937
  $table_name = $wpdb->prefix . SimpleHistory::DBTABLE;
3938
 
3939
+ $cache_key = 'sh_' . md5(__METHOD__ . $days);
 
 
3940
 
3941
+ $numEvents = get_transient($cache_key);
3942
 
3943
+ if (false == $numEvents) {
3944
  $sql = $wpdb->prepare(
3945
  "
3946
  SELECT count( DISTINCT occasionsID )
3947
  FROM $table_name
3948
  WHERE date >= DATE_ADD(CURDATE(), INTERVAL -%d DAY)
3949
+ ",
3950
+ $days
3951
  );
3952
 
3953
+ $numEvents = $wpdb->get_var($sql);
 
 
3954
 
3955
+ set_transient($cache_key, $numEvents, HOUR_IN_SECONDS);
3956
  }
3957
 
3958
  return $numEvents;
 
3959
  } // get_unique_events_for_days
3960
 
3961
  /**
3962
  * Output an admin notice about logger slug being to long
3963
  */
3964
+ public function admin_notice_logger_slug_to_long()
3965
+ {
3966
  ?>
3967
  <div class="error notice">
3968
+ <p><?php echo esc_html__(
3969
+ 'The slug for a logger in Simple History can be max 30 chars long.',
3970
+ 'simple-history'
3971
+ ); ?></p>
3972
  </div>
3973
  <?php
3974
  }
 
3975
  } // class
3976
 
 
3977
  /**
3978
  * Helper function with same name as the SimpleLogger-class
3979
  *
3980
  * Makes call like this possible:
3981
  * SimpleLogger()->info("This is a message sent to the log");
3982
  */
3983
+ function SimpleLogger()
3984
+ {
3985
+ return new SimpleLogger(SimpleHistory::get_instance());
3986
  }
3987
 
 
3988
  /**
3989
  * Add event to history table
3990
  * This is here for backwards compatibility
3992
  * SimpleHistory()->info();
3993
  * instead
3994
  */
3995
+ function simple_history_add($args)
3996
+ {
3997
  $defaults = array(
3998
+ 'action' => null,
3999
+ 'object_type' => null,
4000
  'object_subtype' => null,
4001
+ 'object_id' => null,
4002
+ 'object_name' => null,
4003
+ 'user_id' => null,
4004
+ 'description' => null
4005
  );
4006
 
4007
+ $context = wp_parse_args($args, $defaults);
4008
 
4009
  $message = "{$context["object_type"]} {$context["object_name"]} {$context["action"]}";
4010
 
4011
+ SimpleLogger()->info($message, $context);
 
4012
  } // simple_history_add
4013
 
4014
  /**
4043
  * @param string|array $args Optional. Change 'title', 'title_left', and 'title_right' defaults. And leading_context_lines and trailing_context_lines.
4044
  * @return string Empty string if strings are equivalent or HTML with differences.
4045
  */
4046
+ function simple_history_text_diff($left_string, $right_string, $args = null)
4047
+ {
4048
  $defaults = array(
4049
  'title' => '',
4050
  'title_left' => '',
4051
  'title_right' => '',
4052
  'leading_context_lines' => 1,
4053
+ 'trailing_context_lines' => 1
4054
  );
4055
 
4056
+ $args = wp_parse_args($args, $defaults);
4057
 
4058
+ if (!class_exists('WP_Text_Diff_Renderer_Table')) {
4059
  require ABSPATH . WPINC . '/wp-diff.php';
4060
  }
4061
 
4062
+ $left_string = normalize_whitespace($left_string);
4063
+ $right_string = normalize_whitespace($right_string);
4064
 
4065
+ $left_lines = explode("\n", $left_string);
4066
+ $right_lines = explode("\n", $right_string);
4067
+ $text_diff = new Text_Diff($left_lines, $right_lines);
4068
 
4069
+ $renderer = new WP_Text_Diff_Renderer_Table($args);
4070
  $renderer->_leading_context_lines = $args['leading_context_lines'];
4071
  $renderer->_trailing_context_lines = $args['trailing_context_lines'];
4072
 
4073
+ $diff = $renderer->render($text_diff);
4074
 
4075
+ if (!$diff) {
4076
  return '';
4077
  }
4078
 
4081
  $r .= "<div class='SimpleHistory__diff__contents' tabindex='0'>";
4082
  $r .= "<div class='SimpleHistory__diff__contentsInner'>";
4083
 
4084
+ $r .= "<table class='diff SimpleHistory__diff'>\n";
4085
 
4086
+ if (!empty($args['show_split_view'])) {
4087
+ $r .=
4088
+ "<col class='content diffsplit left' /><col class='content diffsplit middle' /><col class='content diffsplit right' />";
4089
  } else {
4090
  $r .= "<col class='content' />";
4091
  }
4092
 
4093
+ if ($args['title'] || $args['title_left'] || $args['title_right']) {
4094
  $r .= '<thead>';
4095
  }
4096
+ if ($args['title']) {
4097
  $r .= "<tr class='diff-title'><th colspan='4'>$args[title]</th></tr>\n";
4098
  }
4099
+ if ($args['title_left'] || $args['title_right']) {
4100
  $r .= "<tr class='diff-sub-title'>\n";
4101
  $r .= "\t<td></td><th>$args[title_left]</th>\n";
4102
  $r .= "\t<td></td><th>$args[title_right]</th>\n";
4103
  $r .= "</tr>\n";
4104
  }
4105
+ if ($args['title'] || $args['title_left'] || $args['title_right']) {
4106
  $r .= "</thead>\n";
4107
  }
4108
 
4127
  * $handler['callback'][1]
4128
  * );
4129
  */
4130
+ function sh_error_log()
4131
+ {
4132
+ foreach (func_get_args() as $var) {
4133
+ if (is_bool($var)) {
4134
  $bool_string = true === $var ? 'true' : 'false';
4135
+ error_log("$bool_string (boolean value)");
4136
+ } elseif (is_null($var)) {
4137
+ error_log('null (null value)');
4138
  } else {
4139
+ error_log(print_r($var, true));
4140
  }
4141
  }
4142
  }
4158
  * @param callable $callable The callable thing to check.
4159
  * @return string Name of callable.
4160
  */
4161
+ function sh_get_callable_name($callable)
4162
+ {
4163
+ if (is_string($callable)) {
4164
+ return trim($callable);
4165
+ } elseif (is_array($callable)) {
4166
+ if (is_object($callable[0])) {
4167
+ return sprintf(
4168
+ '%s::%s',
4169
+ get_class($callable[0]),
4170
+ trim($callable[1])
4171
+ );
4172
  } else {
4173
+ return sprintf('%s::%s', trim($callable[0]), trim($callable[1]));
4174
  }
4175
+ } elseif ($callable instanceof Closure) {
4176
  return 'closure';
4177
  } else {
4178
  return 'unknown';
4188
  *
4189
  * @return string with words uppercased.
4190
  */
4191
+ function sh_ucwords($str, $separator = ' ')
4192
+ {
4193
+ $str = str_replace($separator, ' ', $str);
4194
+ $str = ucwords(strtolower($str));
4195
+ $str = str_replace(' ', $separator, $str);
4196
  return $str;
4197
  }
index.php CHANGED
@@ -28,17 +28,16 @@
28
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29
  */
30
 
31
- if ( ! defined( 'WPINC' ) ) {
32
- die;
33
  }
34
 
35
  // Plugin requires at least WordPress version "4.5.1", because usage of functions like wp_get_raw_referer.
36
  // true if version ok, false if too old version.
37
- $ok_wp_version = version_compare( $GLOBALS['wp_version'], '4.5.1', '>=' );
38
- $ok_php_version = version_compare( phpversion(), '5.3', '>=' );
39
-
40
- if ( $ok_php_version && $ok_wp_version ) {
41
 
 
42
  /**
43
  * Register function that is called when plugin is installed
44
  *
@@ -46,29 +45,29 @@ if ( $ok_php_version && $ok_wp_version ) {
46
  * register_activation_hook( trailingslashit(WP_PLUGIN_DIR) . trailingslashit( plugin_basename(__DIR__) ) . "index.php" , array("SimpleHistory", "on_plugin_activate" ) );
47
  */
48
 
49
- if ( ! defined( 'SIMPLE_HISTORY_VERSION' ) ) {
50
- define( 'SIMPLE_HISTORY_VERSION', '2.29.2' );
51
  }
52
 
53
- if ( ! defined( 'SIMPLE_HISTORY_PATH' ) ) {
54
- define( 'SIMPLE_HISTORY_PATH', plugin_dir_path( __FILE__ ) );
55
  }
56
 
57
- if ( ! defined( 'SIMPLE_HISTORY_BASENAME' ) ) {
58
- define( 'SIMPLE_HISTORY_BASENAME', plugin_basename( __FILE__ ) );
59
  }
60
 
61
- if ( ! defined( 'SIMPLE_HISTORY_DIR_URL' ) ) {
62
- define( 'SIMPLE_HISTORY_DIR_URL', plugin_dir_url( __FILE__ ) );
63
  }
64
 
65
- if ( ! defined( 'SIMPLE_HISTORY_FILE' ) ) {
66
- define( 'SIMPLE_HISTORY_FILE', __FILE__ );
67
  }
68
 
69
  /** Load required files */
70
- require_once( __DIR__ . '/inc/SimpleHistory.php' );
71
- require_once( __DIR__ . '/inc/SimpleHistoryLogQuery.php' );
72
 
73
  /**
74
  Constants will be like:
@@ -82,44 +81,50 @@ if ( $ok_php_version && $ok_wp_version ) {
82
 
83
  /** Boot up */
84
  SimpleHistory::get_instance();
85
-
86
  } else {
87
-
88
  // User is running to old version of php, add admin notice about that.
89
- add_action( 'admin_notices', 'simple_history_old_version_admin_notice' );
90
 
91
  /**
92
  * Show an admin message if old PHP version.
93
  */
94
- function simple_history_old_version_admin_notice() {
95
- $ok_wp_version = version_compare( $GLOBALS['wp_version'], '4.5.1', '>=' );
96
- $ok_php_version = version_compare( phpversion(), '5.3', '>=' );
97
-
98
  ?>
99
  <div class="updated error">
100
  <?php
101
- if ( ! $ok_php_version ) {
102
- echo '<p>';
103
- printf(
104
- /* translators: 1: PHP version */
105
- esc_html( __( 'Simple History is a great plugin, but to use it your server must have at least PHP 5.3 installed (you have version %s).', 'simple-history' ) ),
106
- phpversion() // 1
107
- );
108
- echo '</p>';
109
- }
110
-
111
- if ( ! $ok_wp_version ) {
112
- echo '<p>';
113
- printf(
114
- /* translators: 1: WordPress version */
115
- esc_html( __( 'Simple History requires WordPress version 4.5.1 or higher (you have version %s).', 'simple-history' ) ),
116
- $GLOBALS['wp_version'] // 1
117
- );
118
- echo '</p>';
119
- }
120
- ?>
 
 
 
 
 
 
 
 
 
121
  </div>
122
  <?php
123
-
124
  }
125
- }// End if().
28
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29
  */
30
 
31
+ if (!defined('WPINC')) {
32
+ die();
33
  }
34
 
35
  // Plugin requires at least WordPress version "4.5.1", because usage of functions like wp_get_raw_referer.
36
  // true if version ok, false if too old version.
37
+ $ok_wp_version = version_compare($GLOBALS['wp_version'], '4.5.1', '>=');
38
+ $ok_php_version = version_compare(phpversion(), '5.3', '>=');
 
 
39
 
40
+ if ($ok_php_version && $ok_wp_version) {
41
  /**
42
  * Register function that is called when plugin is installed
43
  *
45
  * register_activation_hook( trailingslashit(WP_PLUGIN_DIR) . trailingslashit( plugin_basename(__DIR__) ) . "index.php" , array("SimpleHistory", "on_plugin_activate" ) );
46
  */
47
 
48
+ if (!defined('SIMPLE_HISTORY_VERSION')) {
49
+ define('SIMPLE_HISTORY_VERSION', '2.31');
50
  }
51
 
52
+ if (!defined('SIMPLE_HISTORY_PATH')) {
53
+ define('SIMPLE_HISTORY_PATH', plugin_dir_path(__FILE__));
54
  }
55
 
56
+ if (!defined('SIMPLE_HISTORY_BASENAME')) {
57
+ define('SIMPLE_HISTORY_BASENAME', plugin_basename(__FILE__));
58
  }
59
 
60
+ if (!defined('SIMPLE_HISTORY_DIR_URL')) {
61
+ define('SIMPLE_HISTORY_DIR_URL', plugin_dir_url(__FILE__));
62
  }
63
 
64
+ if (!defined('SIMPLE_HISTORY_FILE')) {
65
+ define('SIMPLE_HISTORY_FILE', __FILE__);
66
  }
67
 
68
  /** Load required files */
69
+ require_once __DIR__ . '/inc/SimpleHistory.php';
70
+ require_once __DIR__ . '/inc/SimpleHistoryLogQuery.php';
71
 
72
  /**
73
  Constants will be like:
81
 
82
  /** Boot up */
83
  SimpleHistory::get_instance();
 
84
  } else {
 
85
  // User is running to old version of php, add admin notice about that.
86
+ add_action('admin_notices', 'simple_history_old_version_admin_notice');
87
 
88
  /**
89
  * Show an admin message if old PHP version.
90
  */
91
+ function simple_history_old_version_admin_notice()
92
+ {
93
+ $ok_wp_version = version_compare($GLOBALS['wp_version'], '4.5.1', '>=');
94
+ $ok_php_version = version_compare(phpversion(), '5.3', '>=');
95
  ?>
96
  <div class="updated error">
97
  <?php
98
+ if (!$ok_php_version) {
99
+ echo '<p>';
100
+ printf(
101
+ /* translators: 1: PHP version */
102
+ esc_html(
103
+ __(
104
+ 'Simple History is a great plugin, but to use it your server must have at least PHP 5.3 installed (you have version %s).',
105
+ 'simple-history'
106
+ )
107
+ ),
108
+ phpversion() // 1
109
+ );
110
+ echo '</p>';
111
+ }
112
+
113
+ if (!$ok_wp_version) {
114
+ echo '<p>';
115
+ printf(
116
+ /* translators: 1: WordPress version */
117
+ esc_html(
118
+ __(
119
+ 'Simple History requires WordPress version 4.5.1 or higher (you have version %s).',
120
+ 'simple-history'
121
+ )
122
+ ),
123
+ $GLOBALS['wp_version'] // 1
124
+ );
125
+ echo '</p>';
126
+ }?>
127
  </div>
128
  <?php
 
129
  }
130
+ } // End if().
languages/simple-history.pot CHANGED
@@ -1,14 +1,14 @@
1
- # Copyright (C) 2015 Simple History
2
  # This file is distributed under the same license as the Simple History package.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: Simple History 2.2.4\n"
6
  "Report-Msgid-Bugs-To: http://wordpress.org/support/plugin/Simple-History\n"
7
- "POT-Creation-Date: 2015-10-18 08:27:52+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=utf-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
11
- "PO-Revision-Date: 2015-MO-DA HO:MI+ZONE\n"
12
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
  "Language-Team: LANGUAGE <LL@li.org>\n"
14
  "X-Generator: grunt-wp-i18n 0.4.9\n"
@@ -29,334 +29,476 @@ msgid "Donate"
29
  msgstr ""
30
 
31
  #: dropins/SimpleHistoryDonateDropin.php:74
32
- msgid ""
33
- "If you find Simple History useful please <a href=\"%1$s\">donate</a> or <a "
34
- "href=\"%2$s\">buy me something from my Amazon wish list</a>."
35
  msgstr ""
36
 
37
- #: dropins/SimpleHistoryFilterDropin.php:89
38
  msgid "Filter history"
39
  msgstr ""
40
 
41
- #: dropins/SimpleHistoryFilterDropin.php:155
42
  msgid "All dates"
43
  msgstr ""
44
 
45
- #: dropins/SimpleHistoryFilterDropin.php:216
46
- msgid "Containing words"
47
- msgstr ""
48
-
49
- #: dropins/SimpleHistoryFilterDropin.php:223
50
- #: dropins/SimpleHistoryFilterDropin.php:365
51
  msgid "Search events"
52
  msgstr ""
53
 
54
- #: dropins/SimpleHistoryFilterDropin.php:241
55
  msgid "All log levels"
56
  msgstr ""
57
 
58
- #: dropins/SimpleHistoryFilterDropin.php:269
59
  msgid "All messages"
60
  msgstr ""
61
 
62
- #: dropins/SimpleHistoryFilterDropin.php:358
63
  msgid "All users"
64
  msgstr ""
65
 
66
- #: dropins/SimpleHistoryFilterDropin.php:374
67
  msgid "Search"
68
  msgstr ""
69
 
70
- #: dropins/SimpleHistoryNewRowsNotifier.php:82
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  msgid "1 new event"
72
  msgid_plural "%d new events"
73
  msgstr[0] ""
74
  msgstr[1] ""
75
 
76
- #: dropins/SimpleHistoryRSSDropin.php:57
 
 
 
 
77
  msgid "Address"
78
  msgstr ""
79
 
80
- #: dropins/SimpleHistoryRSSDropin.php:66
81
  msgid "Regenerate"
82
  msgstr ""
83
 
84
- #: dropins/SimpleHistoryRSSDropin.php:83
85
  msgid "Created new secret RSS address"
86
  msgstr ""
87
 
88
- #: dropins/SimpleHistoryRSSDropin.php:150
89
- #: dropins/SimpleHistoryRSSDropin.php:279
 
 
 
 
90
  msgid "History for %s"
91
  msgstr ""
92
 
93
- #: dropins/SimpleHistoryRSSDropin.php:151
94
- #: dropins/SimpleHistoryRSSDropin.php:280
95
  msgid "WordPress History for %s"
96
  msgstr ""
97
 
98
- #: dropins/SimpleHistoryRSSDropin.php:203
99
  msgid "Severity level: %1$s"
100
  msgstr ""
101
 
102
- #: dropins/SimpleHistoryRSSDropin.php:216
103
  msgid "+%1$s occasion"
104
  msgid_plural "+%1$s occasions"
105
  msgstr[0] ""
106
  msgstr[1] ""
107
 
108
- #: dropins/SimpleHistoryRSSDropin.php:283
109
  msgid "Wrong RSS secret"
110
  msgstr ""
111
 
112
- #: dropins/SimpleHistoryRSSDropin.php:284
113
  msgid ""
114
  "Your RSS secret for Simple History RSS feed is wrong. Please see WordPress "
115
  "settings for current link to the RSS feed."
116
  msgstr ""
117
 
118
- #: dropins/SimpleHistoryRSSDropin.php:335
119
  msgid ""
120
  "You can generate a new address for the RSS feed. This is useful if you "
121
  "think that the address has fallen into the wrong hands."
122
  msgstr ""
123
 
124
- #: dropins/SimpleHistoryRSSDropin.php:338
125
  msgid "Generate new address"
126
  msgstr ""
127
 
128
- #: dropins/SimpleHistoryRSSDropin.php:368
129
  msgid ""
130
  "Simple History has a RSS feed which you can subscribe to and receive log "
131
  "updates. Make sure you only share the feed with people you trust, since it "
132
  "can contain sensitive or confidential information."
133
  msgstr ""
134
 
 
 
 
 
135
  #: dropins/SimpleHistorySettingsLogtestDropin.php:22
136
  msgid "Test data (debug)"
137
  msgstr ""
138
 
139
- #: dropins/SimpleHistorySettingsLogtestDropin.php:227
140
  msgid "Plugin"
141
  msgstr ""
142
 
143
- #: dropins/SimpleHistorySettingsLogtestDropin.php:228
144
  msgid "Enter title of new page"
145
  msgstr ""
146
 
147
  #: dropins/SimpleHistorySettingsStatsDropin.php:29
 
148
  msgid "Stats"
149
  msgstr ""
150
 
151
- #: dropins/SimpleHistorySidebarDropin.php:167 loggers/SimpleLogger.php:377
152
  msgid "Just now"
153
  msgstr ""
154
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
155
  #: examples/example-logger.php:46
156
  msgid "Got a 404-page when trying to visit \"{request_uri}\""
157
  msgstr ""
158
 
159
- #: inc/SimpleHistory.php:357
160
  msgid "Sorry, but there are too many similar events to show."
161
  msgstr ""
162
 
163
- #: inc/SimpleHistory.php:582 inc/SimpleHistory.php:951
164
- msgid "Settings"
165
- msgstr ""
166
-
167
- #: inc/SimpleHistory.php:593
168
  msgid "Log (debug)"
169
  msgstr ""
170
 
171
- #: inc/SimpleHistory.php:598
172
  msgid "Styles example (debug)"
173
  msgstr ""
174
 
175
- #: inc/SimpleHistory.php:976
176
- #. #-#-#-#-# simple-history.pot (Simple History 2.2.4) #-#-#-#-#
177
  #. Plugin Name of the plugin/theme
178
  msgid "Simple History"
179
  msgstr ""
180
 
181
- #: inc/SimpleHistory.php:1052
182
  msgid "Remove all log items?"
183
  msgstr ""
184
 
185
- #: inc/SimpleHistory.php:1054
186
  msgid "Go to the first page"
187
  msgstr ""
188
 
189
- #: inc/SimpleHistory.php:1055
190
  msgid "Go to the previous page"
191
  msgstr ""
192
 
193
- #: inc/SimpleHistory.php:1056
194
  msgid "Go to the next page"
195
  msgstr ""
196
 
197
- #: inc/SimpleHistory.php:1057
198
  msgid "Go to the last page"
199
  msgstr ""
200
 
201
- #: inc/SimpleHistory.php:1058
202
  msgid "Current page"
203
  msgstr ""
204
 
205
- #: inc/SimpleHistory.php:1060
206
  msgid "Oups, the log could not be loaded right now."
207
  msgstr ""
208
 
209
- #: inc/SimpleHistory.php:1061
210
  msgid ""
211
  "Hm, the log could not be loaded right now. Perhaps another plugin is giving "
212
  "some errors. Anyway, below is the output I got from the server."
213
  msgstr ""
214
 
215
- #: inc/SimpleHistory.php:1062
216
  msgid "Your search did not match any history events."
217
  msgstr ""
218
 
219
- #: inc/SimpleHistory.php:1411 inc/SimpleHistory.php:1526
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
  msgid "Simple History Settings"
221
  msgstr ""
222
 
223
- #: inc/SimpleHistory.php:1445
224
  msgid "No valid callback found"
225
  msgstr ""
226
 
227
- #: inc/SimpleHistory.php:1547
228
  msgid "Cleared database"
229
  msgstr ""
230
 
231
- #: inc/SimpleHistory.php:1574
232
  msgid "Show history"
233
  msgstr ""
234
 
235
- #: inc/SimpleHistory.php:1587
236
- msgid "Number of items per page"
237
  msgstr ""
238
 
239
- #: inc/SimpleHistory.php:1599
 
 
 
 
240
  msgid "Clear log"
241
  msgstr ""
242
 
243
- #: inc/SimpleHistory.php:1738
244
  msgid "on the dashboard"
245
  msgstr ""
246
 
247
- #: inc/SimpleHistory.php:1743
248
  msgid "as a page under the dashboard menu"
249
  msgstr ""
250
 
251
- #: inc/SimpleHistory.php:1759
252
  msgid "Items in the database are automatically removed after %1$s days."
253
  msgstr ""
254
 
255
- #: inc/SimpleHistory.php:1761
256
  msgid "Items in the database are kept forever."
257
  msgstr ""
258
 
259
- #: inc/SimpleHistory.php:1765
260
  msgid "Clear log now"
261
  msgstr ""
262
 
263
- #: inc/SimpleHistory.php:1817
264
  msgid "The log for Simple History was cleared ({num_rows} rows were removed)."
265
  msgstr ""
266
 
267
- #: inc/SimpleHistory.php:2081
268
  msgid "+%1$s similar event"
269
  msgid_plural "+%1$s similar events"
270
  msgstr[0] ""
271
  msgstr[1] ""
272
 
273
- #: inc/SimpleHistory.php:2088
274
  msgid "Loading…"
275
  msgstr ""
276
 
277
- #: inc/SimpleHistory.php:2095
278
  msgid "Showing %1$s more"
279
  msgstr ""
280
 
281
- #: inc/SimpleHistory.php:2134
282
  msgid "Context data"
283
  msgstr ""
284
 
285
- #: inc/SimpleHistory.php:2135
286
  msgid "This is potentially useful meta data that a logger has saved."
287
  msgstr ""
288
 
289
- #: inc/SimpleHistory.php:2768
290
  msgid "No events today so far."
291
  msgstr ""
292
 
293
- #: inc/SimpleHistory.php:2787
294
  msgid "One event today from one user."
295
  msgstr ""
296
 
297
- #: inc/SimpleHistory.php:2793
298
  msgid "One event today from one source."
299
  msgstr ""
300
 
301
- #: inc/SimpleHistory.php:2799
302
  msgid "%1$d events today from one user."
303
  msgstr ""
304
 
305
- #: inc/SimpleHistory.php:2805
306
  msgid "%1$d events today from %2$d users."
307
  msgstr ""
308
 
309
- #: inc/SimpleHistory.php:2811 inc/SimpleHistory.php:2817
310
  msgid "%1$d events today from one user and one other source."
311
  msgstr ""
312
 
313
- #: inc/SimpleHistory.php:2823
314
  msgid "%1$d events today from one user and %3$d other sources."
315
  msgstr ""
316
 
317
- #: inc/SimpleHistory.php:2829
318
  msgid "%1$s events today from %2$d users and %3$d other sources."
319
  msgstr ""
320
 
321
- #: index.php:98
 
 
 
 
 
322
  msgid ""
323
  "Simple History is a great plugin, but to use it your server must have at "
324
  "least PHP 5.3 installed (you have version %s)."
325
  msgstr ""
326
 
327
- #: loggers/SimpleCommentsLogger.php:689
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
328
  msgid "Spam"
329
  msgstr ""
330
 
331
- #: loggers/SimpleCommentsLogger.php:691
332
  msgid "Approved"
333
  msgstr ""
334
 
335
- #: loggers/SimpleCommentsLogger.php:693
336
  msgid "Pending"
337
  msgstr ""
338
 
339
- #: loggers/SimpleCommentsLogger.php:707
340
  msgid "Trackback"
341
  msgstr ""
342
 
343
- #: loggers/SimpleCommentsLogger.php:709
344
  msgid "Pingback"
345
  msgstr ""
346
 
347
- #: loggers/SimpleCommentsLogger.php:711
348
  msgid "Comment"
349
  msgstr ""
350
 
351
- #: loggers/SimpleCoreUpdatesLogger.php:66
352
  msgid "Updated WordPress to {new_version} from {prev_version}"
353
  msgstr ""
354
 
355
- #: loggers/SimpleCoreUpdatesLogger.php:67
356
  msgid "WordPress auto-updated to {new_version} from {prev_version}"
357
  msgstr ""
358
 
359
- #: loggers/SimpleCoreUpdatesLogger.php:68
360
  msgid "WordPress database version updated to {new_version} from {prev_version}"
361
  msgstr ""
362
 
@@ -372,36 +514,32 @@ msgstr ""
372
  msgid "Created XML export"
373
  msgstr ""
374
 
375
- #: loggers/SimpleLegacyLogger.php:90
376
  msgid "By %s"
377
  msgstr ""
378
 
379
- #: loggers/SimpleLegacyLogger.php:95
380
  msgid "%d occasions"
381
  msgstr ""
382
 
383
- #: loggers/SimpleLogger.php:245
384
- msgid "Deleted user (had id %1$s, email %2$s, login %3$s)"
385
- msgstr ""
386
-
387
- #: loggers/SimpleLogger.php:271
388
- msgid "Anonymous web user"
389
- msgstr ""
390
-
391
- #: loggers/SimpleLogger.php:304
392
  msgid "Anonymous user from %1$s"
393
  msgstr ""
394
 
395
- #: loggers/SimpleLogger.php:382
396
- #. translators: Date format for log row header, see http:php.net/date
397
  msgid "M j, Y \\a\\t G:i"
398
  msgstr ""
399
 
400
- #: loggers/SimpleLogger.php:390
401
- #. translators: 1: last modified date and time in human time diff-format
402
  msgid "%1$s ago"
403
  msgstr ""
404
 
 
 
 
 
405
  #: loggers/SimpleMediaLogger.php:25
406
  msgid "Created {post_type} \"{attachment_title}\""
407
  msgstr ""
@@ -422,19 +560,19 @@ msgstr ""
422
  msgid "Uploaded {post_type} <a href=\"{edit_link}\">\"{attachment_title}\"</a>"
423
  msgstr ""
424
 
425
- #: loggers/SimpleMediaLogger.php:242
426
  msgid "{attachment_thumb}"
427
  msgstr ""
428
 
429
- #: loggers/SimpleMediaLogger.php:251
430
  msgid "{attachment_size_format}"
431
  msgstr ""
432
 
433
- #: loggers/SimpleMediaLogger.php:252
434
  msgid "{attachment_filetype_extension}"
435
  msgstr ""
436
 
437
- #: loggers/SimpleMediaLogger.php:254
438
  msgid "{full_image_width} × {full_image_height}"
439
  msgstr ""
440
 
@@ -458,218 +596,272 @@ msgstr ""
458
  msgid "Updated menu locations"
459
  msgstr ""
460
 
461
- #: loggers/SimpleOptionsLogger.php:142
462
  msgid "Updated option \"{option}\""
463
  msgstr ""
464
 
465
- #: loggers/SimpleOptionsLogger.php:244 loggers/SimpleThemeLogger.php:572
 
 
 
 
 
 
466
  msgid "New value"
467
  msgstr ""
468
 
469
- #: loggers/SimpleOptionsLogger.php:255 loggers/SimpleThemeLogger.php:584
 
 
470
  msgid "Old value"
471
  msgstr ""
472
 
473
- #: loggers/SimpleOptionsLogger.php:270 loggers/SimpleOptionsLogger.php:287
474
  msgid "Settings page"
475
  msgstr ""
476
 
477
- #: loggers/SimplePluginLogger.php:178
 
 
 
 
 
 
 
 
478
  msgid "You don't have access to this page."
479
  msgstr ""
480
 
481
- #: loggers/SimplePluginLogger.php:184 loggers/SimplePluginLogger.php:189
482
  msgid "Could not find GitHub repository."
483
  msgstr ""
484
 
485
- #: loggers/SimplePluginLogger.php:209
486
  msgid ""
487
- "<p>Viewing <code>readme</code> from repository <code><a target=\"_blank\" "
488
- "href=\"%1$s\">%2$s</a></code>.</p>"
489
  msgstr ""
490
 
491
- #: loggers/SimplePluginLogger.php:274
492
  msgid "You do not have sufficient permissions to delete plugins for this site."
493
  msgstr ""
494
 
495
- #: loggers/SimplePluginLogger.php:1122
496
  msgid "WordPress Plugin Repository"
497
  msgstr ""
498
 
499
- #: loggers/SimplePluginLogger.php:1125
500
  msgid "Uploaded ZIP archive"
501
  msgstr ""
502
 
503
- #: loggers/SimplePostLogger.php:119
504
  msgid "Created {post_type} \"{post_title}\""
505
  msgstr ""
506
 
507
- #: loggers/SimplePostLogger.php:120
508
  msgid "Updated {post_type} \"{post_title}\""
509
  msgstr ""
510
 
511
- #: loggers/SimplePostLogger.php:121
512
  msgid "Restored {post_type} \"{post_title}\" from trash"
513
  msgstr ""
514
 
515
- #: loggers/SimplePostLogger.php:122 loggers/SimplePostLogger.php:690
516
  msgid "Deleted {post_type} \"{post_title}\""
517
  msgstr ""
518
 
519
- #: loggers/SimplePostLogger.php:123
520
  msgid "Moved {post_type} \"{post_title}\" to the trash"
521
  msgstr ""
522
 
523
- #: loggers/SimplePostLogger.php:686
524
  msgid "Updated {post_type} <a href=\"{edit_link}\">\"{post_title}\"</a>"
525
  msgstr ""
526
 
527
- #: loggers/SimplePostLogger.php:694
528
  msgid "Created {post_type} <a href=\"{edit_link}\">\"{post_title}\"</a>"
529
  msgstr ""
530
 
531
- #: loggers/SimplePostLogger.php:699
532
  msgid "Moved {post_type} <a href=\"{edit_link}\">\"{post_title}\"</a> to the trash"
533
  msgstr ""
534
 
535
- #: loggers/SimplePostLogger.php:750
536
  msgid "Title"
537
  msgstr ""
538
 
539
- #: loggers/SimplePostLogger.php:764
540
  msgid "Content"
541
  msgstr ""
542
 
543
- #: loggers/SimplePostLogger.php:778
544
  msgid "Status"
545
  msgstr ""
546
 
547
- #: loggers/SimplePostLogger.php:794
548
  msgid "Publish date"
549
  msgstr ""
550
 
551
- #: loggers/SimplePostLogger.php:809
552
  msgid "Permalink"
553
  msgstr ""
554
 
555
- #: loggers/SimplePostLogger.php:823
556
  msgid "Comment status"
557
  msgstr ""
558
 
559
- #: loggers/SimplePostLogger.php:846
560
  msgid "Author"
561
  msgstr ""
562
 
563
- #: loggers/SimplePostLogger.php:848
564
  msgid ""
565
  "Changed from {prev_user_display_name} ({prev_user_email}) to "
566
  "{new_user_display_name} ({new_user_email})"
567
  msgstr ""
568
 
569
- #: loggers/SimplePostLogger.php:882
570
  msgid "Changed from {prev_page_template} to {new_page_template}"
571
  msgstr ""
572
 
573
- #: loggers/SimplePostLogger.php:884
574
  msgid "Changed from \"{prev_page_template_name}\" to \"{new_page_template_name}\""
575
  msgstr ""
576
 
577
- #: loggers/SimplePostLogger.php:892
578
  msgid "Template"
579
  msgstr ""
580
 
581
- #: loggers/SimplePostLogger.php:936
582
  msgid "Custom fields"
583
  msgstr ""
584
 
 
 
 
 
585
  #: loggers/SimpleThemeLogger.php:27
586
  msgid "Switched theme to \"{theme_name}\" from \"{prev_theme_name}\""
587
  msgstr ""
588
 
589
  #: loggers/SimpleThemeLogger.php:28
590
- msgid "Customized theme appearance \"{setting_id}\""
591
  msgstr ""
592
 
593
  #: loggers/SimpleThemeLogger.php:29
594
- msgid "Removed widget \"{widget_id_base}\" from sidebar \"{sidebar_id}\""
595
  msgstr ""
596
 
597
  #: loggers/SimpleThemeLogger.php:30
598
- msgid "Added widget \"{widget_id_base}\" to sidebar \"{sidebar_id}\""
599
  msgstr ""
600
 
601
  #: loggers/SimpleThemeLogger.php:31
602
- msgid "Changed widget order \"{widget_id_base}\" in sidebar \"{sidebar_id}\""
603
  msgstr ""
604
 
605
  #: loggers/SimpleThemeLogger.php:32
606
- msgid "Changed widget \"{widget_id_base}\" in sidebar \"{sidebar_id}\""
607
  msgstr ""
608
 
609
  #: loggers/SimpleThemeLogger.php:33
 
 
 
 
 
 
 
 
 
 
 
 
610
  msgid "Changed settings for the theme custom background"
611
  msgstr ""
612
 
613
- #: loggers/SimpleThemeLogger.php:534
614
  msgid "Section"
615
  msgstr ""
616
 
617
- #: loggers/SimpleUserLogger.php:24
618
- msgid ""
619
- "Failed to login to account with username \"{login_user_login}\" because an "
620
- "incorrect password was entered"
621
  msgstr ""
622
 
623
- #: loggers/SimpleUserLogger.php:25
624
- msgid ""
625
- "Failed to login with username \"{failed_login_username}\" because no user "
626
- "with that username exists"
 
 
627
  msgstr ""
628
 
629
  #: loggers/SimpleUserLogger.php:26
 
 
 
 
 
 
630
  msgid "Logged in"
631
  msgstr ""
632
 
633
- #: loggers/SimpleUserLogger.php:27
634
  msgid "Unknown user logged in"
635
  msgstr ""
636
 
637
- #: loggers/SimpleUserLogger.php:28
638
  msgid "Logged out"
639
  msgstr ""
640
 
641
- #: loggers/SimpleUserLogger.php:29
642
  msgid "Edited the profile for user {edited_user_login} ({edited_user_email})"
643
  msgstr ""
644
 
645
- #: loggers/SimpleUserLogger.php:30
646
  msgid ""
647
  "Created user {created_user_login} ({created_user_email}) with role "
648
  "{created_user_role}"
649
  msgstr ""
650
 
651
- #: loggers/SimpleUserLogger.php:31
652
  msgid "Deleted user {deleted_user_login} ({deleted_user_email})"
653
  msgstr ""
654
 
655
- #: loggers/SimpleUserLogger.php:229
 
 
 
 
 
 
 
 
 
 
656
  msgid "Edited <a href=\"{edit_profile_link}\">your profile</a>"
657
  msgstr ""
658
 
659
- #: loggers/SimpleUserLogger.php:233
660
  msgid "Edited <a href=\"{edit_profile_link}\">their profile</a>"
661
  msgstr ""
662
 
663
- #: loggers/SimpleUserLogger.php:242
664
  msgid "Edited your profile"
665
  msgstr ""
666
 
667
- #: loggers/SimpleUserLogger.php:253
668
  msgid ""
669
  "Edited the profile for user <a "
670
  "href=\"{edit_profile_link}\">{edited_user_login} ({edited_user_email})</a>"
671
  msgstr ""
672
 
 
 
 
 
 
 
673
  #: node_modules/grunt-wp-i18n/test/fixtures/basic-theme/exclude/file.php:3
674
  #: node_modules/grunt-wp-i18n/test/fixtures/plugin-include/plugin-include.php:6
675
  msgid "Exclude"
@@ -740,64 +932,114 @@ msgctxt "donate settings headline"
740
  msgid "Donate"
741
  msgstr ""
742
 
743
- #: dropins/SimpleHistoryExportDropin.php:23
744
  msgctxt "Export dropin: Tab name on settings page"
745
  msgid "Export"
746
  msgstr ""
747
 
748
- #: dropins/SimpleHistoryExportDropin.php:221
749
  msgctxt "Export dropin: introtext"
750
  msgid "The export function will export the full history."
751
  msgstr ""
752
 
753
- #: dropins/SimpleHistoryExportDropin.php:225
754
  msgctxt "Export dropin: format"
755
  msgid "Choose format to export to"
756
  msgstr ""
757
 
758
- #: dropins/SimpleHistoryExportDropin.php:230
759
  msgctxt "Export dropin: export format"
760
  msgid "JSON"
761
  msgstr ""
762
 
763
- #: dropins/SimpleHistoryExportDropin.php:237
764
  msgctxt "Export dropin: export format"
765
  msgid "CSV"
766
  msgstr ""
767
 
768
- #: dropins/SimpleHistoryExportDropin.php:255
769
  msgctxt "Export dropin: submit button"
770
  msgid "Download Export File"
771
  msgstr ""
772
 
773
- #: dropins/SimpleHistoryFilterDropin.php:162
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
774
  msgctxt "Filter dropin: filter week"
775
  msgid "Last 7 days"
776
  msgstr ""
777
 
778
- #: dropins/SimpleHistoryFilterDropin.php:169
779
  msgctxt "Filter dropin: filter week"
780
  msgid "Last 14 days"
781
  msgstr ""
782
 
783
- #: dropins/SimpleHistoryFilterDropin.php:176
784
  msgctxt "Filter dropin: filter week"
785
  msgid "Last 30 days"
786
  msgstr ""
787
 
788
- #: dropins/SimpleHistoryFilterDropin.php:183
789
  msgctxt "Filter dropin: filter week"
790
  msgid "Last 60 days"
791
  msgstr ""
792
 
793
- #: dropins/SimpleHistoryFilterDropin.php:225
794
  msgctxt "Filter dropin: button to show more search options"
795
- msgid "Show options"
796
  msgstr ""
797
 
798
- #: dropins/SimpleHistoryFilterDropin.php:366
799
  msgctxt "Filter dropin: button to hide more search options"
800
- msgid "Hide options"
 
 
 
 
 
 
 
 
 
 
801
  msgstr ""
802
 
803
  #: dropins/SimpleHistoryIpInfoDropin.php:68
@@ -805,38 +1047,38 @@ msgctxt "IP Info Dropin"
805
  msgid "That IP address does not seem like a public one."
806
  msgstr ""
807
 
808
- #: dropins/SimpleHistoryIpInfoDropin.php:87
809
  msgctxt "IP Info Dropin"
810
  msgid "IP address"
811
  msgstr ""
812
 
813
- #: dropins/SimpleHistoryIpInfoDropin.php:98
814
  msgctxt "IP Info Dropin"
815
  msgid "Hostname"
816
  msgstr ""
817
 
818
- #: dropins/SimpleHistoryIpInfoDropin.php:109
819
- #: dropins/SimpleHistoryIpInfoDropin.php:120
820
  msgctxt "IP Info Dropin"
821
  msgid "Network"
822
  msgstr ""
823
 
824
- #: dropins/SimpleHistoryIpInfoDropin.php:131
825
  msgctxt "IP Info Dropin"
826
  msgid "City"
827
  msgstr ""
828
 
829
- #: dropins/SimpleHistoryIpInfoDropin.php:142
830
  msgctxt "IP Info Dropin"
831
  msgid "Region"
832
  msgstr ""
833
 
834
- #: dropins/SimpleHistoryIpInfoDropin.php:153
835
  msgctxt "IP Info Dropin"
836
  msgid "Country"
837
  msgstr ""
838
 
839
- #: dropins/SimpleHistoryIpInfoDropin.php:164
840
  msgctxt "IP Info Dropin"
841
  msgid "IP info provided by %1$s ipinfo.io %2$s"
842
  msgstr ""
@@ -846,54 +1088,87 @@ msgctxt "New rows notifier: error while checking for new rows"
846
  msgid "An error occured while checking for new events"
847
  msgstr ""
848
 
849
- #: dropins/SimpleHistoryRSSDropin.php:49
850
  msgctxt "rss settings headline"
851
  msgid "RSS feed"
852
  msgstr ""
853
 
854
- #: dropins/SimpleHistorySidebarDropin.php:34
855
  msgctxt "Sidebar box"
856
  msgid "Simple History is on GitHub"
857
  msgstr ""
858
 
859
- #: dropins/SimpleHistorySidebarDropin.php:37
860
  msgctxt "Sidebar box"
861
  msgid ""
862
  "You can star, fork, or report issues with this plugin over at the <a "
863
  "href=\"%1$s\">GitHub page</a>."
864
  msgstr ""
865
 
866
- #: dropins/SimpleHistorySidebarDropin.php:51
867
  msgctxt "Sidebar box"
868
  msgid "Donate to support development"
869
  msgstr ""
870
 
871
- #: dropins/SimpleHistorySidebarDropin.php:54
872
  msgctxt "Sidebar box"
873
  msgid ""
874
  "If you like and use Simple History you should <a href=\"%1$s\">donate to "
875
  "keep this plugin free</a>."
876
  msgstr ""
877
 
878
- #: dropins/SimpleHistorySidebarDropin.php:68
879
  msgctxt "Sidebar box"
880
  msgid "Review this plugin if you like it"
881
  msgstr ""
882
 
883
- #: dropins/SimpleHistorySidebarDropin.php:71
884
  msgctxt "Sidebar box"
885
  msgid ""
886
  "If you like Simple History then please <a href=\"%1$s\">give it a nice "
887
  "review over at wordpress.org</a>."
888
  msgstr ""
889
 
890
- #: dropins/SimpleHistorySidebarDropin.php:75
891
  msgctxt "Sidebar box"
892
  msgid ""
893
  "A good review will help new users find this plugin. And it will make the "
894
  "plugin author very happy :)"
895
  msgstr ""
896
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
897
  #: examples/example-logger.php:50
898
  msgctxt "User logger: 404"
899
  msgid "Pages not found (404 errors)"
@@ -904,118 +1179,183 @@ msgctxt "User logger: 404"
904
  msgid "Pages not found"
905
  msgstr ""
906
 
907
- #: inc/SimpleHistory.php:277
 
 
 
 
 
 
 
 
 
 
908
  msgctxt "Message visible while waiting for log to load from server the first time"
909
  msgid "Loading history..."
910
  msgstr ""
911
 
912
- #: inc/SimpleHistory.php:314
913
  msgctxt "page n of n"
914
  msgid "of"
915
  msgstr ""
916
 
917
- #: inc/SimpleHistory.php:409
918
  msgctxt "API: not enought arguments passed"
919
  msgid "Not enough args specified"
920
  msgstr ""
921
 
922
- #: inc/SimpleHistory.php:1508
 
 
 
 
 
923
  msgctxt "dashboard menu name"
924
  msgid "Simple History"
925
  msgstr ""
926
 
927
- #: inc/SimpleHistory.php:1635
 
 
 
 
 
928
  msgctxt "history page headline"
929
  msgid "Simple History"
930
  msgstr ""
931
 
932
- #: inc/SimpleHistory.php:1905
933
- msgctxt "simple-history"
934
  msgid "Simple History removed one event that were older than {days} days"
935
  msgid_plural "Simple History removed {num_rows} events that were older than {days} days"
936
  msgstr[0] ""
937
  msgstr[1] ""
938
 
939
- #: inc/SimpleHistory.php:2367
940
  msgctxt "Log level in gui"
941
  msgid "emergency"
942
  msgstr ""
943
 
944
- #: inc/SimpleHistory.php:2371
945
  msgctxt "Log level in gui"
946
  msgid "alert"
947
  msgstr ""
948
 
949
- #: inc/SimpleHistory.php:2375
950
  msgctxt "Log level in gui"
951
  msgid "critical"
952
  msgstr ""
953
 
954
- #: inc/SimpleHistory.php:2379
955
  msgctxt "Log level in gui"
956
  msgid "error"
957
  msgstr ""
958
 
959
- #: inc/SimpleHistory.php:2383
960
  msgctxt "Log level in gui"
961
  msgid "warning"
962
  msgstr ""
963
 
964
- #: inc/SimpleHistory.php:2387
965
  msgctxt "Log level in gui"
966
  msgid "notice"
967
  msgstr ""
968
 
969
- #: inc/SimpleHistory.php:2391
970
  msgctxt "Log level in gui"
971
  msgid "info"
972
  msgstr ""
973
 
974
- #: inc/SimpleHistory.php:2395
975
  msgctxt "Log level in gui"
976
  msgid "debug"
977
  msgstr ""
978
 
979
- #: inc/SimpleHistory.php:2400
980
  msgctxt "Log level in gui"
981
  msgid "Emergency"
982
  msgstr ""
983
 
984
- #: inc/SimpleHistory.php:2404
985
  msgctxt "Log level in gui"
986
  msgid "Alert"
987
  msgstr ""
988
 
989
- #: inc/SimpleHistory.php:2408
990
  msgctxt "Log level in gui"
991
  msgid "Critical"
992
  msgstr ""
993
 
994
- #: inc/SimpleHistory.php:2412
995
  msgctxt "Log level in gui"
996
  msgid "Error"
997
  msgstr ""
998
 
999
- #: inc/SimpleHistory.php:2416
1000
  msgctxt "Log level in gui"
1001
  msgid "Warning"
1002
  msgstr ""
1003
 
1004
- #: inc/SimpleHistory.php:2420
1005
  msgctxt "Log level in gui"
1006
  msgid "Notice"
1007
  msgstr ""
1008
 
1009
- #: inc/SimpleHistory.php:2424
1010
  msgctxt "Log level in gui"
1011
  msgid "Info"
1012
  msgstr ""
1013
 
1014
- #: inc/SimpleHistory.php:2428
1015
  msgctxt "Log level in gui"
1016
  msgid "Debug"
1017
  msgstr ""
1018
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1019
  #: loggers/PluginEnableMediaReplaceLogger.php:23
1020
  msgctxt "PluginEnableMediaReplaceLogger"
1021
  msgid "Enable Media Replace Logger"
@@ -1026,13 +1366,18 @@ msgctxt "PluginEnableMediaReplaceLogger"
1026
  msgid "Logs media updates made with the Enable Media Replace Plugin"
1027
  msgstr ""
1028
 
1029
- #: loggers/PluginEnableMediaReplaceLogger.php:27
1030
  msgctxt "PluginEnableMediaReplaceLogger"
1031
  msgid ""
1032
  "Replaced attachment \"{prev_attachment_title}\" with new attachment "
1033
  "\"{new_attachment_title}\""
1034
  msgstr ""
1035
 
 
 
 
 
 
1036
  #: loggers/PluginUserSwitchingLogger.php:23
1037
  msgctxt "PluginUserSwitchingLogger"
1038
  msgid "User Switching Logger"
@@ -1043,341 +1388,666 @@ msgctxt "PluginUserSwitchingLogger"
1043
  msgid "Logs user switches"
1044
  msgstr ""
1045
 
1046
- #: loggers/PluginUserSwitchingLogger.php:27
 
 
 
 
 
1047
  msgctxt "PluginUserSwitchingLogger"
1048
  msgid "Switched to user \"{user_login_to}\" from user \"{user_login_from}\""
1049
  msgstr ""
1050
 
1051
- #: loggers/PluginUserSwitchingLogger.php:28
1052
  msgctxt "PluginUserSwitchingLogger"
1053
  msgid "Switched back to user \"{user_login_to}\" from user \"{user_login_from}\""
1054
  msgstr ""
1055
 
1056
- #: loggers/PluginUserSwitchingLogger.php:29
1057
  msgctxt "PluginUserSwitchingLogger"
1058
  msgid "Switched back to user \"{user_login_to}\""
1059
  msgstr ""
1060
 
1061
- #: loggers/PluginUserSwitchingLogger.php:30
1062
  msgctxt "PluginUserSwitchingLogger"
1063
  msgid "Switched off user \"{user_login}\""
1064
  msgstr ""
1065
 
1066
- #: loggers/Plugin_UltimateMembers_Logger.php:23
1067
- msgctxt "PluginUltimateMembersLogger"
1068
- msgid "Ultimate Members Logger"
1069
  msgstr ""
1070
 
1071
- #: loggers/Plugin_UltimateMembers_Logger.php:24
1072
- msgctxt "PluginUltimateMembersLogger"
1073
- msgid "Logs actions from the Ultimate Members plugin"
1074
  msgstr ""
1075
 
1076
- #: loggers/Plugin_UltimateMembers_Logger.php:27
1077
- msgctxt "PluginUltimateMembersLogger"
1078
- msgid "Logged in"
1079
  msgstr ""
1080
 
1081
- #: loggers/SimpleCommentsLogger.php:97
1082
- msgctxt "A comment was added to the database by a non-logged in internet user"
1083
- msgid "Added a comment to {comment_post_type} \"{comment_post_title}\""
1084
  msgstr ""
1085
 
1086
- #: loggers/SimpleCommentsLogger.php:103
1087
- msgctxt "A comment was added to the database by a logged in user"
1088
- msgid "Added a comment to {comment_post_type} \"{comment_post_title}\""
1089
  msgstr ""
1090
 
1091
- #: loggers/SimpleCommentsLogger.php:109
1092
- msgctxt "A comment was approved"
1093
- msgid ""
1094
- "Approved a comment to \"{comment_post_title}\" by {comment_author} "
1095
- "({comment_author_email})"
1096
  msgstr ""
1097
 
1098
- #: loggers/SimpleCommentsLogger.php:115
1099
- msgctxt "A comment was was unapproved"
1100
- msgid ""
1101
- "Unapproved a comment to \"{comment_post_title}\" by {comment_author} "
1102
- "({comment_author_email})"
1103
  msgstr ""
1104
 
1105
- #: loggers/SimpleCommentsLogger.php:121
1106
- msgctxt "A comment was marked as spam"
1107
- msgid "Marked a comment to post \"{comment_post_title}\" as spam"
1108
  msgstr ""
1109
 
1110
- #: loggers/SimpleCommentsLogger.php:127
1111
- msgctxt "A comment was marked moved to the trash"
1112
- msgid ""
1113
- "Trashed a comment to \"{comment_post_title}\" by {comment_author} "
1114
- "({comment_author_email})"
1115
  msgstr ""
1116
 
1117
- #: loggers/SimpleCommentsLogger.php:133
1118
- msgctxt "A comment was restored from the trash"
1119
- msgid ""
1120
- "Restored a comment to \"{comment_post_title}\" by {comment_author} "
1121
- "({comment_author_email}) from the trash"
1122
  msgstr ""
1123
 
1124
- #: loggers/SimpleCommentsLogger.php:139
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1125
  msgctxt "A comment was deleted"
1126
  msgid ""
1127
  "Deleted a comment to \"{comment_post_title}\" by {comment_author} "
1128
  "({comment_author_email})"
1129
  msgstr ""
1130
 
1131
- #: loggers/SimpleCommentsLogger.php:145
1132
  msgctxt "A comment was edited"
1133
  msgid ""
1134
  "Edited a comment to \"{comment_post_title}\" by {comment_author} "
1135
  "({comment_author_email})"
1136
  msgstr ""
1137
 
1138
- #: loggers/SimpleCommentsLogger.php:152
1139
  msgctxt "A trackback was added to the database by a non-logged in internet user"
1140
  msgid "Added a trackback to {comment_post_type} \"{comment_post_title}\""
1141
  msgstr ""
1142
 
1143
- #: loggers/SimpleCommentsLogger.php:207
1144
  msgctxt "A trackback was added to the database by a non-logged in internet user"
1145
  msgid "Added a pingback to {comment_post_type} \"{comment_post_title}\""
1146
  msgstr ""
1147
 
1148
- #: loggers/SimpleCommentsLogger.php:158
1149
  msgctxt "A trackback was added to the database by a logged in user"
1150
  msgid "Added a trackback to {comment_post_type} \"{comment_post_title}\""
1151
  msgstr ""
1152
 
1153
- #: loggers/SimpleCommentsLogger.php:164
1154
  msgctxt "A trackback was approved"
1155
  msgid ""
1156
  "Approved a trackback to \"{comment_post_title}\" by {comment_author} "
1157
  "({comment_author_email})"
1158
  msgstr ""
1159
 
1160
- #: loggers/SimpleCommentsLogger.php:170
1161
  msgctxt "A trackback was was unapproved"
1162
  msgid ""
1163
  "Unapproved a trackback to \"{comment_post_title}\" by {comment_author} "
1164
  "({comment_author_email})"
1165
  msgstr ""
1166
 
1167
- #: loggers/SimpleCommentsLogger.php:176
1168
  msgctxt "A trackback was marked as spam"
1169
  msgid "Marked a trackback to post \"{comment_post_title}\" as spam"
1170
  msgstr ""
1171
 
1172
- #: loggers/SimpleCommentsLogger.php:182
1173
  msgctxt "A trackback was marked moved to the trash"
1174
  msgid ""
1175
  "Trashed a trackback to \"{comment_post_title}\" by {comment_author} "
1176
  "({comment_author_email})"
1177
  msgstr ""
1178
 
1179
- #: loggers/SimpleCommentsLogger.php:188
1180
  msgctxt "A trackback was restored from the trash"
1181
  msgid ""
1182
  "Restored a trackback to \"{comment_post_title}\" by {comment_author} "
1183
  "({comment_author_email}) from the trash"
1184
  msgstr ""
1185
 
1186
- #: loggers/SimpleCommentsLogger.php:194
1187
  msgctxt "A trackback was deleted"
1188
  msgid ""
1189
  "Deleted a trackback to \"{comment_post_title}\" by {comment_author} "
1190
  "({comment_author_email})"
1191
  msgstr ""
1192
 
1193
- #: loggers/SimpleCommentsLogger.php:200
1194
  msgctxt "A trackback was edited"
1195
  msgid ""
1196
  "Edited a trackback to \"{comment_post_title}\" by {comment_author} "
1197
  "({comment_author_email})"
1198
  msgstr ""
1199
 
1200
- #: loggers/SimpleCommentsLogger.php:213
1201
  msgctxt "A pingback was added to the database by a logged in user"
1202
  msgid "Added a pingback to {comment_post_type} \"{comment_post_title}\""
1203
  msgstr ""
1204
 
1205
- #: loggers/SimpleCommentsLogger.php:219
1206
  msgctxt "A pingback was approved"
1207
  msgid ""
1208
  "Approved a pingback to \"{comment_post_title}\" by \"{comment_author}\"\" "
1209
  "({comment_author_email})"
1210
  msgstr ""
1211
 
1212
- #: loggers/SimpleCommentsLogger.php:225
1213
  msgctxt "A pingback was was unapproved"
1214
  msgid ""
1215
  "Unapproved a pingback to \"{comment_post_title}\" by \"{comment_author}\" "
1216
  "({comment_author_email})"
1217
  msgstr ""
1218
 
1219
- #: loggers/SimpleCommentsLogger.php:231
1220
  msgctxt "A pingback was marked as spam"
1221
  msgid "Marked a pingback to post \"{comment_post_title}\" as spam"
1222
  msgstr ""
1223
 
1224
- #: loggers/SimpleCommentsLogger.php:237
1225
  msgctxt "A pingback was marked moved to the trash"
1226
  msgid ""
1227
  "Trashed a pingback to \"{comment_post_title}\" by {comment_author} "
1228
  "({comment_author_email})"
1229
  msgstr ""
1230
 
1231
- #: loggers/SimpleCommentsLogger.php:243
1232
  msgctxt "A pingback was restored from the trash"
1233
  msgid ""
1234
  "Restored a pingback to \"{comment_post_title}\" by {comment_author} "
1235
  "({comment_author_email}) from the trash"
1236
  msgstr ""
1237
 
1238
- #: loggers/SimpleCommentsLogger.php:249
1239
  msgctxt "A pingback was deleted"
1240
  msgid ""
1241
  "Deleted a pingback to \"{comment_post_title}\" by {comment_author} "
1242
  "({comment_author_email})"
1243
  msgstr ""
1244
 
1245
- #: loggers/SimpleCommentsLogger.php:255
1246
  msgctxt "A pingback was edited"
1247
  msgid ""
1248
  "Edited a pingback to \"{comment_post_title}\" by {comment_author} "
1249
  "({comment_author_email})"
1250
  msgstr ""
1251
 
1252
- #: loggers/SimpleCommentsLogger.php:266
1253
  msgctxt "Comments logger: search"
1254
  msgid "Comments"
1255
  msgstr ""
1256
 
1257
- #: loggers/SimpleCommentsLogger.php:267
1258
  msgctxt "Comments logger: search"
1259
  msgid "All comments activity"
1260
  msgstr ""
1261
 
1262
- #: loggers/SimpleCommentsLogger.php:269
1263
  msgctxt "Comments logger: search"
1264
  msgid "Added comments"
1265
  msgstr ""
1266
 
1267
- #: loggers/SimpleCommentsLogger.php:277
1268
  msgctxt "Comments logger: search"
1269
  msgid "Edited comments"
1270
  msgstr ""
1271
 
1272
- #: loggers/SimpleCommentsLogger.php:282
1273
  msgctxt "Comments logger: search"
1274
- msgid "Approved comments"
1275
  msgstr ""
1276
 
1277
- #: loggers/SimpleCommentsLogger.php:287
1278
  msgctxt "Comments logger: search"
1279
  msgid "Held comments"
1280
  msgstr ""
1281
 
1282
- #: loggers/SimpleCommentsLogger.php:292
1283
  msgctxt "Comments logger: search"
1284
  msgid "Comments status changed to spam"
1285
  msgstr ""
1286
 
1287
- #: loggers/SimpleCommentsLogger.php:297
1288
  msgctxt "Comments logger: search"
1289
  msgid "Trashed comments"
1290
  msgstr ""
1291
 
1292
- #: loggers/SimpleCommentsLogger.php:302
1293
  msgctxt "Comments logger: search"
1294
  msgid "Untrashed comments"
1295
  msgstr ""
1296
 
1297
- #: loggers/SimpleCommentsLogger.php:307
1298
  msgctxt "Comments logger: search"
1299
  msgid "Deleted comments"
1300
  msgstr ""
1301
 
1302
- #: loggers/SimpleCommentsLogger.php:604 loggers/SimpleCommentsLogger.php:617
1303
- #: loggers/SimpleCommentsLogger.php:631
1304
  msgctxt "comments logger - detailed output comment status"
1305
  msgid "Status"
1306
  msgstr ""
1307
 
1308
- #: loggers/SimpleCommentsLogger.php:606 loggers/SimpleCommentsLogger.php:619
1309
- #: loggers/SimpleCommentsLogger.php:633
1310
  msgctxt "comments logger - detailed output author"
1311
  msgid "Name"
1312
  msgstr ""
1313
 
1314
- #: loggers/SimpleCommentsLogger.php:607 loggers/SimpleCommentsLogger.php:620
1315
- #: loggers/SimpleCommentsLogger.php:634
1316
  msgctxt "comments logger - detailed output email"
1317
  msgid "Email"
1318
  msgstr ""
1319
 
1320
- #: loggers/SimpleCommentsLogger.php:608 loggers/SimpleCommentsLogger.php:621
1321
  msgctxt "comments logger - detailed output content"
1322
  msgid "Content"
1323
  msgstr ""
1324
 
1325
- #: loggers/SimpleCommentsLogger.php:635
1326
  msgctxt "comments logger - detailed output content"
1327
  msgid "Comment"
1328
  msgstr ""
1329
 
1330
- #: loggers/SimpleCommentsLogger.php:771
1331
  msgctxt "comments logger - edit comment"
1332
  msgid "View/Edit"
1333
  msgstr ""
1334
 
1335
- #: loggers/SimpleCoreUpdatesLogger.php:72
1336
  msgctxt "User logger: search"
1337
  msgid "WordPress Core"
1338
  msgstr ""
1339
 
1340
- #: loggers/SimpleCoreUpdatesLogger.php:74
1341
  msgctxt "User logger: search"
1342
  msgid "WordPress core updates"
1343
  msgstr ""
1344
 
1345
- #: loggers/SimpleUserLogger.php:56
1346
  msgctxt "User logger: search"
1347
  msgid "Users"
1348
  msgstr ""
1349
 
1350
- #: loggers/SimpleUserLogger.php:57
1351
  msgctxt "User logger: search"
1352
  msgid "All user activity"
1353
  msgstr ""
1354
 
1355
- #: loggers/SimpleUserLogger.php:59
1356
  msgctxt "User logger: search"
1357
  msgid "Successful user logins"
1358
  msgstr ""
1359
 
1360
- #: loggers/SimpleUserLogger.php:63
1361
  msgctxt "User logger: search"
1362
  msgid "Failed user logins"
1363
  msgstr ""
1364
 
1365
- #: loggers/SimpleUserLogger.php:67
1366
  msgctxt "User logger: search"
1367
  msgid "User logouts"
1368
  msgstr ""
1369
 
1370
- #: loggers/SimpleUserLogger.php:70
1371
  msgctxt "User logger: search"
1372
  msgid "Created users"
1373
  msgstr ""
1374
 
1375
- #: loggers/SimpleUserLogger.php:73
1376
  msgctxt "User logger: search"
1377
  msgid "User profile updates"
1378
  msgstr ""
1379
 
1380
- #: loggers/SimpleUserLogger.php:76
1381
  msgctxt "User logger: search"
1382
  msgid "User deletions"
1383
  msgstr ""
@@ -1392,16 +2062,11 @@ msgctxt "Export logger: search"
1392
  msgid "Created exports"
1393
  msgstr ""
1394
 
1395
- #: loggers/SimpleLogger.php:231
1396
  msgctxt "header output when initiator is the currently logged in user"
1397
  msgid "You"
1398
  msgstr ""
1399
 
1400
- #: loggers/SimpleLogger.php:322
1401
- msgctxt "Event header output, when initiator is unknown"
1402
- msgid "Other"
1403
- msgstr ""
1404
-
1405
  #: loggers/SimpleMediaLogger.php:31
1406
  msgctxt "Media logger: search"
1407
  msgid "Media"
@@ -1452,266 +2117,588 @@ msgctxt "Menu updates logger: search"
1452
  msgid "Deleted menus"
1453
  msgstr ""
1454
 
1455
- #: loggers/SimpleMenuLogger.php:329
1456
  msgctxt "menu logger"
1457
  msgid "%1$s menu item added"
1458
  msgid_plural "%1$s menu items added"
1459
  msgstr[0] ""
1460
  msgstr[1] ""
1461
 
1462
- #: loggers/SimpleMenuLogger.php:336
1463
  msgctxt "menu logger"
1464
  msgid "%1$s menu item removed"
1465
  msgid_plural "%1$s menu items removed"
1466
  msgstr[0] ""
1467
  msgstr[1] ""
1468
 
1469
- #: loggers/SimpleOptionsLogger.php:155
1470
  msgctxt "Options logger: search"
1471
  msgid "Options"
1472
  msgstr ""
1473
 
1474
- #: loggers/SimpleOptionsLogger.php:157
1475
  msgctxt "Options logger: search"
1476
  msgid "Changed options"
1477
  msgstr ""
1478
 
1479
- #: loggers/SimplePluginLogger.php:27
1480
  msgctxt "Plugin was non-silently activated by a user"
1481
  msgid "Activated plugin \"{plugin_name}\""
1482
  msgstr ""
1483
 
1484
- #: loggers/SimplePluginLogger.php:33
1485
  msgctxt "Plugin was non-silently deactivated by a user"
1486
  msgid "Deactivated plugin \"{plugin_name}\""
1487
  msgstr ""
1488
 
1489
- #: loggers/SimplePluginLogger.php:39
1490
  msgctxt "Plugin was installed"
1491
  msgid "Installed plugin \"{plugin_name}\""
1492
  msgstr ""
1493
 
1494
- #: loggers/SimplePluginLogger.php:45
1495
  msgctxt "Plugin failed to install"
1496
  msgid "Failed to install plugin \"{plugin_name}\""
1497
  msgstr ""
1498
 
1499
- #: loggers/SimplePluginLogger.php:51
1500
  msgctxt "Plugin was updated"
1501
  msgid ""
1502
  "Updated plugin \"{plugin_name}\" to version {plugin_version} from "
1503
  "{plugin_prev_version}"
1504
  msgstr ""
1505
 
1506
- #: loggers/SimplePluginLogger.php:57
1507
  msgctxt "Plugin update failed"
1508
- msgid "Updated plugin \"{plugin_name}\""
1509
  msgstr ""
1510
 
1511
- #: loggers/SimplePluginLogger.php:63
1512
- msgctxt "Plugin file edited"
1513
- msgid "Edited plugin file \"{plugin_edited_file}\""
1514
- msgstr ""
1515
-
1516
- #: loggers/SimplePluginLogger.php:69
1517
  msgctxt "Plugin files was deleted"
1518
  msgid "Deleted plugin \"{plugin_name}\""
1519
  msgstr ""
1520
 
1521
- #: loggers/SimplePluginLogger.php:76
1522
  msgctxt "Plugin was updated in bulk"
1523
  msgid ""
1524
  "Updated plugin \"{plugin_name}\" to {plugin_version} from "
1525
  "{plugin_prev_version}"
1526
  msgstr ""
1527
 
1528
- #: loggers/SimplePluginLogger.php:84
 
 
 
 
 
 
 
1529
  msgctxt "Plugin logger: search"
1530
  msgid "Plugins"
1531
  msgstr ""
1532
 
1533
- #: loggers/SimplePluginLogger.php:85
1534
  msgctxt "Plugin logger: search"
1535
  msgid "All plugin activity"
1536
  msgstr ""
1537
 
1538
- #: loggers/SimplePluginLogger.php:87
1539
  msgctxt "Plugin logger: search"
1540
  msgid "Activated plugins"
1541
  msgstr ""
1542
 
1543
- #: loggers/SimplePluginLogger.php:90
1544
  msgctxt "Plugin logger: search"
1545
  msgid "Deactivated plugins"
1546
  msgstr ""
1547
 
1548
- #: loggers/SimplePluginLogger.php:93
1549
  msgctxt "Plugin logger: search"
1550
  msgid "Installed plugins"
1551
  msgstr ""
1552
 
1553
- #: loggers/SimplePluginLogger.php:96
1554
  msgctxt "Plugin logger: search"
1555
  msgid "Failed plugin installs"
1556
  msgstr ""
1557
 
1558
- #: loggers/SimplePluginLogger.php:99
1559
  msgctxt "Plugin logger: search"
1560
  msgid "Updated plugins"
1561
  msgstr ""
1562
 
1563
- #: loggers/SimplePluginLogger.php:103
1564
  msgctxt "Plugin logger: search"
1565
  msgid "Failed plugin updates"
1566
  msgstr ""
1567
 
1568
- #: loggers/SimplePluginLogger.php:106
1569
- msgctxt "Plugin logger: search"
1570
- msgid "Edited plugin files"
1571
- msgstr ""
1572
-
1573
- #: loggers/SimplePluginLogger.php:109
1574
  msgctxt "Plugin logger: search"
1575
  msgid "Deleted plugins"
1576
  msgstr ""
1577
 
1578
- #: loggers/SimplePluginLogger.php:1074
1579
  msgctxt "plugin logger - detailed output"
1580
  msgid "Description"
1581
  msgstr ""
1582
 
1583
- #: loggers/SimplePluginLogger.php:1075
1584
  msgctxt "plugin logger - detailed output install source"
1585
  msgid "Source"
1586
  msgstr ""
1587
 
1588
- #: loggers/SimplePluginLogger.php:1076
1589
  msgctxt "plugin logger - detailed output install source"
1590
  msgid "Source file name"
1591
  msgstr ""
1592
 
1593
- #: loggers/SimplePluginLogger.php:1077
1594
  msgctxt "plugin logger - detailed output version"
1595
  msgid "Version"
1596
  msgstr ""
1597
 
1598
- #: loggers/SimplePluginLogger.php:1078
1599
  msgctxt "plugin logger - detailed output author"
1600
  msgid "Author"
1601
  msgstr ""
1602
 
1603
- #: loggers/SimplePluginLogger.php:1079
1604
  msgctxt "plugin logger - detailed output url"
1605
  msgid "URL"
1606
  msgstr ""
1607
 
1608
- #: loggers/SimplePluginLogger.php:1187 loggers/SimplePluginLogger.php:1206
1609
- #: loggers/SimplePluginLogger.php:1245
1610
  msgctxt "plugin logger: plugin info thickbox title view all info"
1611
  msgid "View plugin info"
1612
  msgstr ""
1613
 
1614
- #: loggers/SimplePluginLogger.php:1221
1615
  msgctxt "plugin logger: plugin info thickbox title"
1616
  msgid "View plugin info"
1617
  msgstr ""
1618
 
1619
- #: loggers/SimplePluginLogger.php:1225
1620
  msgctxt "plugin logger: plugin info thickbox title"
1621
  msgid "View changelog"
1622
  msgstr ""
1623
 
1624
- #: loggers/SimplePostLogger.php:127
1625
  msgctxt "Post logger: search"
1626
  msgid "Posts & Pages"
1627
  msgstr ""
1628
 
1629
- #: loggers/SimplePostLogger.php:128
1630
  msgctxt "Post logger: search"
1631
  msgid "All posts & pages activity"
1632
  msgstr ""
1633
 
1634
- #: loggers/SimplePostLogger.php:130
1635
  msgctxt "Post logger: search"
1636
  msgid "Posts created"
1637
  msgstr ""
1638
 
1639
- #: loggers/SimplePostLogger.php:133
1640
  msgctxt "Post logger: search"
1641
  msgid "Posts updated"
1642
  msgstr ""
1643
 
1644
- #: loggers/SimplePostLogger.php:136
1645
  msgctxt "Post logger: search"
1646
  msgid "Posts trashed"
1647
  msgstr ""
1648
 
1649
- #: loggers/SimplePostLogger.php:139
1650
  msgctxt "Post logger: search"
1651
  msgid "Posts deleted"
1652
  msgstr ""
1653
 
1654
- #: loggers/SimplePostLogger.php:142
1655
  msgctxt "Post logger: search"
1656
  msgid "Posts restored"
1657
  msgstr ""
1658
 
1659
- #: loggers/SimpleThemeLogger.php:37
1660
  msgctxt "Theme logger: search"
1661
  msgid "Themes & Widgets"
1662
  msgstr ""
1663
 
1664
- #: loggers/SimpleThemeLogger.php:38
1665
  msgctxt "Theme logger: search"
1666
  msgid "All theme activity"
1667
  msgstr ""
1668
 
1669
- #: loggers/SimpleThemeLogger.php:40
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1670
  msgctxt "Theme logger: search"
1671
  msgid "Switched themes"
1672
  msgstr ""
1673
 
1674
- #: loggers/SimpleThemeLogger.php:43
1675
  msgctxt "Theme logger: search"
1676
  msgid "Changed appearance of themes"
1677
  msgstr ""
1678
 
1679
- #: loggers/SimpleThemeLogger.php:46
1680
  msgctxt "Theme logger: search"
1681
  msgid "Added widgets"
1682
  msgstr ""
1683
 
1684
- #: loggers/SimpleThemeLogger.php:49
1685
  msgctxt "Theme logger: search"
1686
  msgid "Removed widgets"
1687
  msgstr ""
1688
 
1689
- #: loggers/SimpleThemeLogger.php:52
1690
  msgctxt "Theme logger: search"
1691
  msgid "Changed widgets order"
1692
  msgstr ""
1693
 
1694
- #: loggers/SimpleThemeLogger.php:55
1695
  msgctxt "Theme logger: search"
1696
  msgid "Edited widgets"
1697
  msgstr ""
1698
 
1699
- #: loggers/SimpleThemeLogger.php:58
1700
  msgctxt "Theme logger: search"
1701
  msgid "Background of themes changed"
1702
  msgstr ""
1703
 
1704
- #: loggers/SimpleUserLogger.php:38
1705
  msgctxt "User destroys other login sessions for themself"
1706
  msgid "Logged out from all other sessions"
1707
  msgstr ""
1708
 
1709
- #: loggers/SimpleUserLogger.php:47
1710
  msgctxt "User destroys all login sessions for a user"
1711
  msgid "Logged out \"{user_display_name}\" from all sessions"
1712
  msgstr ""
1713
 
1714
- #: templates/settings-statsRowsPerDay.php:38
1715
- msgctxt "stats: date in rows per day chart"
1716
- msgid "M j"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1717
  msgstr ""
1
+ # Copyright (C) 2019 Simple History
2
  # This file is distributed under the same license as the Simple History package.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: Simple History 2.29.2\n"
6
  "Report-Msgid-Bugs-To: http://wordpress.org/support/plugin/Simple-History\n"
7
+ "POT-Creation-Date: 2019-04-30 21:11:01+00:00\n"
8
  "MIME-Version: 1.0\n"
9
  "Content-Type: text/plain; charset=utf-8\n"
10
  "Content-Transfer-Encoding: 8bit\n"
11
+ "PO-Revision-Date: 2019-MO-DA HO:MI+ZONE\n"
12
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13
  "Language-Team: LANGUAGE <LL@li.org>\n"
14
  "X-Generator: grunt-wp-i18n 0.4.9\n"
29
  msgstr ""
30
 
31
  #: dropins/SimpleHistoryDonateDropin.php:74
32
+ msgid "If you find Simple History useful please <a href=\"%1$s\">donate</a>."
 
 
33
  msgstr ""
34
 
35
+ #: dropins/SimpleHistoryFilterDropin.php:60
36
  msgid "Filter history"
37
  msgstr ""
38
 
39
+ #: dropins/SimpleHistoryFilterDropin.php:165
40
  msgid "All dates"
41
  msgstr ""
42
 
43
+ #: dropins/SimpleHistoryFilterDropin.php:268
44
+ #: dropins/SimpleHistoryFilterDropin.php:432
 
 
 
 
45
  msgid "Search events"
46
  msgstr ""
47
 
48
+ #: dropins/SimpleHistoryFilterDropin.php:291
49
  msgid "All log levels"
50
  msgstr ""
51
 
52
+ #: dropins/SimpleHistoryFilterDropin.php:328
53
  msgid "All messages"
54
  msgstr ""
55
 
56
+ #: dropins/SimpleHistoryFilterDropin.php:420
57
  msgid "All users"
58
  msgstr ""
59
 
60
+ #: dropins/SimpleHistoryFilterDropin.php:440
61
  msgid "Search"
62
  msgstr ""
63
 
64
+ #: dropins/SimpleHistoryFilterDropin.php:585
65
+ #. translators: 1: month number (01, 02, etc.), 2: month abbreviation
66
+ msgid "%1$s-%2$s"
67
+ msgstr ""
68
+
69
+ #: dropins/SimpleHistoryFilterDropin.php:590
70
+ msgid "Day"
71
+ msgstr ""
72
+
73
+ #: dropins/SimpleHistoryFilterDropin.php:591
74
+ msgid "Year"
75
+ msgstr ""
76
+
77
+ #: dropins/SimpleHistoryFilterDropin.php:598
78
+ #. translators: 1: month, 2: day, 3: year
79
+ msgid "%1$s %2$s, %3$s"
80
+ msgstr ""
81
+
82
+ #: dropins/SimpleHistoryNewRowsNotifier.php:89
83
  msgid "1 new event"
84
  msgid_plural "%d new events"
85
  msgstr[0] ""
86
  msgstr[1] ""
87
 
88
+ #: dropins/SimpleHistoryRSSDropin.php:68
89
+ msgid "Enable"
90
+ msgstr ""
91
+
92
+ #: dropins/SimpleHistoryRSSDropin.php:79
93
  msgid "Address"
94
  msgstr ""
95
 
96
+ #: dropins/SimpleHistoryRSSDropin.php:88
97
  msgid "Regenerate"
98
  msgstr ""
99
 
100
+ #: dropins/SimpleHistoryRSSDropin.php:106
101
  msgid "Created new secret RSS address"
102
  msgstr ""
103
 
104
+ #: dropins/SimpleHistoryRSSDropin.php:143
105
+ msgid "Enable RSS feed"
106
+ msgstr ""
107
+
108
+ #: dropins/SimpleHistoryRSSDropin.php:207
109
+ #: dropins/SimpleHistoryRSSDropin.php:302
110
  msgid "History for %s"
111
  msgstr ""
112
 
113
+ #: dropins/SimpleHistoryRSSDropin.php:208
114
+ #: dropins/SimpleHistoryRSSDropin.php:303
115
  msgid "WordPress History for %s"
116
  msgstr ""
117
 
118
+ #: dropins/SimpleHistoryRSSDropin.php:262
119
  msgid "Severity level: %1$s"
120
  msgstr ""
121
 
122
+ #: dropins/SimpleHistoryRSSDropin.php:276
123
  msgid "+%1$s occasion"
124
  msgid_plural "+%1$s occasions"
125
  msgstr[0] ""
126
  msgstr[1] ""
127
 
128
+ #: dropins/SimpleHistoryRSSDropin.php:306
129
  msgid "Wrong RSS secret"
130
  msgstr ""
131
 
132
+ #: dropins/SimpleHistoryRSSDropin.php:307
133
  msgid ""
134
  "Your RSS secret for Simple History RSS feed is wrong. Please see WordPress "
135
  "settings for current link to the RSS feed."
136
  msgstr ""
137
 
138
+ #: dropins/SimpleHistoryRSSDropin.php:354
139
  msgid ""
140
  "You can generate a new address for the RSS feed. This is useful if you "
141
  "think that the address has fallen into the wrong hands."
142
  msgstr ""
143
 
144
+ #: dropins/SimpleHistoryRSSDropin.php:361
145
  msgid "Generate new address"
146
  msgstr ""
147
 
148
+ #: dropins/SimpleHistoryRSSDropin.php:394
149
  msgid ""
150
  "Simple History has a RSS feed which you can subscribe to and receive log "
151
  "updates. Make sure you only share the feed with people you trust, since it "
152
  "can contain sensitive or confidential information."
153
  msgstr ""
154
 
155
+ #: dropins/SimpleHistorySettingsDebugDropin.php:23
156
+ msgid "Debug"
157
+ msgstr ""
158
+
159
  #: dropins/SimpleHistorySettingsLogtestDropin.php:22
160
  msgid "Test data (debug)"
161
  msgstr ""
162
 
163
+ #: dropins/SimpleHistorySettingsLogtestDropin.php:226
164
  msgid "Plugin"
165
  msgstr ""
166
 
167
+ #: dropins/SimpleHistorySettingsLogtestDropin.php:229
168
  msgid "Enter title of new page"
169
  msgstr ""
170
 
171
  #: dropins/SimpleHistorySettingsStatsDropin.php:29
172
+ #: dropins/SimpleHistorySidebarStats.php:159
173
  msgid "Stats"
174
  msgstr ""
175
 
176
+ #: dropins/SimpleHistorySidebarDropin.php:182 loggers/SimpleLogger.php:446
177
  msgid "Just now"
178
  msgstr ""
179
 
180
+ #: dropins/SimpleHistorySidebarSettings.php:53 inc/SimpleHistory.php:919
181
+ #: inc/SimpleHistory.php:1359
182
+ msgid "Settings"
183
+ msgstr ""
184
+
185
+ #: dropins/SimpleHistorySidebarSettings.php:72
186
+ #. translators: 1: URL to settings page
187
+ msgid ""
188
+ "<a href=\"%1$s\">Visit the settings page</a> to change things like the "
189
+ "number of events to show and to get access to the RSS feed with all events, "
190
+ "and more."
191
+ msgstr ""
192
+
193
+ #: dropins/SimpleHistorySidebarStats.php:167
194
+ msgid "<b>%1$s events</b> have been logged the last <b>%2$s days</b>."
195
+ msgstr ""
196
+
197
+ #: dropins/SimpleHistorySidebarStats.php:181
198
+ msgid "Number of events per day."
199
+ msgstr ""
200
+
201
+ #: dropins/SimpleHistoryWPCLIDropin.php:86 loggers/SimpleLogger.php:305
202
+ msgid "Deleted user (had id %1$s, email %2$s, login %3$s)"
203
+ msgstr ""
204
+
205
+ #: dropins/SimpleHistoryWPCLIDropin.php:94 loggers/SimpleLogger.php:330
206
+ msgid "Anonymous web user"
207
+ msgstr ""
208
+
209
+ #: dropins/SimpleHistoryWPCLIDropin.php:112
210
+ msgid "Error: parameter \"count\" must be a number"
211
+ msgstr ""
212
+
213
+ #: examples/example-dropin.php:48
214
+ msgid "Example tab"
215
+ msgstr ""
216
+
217
  #: examples/example-logger.php:46
218
  msgid "Got a 404-page when trying to visit \"{request_uri}\""
219
  msgstr ""
220
 
221
+ #: inc/SimpleHistory.php:674
222
  msgid "Sorry, but there are too many similar events to show."
223
  msgstr ""
224
 
225
+ #: inc/SimpleHistory.php:930
 
 
 
 
226
  msgid "Log (debug)"
227
  msgstr ""
228
 
229
+ #: inc/SimpleHistory.php:935
230
  msgid "Styles example (debug)"
231
  msgstr ""
232
 
 
 
233
  #. Plugin Name of the plugin/theme
234
  msgid "Simple History"
235
  msgstr ""
236
 
237
+ #: inc/SimpleHistory.php:1460
238
  msgid "Remove all log items?"
239
  msgstr ""
240
 
241
+ #: inc/SimpleHistory.php:1462
242
  msgid "Go to the first page"
243
  msgstr ""
244
 
245
+ #: inc/SimpleHistory.php:1463
246
  msgid "Go to the previous page"
247
  msgstr ""
248
 
249
+ #: inc/SimpleHistory.php:1464
250
  msgid "Go to the next page"
251
  msgstr ""
252
 
253
+ #: inc/SimpleHistory.php:1465
254
  msgid "Go to the last page"
255
  msgstr ""
256
 
257
+ #: inc/SimpleHistory.php:1466
258
  msgid "Current page"
259
  msgstr ""
260
 
261
+ #: inc/SimpleHistory.php:1468
262
  msgid "Oups, the log could not be loaded right now."
263
  msgstr ""
264
 
265
+ #: inc/SimpleHistory.php:1469
266
  msgid ""
267
  "Hm, the log could not be loaded right now. Perhaps another plugin is giving "
268
  "some errors. Anyway, below is the output I got from the server."
269
  msgstr ""
270
 
271
+ #: inc/SimpleHistory.php:1470
272
  msgid "Your search did not match any history events."
273
  msgstr ""
274
 
275
+ #: inc/SimpleHistory.php:1789
276
+ msgid ""
277
+ "\n"
278
+ "Welcome to Simple History!\n"
279
+ "\n"
280
+ "This is the main history feed. It will contain events that this plugin has "
281
+ "logged.\n"
282
+ msgstr ""
283
+
284
+ #: inc/SimpleHistory.php:1795
285
+ msgid ""
286
+ "\n"
287
+ "Because Simple History was just recently installed, this feed does not "
288
+ "contain much events yet. But keep the plugin activated and soon you will "
289
+ "see detailed information about page edits, plugin updates, user logins, and "
290
+ "much more.\n"
291
+ msgstr ""
292
+
293
+ #: inc/SimpleHistory.php:1836 inc/SimpleHistory.php:1954
294
  msgid "Simple History Settings"
295
  msgstr ""
296
 
297
+ #: inc/SimpleHistory.php:1874
298
  msgid "No valid callback found"
299
  msgstr ""
300
 
301
+ #: inc/SimpleHistory.php:1978
302
  msgid "Cleared database"
303
  msgstr ""
304
 
305
+ #: inc/SimpleHistory.php:2006
306
  msgid "Show history"
307
  msgstr ""
308
 
309
+ #: inc/SimpleHistory.php:2019
310
+ msgid "Number of items per page on the log page"
311
  msgstr ""
312
 
313
+ #: inc/SimpleHistory.php:2031
314
+ msgid "Number of items per page on the dashboard"
315
+ msgstr ""
316
+
317
+ #: inc/SimpleHistory.php:2044
318
  msgid "Clear log"
319
  msgstr ""
320
 
321
+ #: inc/SimpleHistory.php:2208
322
  msgid "on the dashboard"
323
  msgstr ""
324
 
325
+ #: inc/SimpleHistory.php:2213
326
  msgid "as a page under the dashboard menu"
327
  msgstr ""
328
 
329
+ #: inc/SimpleHistory.php:2230
330
  msgid "Items in the database are automatically removed after %1$s days."
331
  msgstr ""
332
 
333
+ #: inc/SimpleHistory.php:2232
334
  msgid "Items in the database are kept forever."
335
  msgstr ""
336
 
337
+ #: inc/SimpleHistory.php:2237
338
  msgid "Clear log now"
339
  msgstr ""
340
 
341
+ #: inc/SimpleHistory.php:2288
342
  msgid "The log for Simple History was cleared ({num_rows} rows were removed)."
343
  msgstr ""
344
 
345
+ #: inc/SimpleHistory.php:2551
346
  msgid "+%1$s similar event"
347
  msgid_plural "+%1$s similar events"
348
  msgstr[0] ""
349
  msgstr[1] ""
350
 
351
+ #: inc/SimpleHistory.php:2558
352
  msgid "Loading…"
353
  msgstr ""
354
 
355
+ #: inc/SimpleHistory.php:2565
356
  msgid "Showing %1$s more"
357
  msgstr ""
358
 
359
+ #: inc/SimpleHistory.php:2604
360
  msgid "Context data"
361
  msgstr ""
362
 
363
+ #: inc/SimpleHistory.php:2605
364
  msgid "This is potentially useful meta data that a logger has saved."
365
  msgstr ""
366
 
367
+ #: inc/SimpleHistory.php:3214
368
  msgid "No events today so far."
369
  msgstr ""
370
 
371
+ #: inc/SimpleHistory.php:3233
372
  msgid "One event today from one user."
373
  msgstr ""
374
 
375
+ #: inc/SimpleHistory.php:3239
376
  msgid "One event today from one source."
377
  msgstr ""
378
 
379
+ #: inc/SimpleHistory.php:3245
380
  msgid "%1$d events today from one user."
381
  msgstr ""
382
 
383
+ #: inc/SimpleHistory.php:3251
384
  msgid "%1$d events today from %2$d users."
385
  msgstr ""
386
 
387
+ #: inc/SimpleHistory.php:3257 inc/SimpleHistory.php:3263
388
  msgid "%1$d events today from one user and one other source."
389
  msgstr ""
390
 
391
+ #: inc/SimpleHistory.php:3269
392
  msgid "%1$d events today from one user and %3$d other sources."
393
  msgstr ""
394
 
395
+ #: inc/SimpleHistory.php:3275
396
  msgid "%1$s events today from %2$d users and %3$d other sources."
397
  msgstr ""
398
 
399
+ #: inc/SimpleHistory.php:3448
400
+ msgid "The slug for a logger in Simple History can be max 30 chars long."
401
+ msgstr ""
402
+
403
+ #: index.php:105
404
+ #. translators: 1: PHP version
405
  msgid ""
406
  "Simple History is a great plugin, but to use it your server must have at "
407
  "least PHP 5.3 installed (you have version %s)."
408
  msgstr ""
409
 
410
+ #: index.php:115
411
+ #. translators: 1: WordPress version
412
+ msgid ""
413
+ "Simple History requires WordPress version 4.5.1 or higher (you have version "
414
+ "%s)."
415
+ msgstr ""
416
+
417
+ #: loggers/AvailableUpdatesLogger.php:35
418
+ msgid "Found an update to WordPress."
419
+ msgstr ""
420
+
421
+ #: loggers/AvailableUpdatesLogger.php:36
422
+ msgid "Found an update to plugin \"{plugin_name}\""
423
+ msgstr ""
424
+
425
+ #: loggers/AvailableUpdatesLogger.php:37
426
+ msgid "Found an update to theme \"{theme_name}\""
427
+ msgstr ""
428
+
429
+ #: loggers/AvailableUpdatesLogger.php:293
430
+ msgid "Available version"
431
+ msgstr ""
432
+
433
+ #: loggers/AvailableUpdatesLogger.php:297
434
+ msgid "Installed version"
435
+ msgstr ""
436
+
437
+ #: loggers/AvailableUpdatesLogger.php:307
438
+ msgid "View all updates"
439
+ msgstr ""
440
+
441
+ #: loggers/FileEditsLogger.php:17
442
+ msgid "Edited file \"{file_name}\" in theme \"{theme_name}\""
443
+ msgstr ""
444
+
445
+ #: loggers/FileEditsLogger.php:18
446
+ msgid "Edited file \"{file_name}\" in plugin \"{plugin_name}\""
447
+ msgstr ""
448
+
449
+ #: loggers/FileEditsLogger.php:238
450
+ msgid "File contents"
451
+ msgstr ""
452
+
453
+ #: loggers/SimpleCategoriesLogger.php:20
454
+ msgid "Categories Logger"
455
+ msgstr ""
456
+
457
+ #: loggers/SimpleCategoriesLogger.php:23
458
+ msgid "Added term \"{term_name}\" in taxonomy \"{term_taxonomy}\""
459
+ msgstr ""
460
+
461
+ #: loggers/SimpleCategoriesLogger.php:24
462
+ msgid "Deleted term \"{term_name}\" from taxonomy \"{term_taxonomy}\""
463
+ msgstr ""
464
+
465
+ #: loggers/SimpleCategoriesLogger.php:25
466
+ msgid "Edited term \"{to_term_name}\" in taxonomy \"{to_term_taxonomy}\""
467
+ msgstr ""
468
+
469
+ #: loggers/SimpleCommentsLogger.php:695
470
  msgid "Spam"
471
  msgstr ""
472
 
473
+ #: loggers/SimpleCommentsLogger.php:697
474
  msgid "Approved"
475
  msgstr ""
476
 
477
+ #: loggers/SimpleCommentsLogger.php:699
478
  msgid "Pending"
479
  msgstr ""
480
 
481
+ #: loggers/SimpleCommentsLogger.php:712
482
  msgid "Trackback"
483
  msgstr ""
484
 
485
+ #: loggers/SimpleCommentsLogger.php:714
486
  msgid "Pingback"
487
  msgstr ""
488
 
489
+ #: loggers/SimpleCommentsLogger.php:716
490
  msgid "Comment"
491
  msgstr ""
492
 
493
+ #: loggers/SimpleCoreUpdatesLogger.php:64
494
  msgid "Updated WordPress to {new_version} from {prev_version}"
495
  msgstr ""
496
 
497
+ #: loggers/SimpleCoreUpdatesLogger.php:65
498
  msgid "WordPress auto-updated to {new_version} from {prev_version}"
499
  msgstr ""
500
 
501
+ #: loggers/SimpleCoreUpdatesLogger.php:66
502
  msgid "WordPress database version updated to {new_version} from {prev_version}"
503
  msgstr ""
504
 
514
  msgid "Created XML export"
515
  msgstr ""
516
 
517
+ #: loggers/SimpleLegacyLogger.php:86
518
  msgid "By %s"
519
  msgstr ""
520
 
521
+ #: loggers/SimpleLegacyLogger.php:91
522
  msgid "%d occasions"
523
  msgstr ""
524
 
525
+ #: loggers/SimpleLogger.php:359
 
 
 
 
 
 
 
 
526
  msgid "Anonymous user from %1$s"
527
  msgstr ""
528
 
529
+ #: loggers/SimpleLogger.php:449
530
+ #. Translators: Date format for log row header, see http:php.net/date
531
  msgid "M j, Y \\a\\t G:i"
532
  msgstr ""
533
 
534
+ #: loggers/SimpleLogger.php:455
535
+ #. Translators: 1: last modified date and time in human time diff-format
536
  msgid "%1$s ago"
537
  msgstr ""
538
 
539
+ #: loggers/SimpleLogger.php:465
540
+ msgid "%1$s local time %3$s (%2$s GMT time)"
541
+ msgstr ""
542
+
543
  #: loggers/SimpleMediaLogger.php:25
544
  msgid "Created {post_type} \"{attachment_title}\""
545
  msgstr ""
560
  msgid "Uploaded {post_type} <a href=\"{edit_link}\">\"{attachment_title}\"</a>"
561
  msgstr ""
562
 
563
+ #: loggers/SimpleMediaLogger.php:240
564
  msgid "{attachment_thumb}"
565
  msgstr ""
566
 
567
+ #: loggers/SimpleMediaLogger.php:248
568
  msgid "{attachment_size_format}"
569
  msgstr ""
570
 
571
+ #: loggers/SimpleMediaLogger.php:249
572
  msgid "{attachment_filetype_extension}"
573
  msgstr ""
574
 
575
+ #: loggers/SimpleMediaLogger.php:253
576
  msgid "{full_image_width} × {full_image_height}"
577
  msgstr ""
578
 
596
  msgid "Updated menu locations"
597
  msgstr ""
598
 
599
+ #: loggers/SimpleOptionsLogger.php:26
600
  msgid "Updated option \"{option}\""
601
  msgstr ""
602
 
603
+ #: loggers/SimpleOptionsLogger.php:225
604
+ msgid "&hellip;"
605
+ msgstr ""
606
+
607
+ #: loggers/SimpleOptionsLogger.php:241 loggers/SimpleOptionsLogger.php:368
608
+ #: loggers/SimpleOptionsLogger.php:377 loggers/SimpleOptionsLogger.php:480
609
+ #: loggers/SimpleThemeLogger.php:783
610
  msgid "New value"
611
  msgstr ""
612
 
613
+ #: loggers/SimpleOptionsLogger.php:247 loggers/SimpleOptionsLogger.php:394
614
+ #: loggers/SimpleOptionsLogger.php:404 loggers/SimpleOptionsLogger.php:470
615
+ #: loggers/SimpleThemeLogger.php:795
616
  msgid "Old value"
617
  msgstr ""
618
 
619
+ #: loggers/SimpleOptionsLogger.php:268 loggers/SimpleOptionsLogger.php:285
620
  msgid "Settings page"
621
  msgstr ""
622
 
623
+ #: loggers/SimpleOptionsLogger.php:369 loggers/SimpleOptionsLogger.php:395
624
+ msgid "Page %1$s"
625
+ msgstr ""
626
+
627
+ #: loggers/SimpleOptionsLogger.php:378 loggers/SimpleOptionsLogger.php:405
628
+ msgid "Your latests posts"
629
+ msgstr ""
630
+
631
+ #: loggers/SimplePluginLogger.php:307
632
  msgid "You don't have access to this page."
633
  msgstr ""
634
 
635
+ #: loggers/SimplePluginLogger.php:313 loggers/SimplePluginLogger.php:318
636
  msgid "Could not find GitHub repository."
637
  msgstr ""
638
 
639
+ #: loggers/SimplePluginLogger.php:340
640
  msgid ""
641
+ "Viewing <code>readme</code> from repository <code><a target=\"_blank\" "
642
+ "href=\"%1$s\">%2$s</a></code>."
643
  msgstr ""
644
 
645
+ #: loggers/SimplePluginLogger.php:404
646
  msgid "You do not have sufficient permissions to delete plugins for this site."
647
  msgstr ""
648
 
649
+ #: loggers/SimplePluginLogger.php:1081
650
  msgid "WordPress Plugin Repository"
651
  msgstr ""
652
 
653
+ #: loggers/SimplePluginLogger.php:1084
654
  msgid "Uploaded ZIP archive"
655
  msgstr ""
656
 
657
+ #: loggers/SimplePostLogger.php:224
658
  msgid "Created {post_type} \"{post_title}\""
659
  msgstr ""
660
 
661
+ #: loggers/SimplePostLogger.php:225
662
  msgid "Updated {post_type} \"{post_title}\""
663
  msgstr ""
664
 
665
+ #: loggers/SimplePostLogger.php:226
666
  msgid "Restored {post_type} \"{post_title}\" from trash"
667
  msgstr ""
668
 
669
+ #: loggers/SimplePostLogger.php:227 loggers/SimplePostLogger.php:996
670
  msgid "Deleted {post_type} \"{post_title}\""
671
  msgstr ""
672
 
673
+ #: loggers/SimplePostLogger.php:228
674
  msgid "Moved {post_type} \"{post_title}\" to the trash"
675
  msgstr ""
676
 
677
+ #: loggers/SimplePostLogger.php:992
678
  msgid "Updated {post_type} <a href=\"{edit_link}\">\"{post_title}\"</a>"
679
  msgstr ""
680
 
681
+ #: loggers/SimplePostLogger.php:1000
682
  msgid "Created {post_type} <a href=\"{edit_link}\">\"{post_title}\"</a>"
683
  msgstr ""
684
 
685
+ #: loggers/SimplePostLogger.php:1005
686
  msgid "Moved {post_type} <a href=\"{edit_link}\">\"{post_title}\"</a> to the trash"
687
  msgstr ""
688
 
689
+ #: loggers/SimplePostLogger.php:1057
690
  msgid "Title"
691
  msgstr ""
692
 
693
+ #: loggers/SimplePostLogger.php:1072
694
  msgid "Content"
695
  msgstr ""
696
 
697
+ #: loggers/SimplePostLogger.php:1084
698
  msgid "Status"
699
  msgstr ""
700
 
701
+ #: loggers/SimplePostLogger.php:1099
702
  msgid "Publish date"
703
  msgstr ""
704
 
705
+ #: loggers/SimplePostLogger.php:1114
706
  msgid "Permalink"
707
  msgstr ""
708
 
709
+ #: loggers/SimplePostLogger.php:1128
710
  msgid "Comment status"
711
  msgstr ""
712
 
713
+ #: loggers/SimplePostLogger.php:1151
714
  msgid "Author"
715
  msgstr ""
716
 
717
+ #: loggers/SimplePostLogger.php:1153
718
  msgid ""
719
  "Changed from {prev_user_display_name} ({prev_user_email}) to "
720
  "{new_user_display_name} ({new_user_email})"
721
  msgstr ""
722
 
723
+ #: loggers/SimplePostLogger.php:1184
724
  msgid "Changed from {prev_page_template} to {new_page_template}"
725
  msgstr ""
726
 
727
+ #: loggers/SimplePostLogger.php:1186
728
  msgid "Changed from \"{prev_page_template_name}\" to \"{new_page_template_name}\""
729
  msgstr ""
730
 
731
+ #: loggers/SimplePostLogger.php:1194
732
  msgid "Template"
733
  msgstr ""
734
 
735
+ #: loggers/SimplePostLogger.php:1234
736
  msgid "Custom fields"
737
  msgstr ""
738
 
739
+ #: loggers/SimplePostLogger.php:1441
740
+ msgid "Featured image"
741
+ msgstr ""
742
+
743
  #: loggers/SimpleThemeLogger.php:27
744
  msgid "Switched theme to \"{theme_name}\" from \"{prev_theme_name}\""
745
  msgstr ""
746
 
747
  #: loggers/SimpleThemeLogger.php:28
748
+ msgid "Installed theme \"{theme_name}\""
749
  msgstr ""
750
 
751
  #: loggers/SimpleThemeLogger.php:29
752
+ msgid "Deleted theme with slug \"{theme_slug}\""
753
  msgstr ""
754
 
755
  #: loggers/SimpleThemeLogger.php:30
756
+ msgid "Updated theme \"{theme_name}\""
757
  msgstr ""
758
 
759
  #: loggers/SimpleThemeLogger.php:31
760
+ msgid "Customized theme appearance \"{setting_id}\""
761
  msgstr ""
762
 
763
  #: loggers/SimpleThemeLogger.php:32
764
+ msgid "Removed widget \"{widget_id_base}\" from sidebar \"{sidebar_id}\""
765
  msgstr ""
766
 
767
  #: loggers/SimpleThemeLogger.php:33
768
+ msgid "Added widget \"{widget_id_base}\" to sidebar \"{sidebar_id}\""
769
+ msgstr ""
770
+
771
+ #: loggers/SimpleThemeLogger.php:34
772
+ msgid "Changed widget order \"{widget_id_base}\" in sidebar \"{sidebar_id}\""
773
+ msgstr ""
774
+
775
+ #: loggers/SimpleThemeLogger.php:35
776
+ msgid "Changed widget \"{widget_id_base}\" in sidebar \"{sidebar_id}\""
777
+ msgstr ""
778
+
779
+ #: loggers/SimpleThemeLogger.php:36
780
  msgid "Changed settings for the theme custom background"
781
  msgstr ""
782
 
783
+ #: loggers/SimpleThemeLogger.php:746
784
  msgid "Section"
785
  msgstr ""
786
 
787
+ #: loggers/SimpleUserLogger.php:18
788
+ msgid "User Logger"
 
 
789
  msgstr ""
790
 
791
+ #: loggers/SimpleUserLogger.php:19
792
+ msgid "Logs user logins, logouts, and failed logins"
793
+ msgstr ""
794
+
795
+ #: loggers/SimpleUserLogger.php:22
796
+ msgid "Failed to login with username \"{login}\" (incorrect password entered)"
797
  msgstr ""
798
 
799
  #: loggers/SimpleUserLogger.php:26
800
+ msgid ""
801
+ "Failed to login with username \"{failed_username}\" (username does not "
802
+ "exist)"
803
+ msgstr ""
804
+
805
+ #: loggers/SimpleUserLogger.php:30
806
  msgid "Logged in"
807
  msgstr ""
808
 
809
+ #: loggers/SimpleUserLogger.php:31
810
  msgid "Unknown user logged in"
811
  msgstr ""
812
 
813
+ #: loggers/SimpleUserLogger.php:32
814
  msgid "Logged out"
815
  msgstr ""
816
 
817
+ #: loggers/SimpleUserLogger.php:33
818
  msgid "Edited the profile for user {edited_user_login} ({edited_user_email})"
819
  msgstr ""
820
 
821
+ #: loggers/SimpleUserLogger.php:37
822
  msgid ""
823
  "Created user {created_user_login} ({created_user_email}) with role "
824
  "{created_user_role}"
825
  msgstr ""
826
 
827
+ #: loggers/SimpleUserLogger.php:41
828
  msgid "Deleted user {deleted_user_login} ({deleted_user_email})"
829
  msgstr ""
830
 
831
+ #: loggers/SimpleUserLogger.php:42
832
+ msgid "Reset their password"
833
+ msgstr ""
834
+
835
+ #: loggers/SimpleUserLogger.php:43
836
+ msgid ""
837
+ "Requested a password reset link for user with login '{user_login}' and "
838
+ "email '{user_email}'"
839
+ msgstr ""
840
+
841
+ #: loggers/SimpleUserLogger.php:471
842
  msgid "Edited <a href=\"{edit_profile_link}\">your profile</a>"
843
  msgstr ""
844
 
845
+ #: loggers/SimpleUserLogger.php:473
846
  msgid "Edited <a href=\"{edit_profile_link}\">their profile</a>"
847
  msgstr ""
848
 
849
+ #: loggers/SimpleUserLogger.php:479
850
  msgid "Edited your profile"
851
  msgstr ""
852
 
853
+ #: loggers/SimpleUserLogger.php:486
854
  msgid ""
855
  "Edited the profile for user <a "
856
  "href=\"{edit_profile_link}\">{edited_user_login} ({edited_user_email})</a>"
857
  msgstr ""
858
 
859
+ #: loggers/SimpleUserLogger.php:502
860
+ msgid ""
861
+ "Created user <a href=\"{edit_profile_link}\">{created_user_login} "
862
+ "({created_user_email})</a> with role {created_user_role}"
863
+ msgstr ""
864
+
865
  #: node_modules/grunt-wp-i18n/test/fixtures/basic-theme/exclude/file.php:3
866
  #: node_modules/grunt-wp-i18n/test/fixtures/plugin-include/plugin-include.php:6
867
  msgid "Exclude"
932
  msgid "Donate"
933
  msgstr ""
934
 
935
+ #: dropins/SimpleHistoryExportDropin.php:30
936
  msgctxt "Export dropin: Tab name on settings page"
937
  msgid "Export"
938
  msgstr ""
939
 
940
+ #: dropins/SimpleHistoryExportDropin.php:226
941
  msgctxt "Export dropin: introtext"
942
  msgid "The export function will export the full history."
943
  msgstr ""
944
 
945
+ #: dropins/SimpleHistoryExportDropin.php:230
946
  msgctxt "Export dropin: format"
947
  msgid "Choose format to export to"
948
  msgstr ""
949
 
950
+ #: dropins/SimpleHistoryExportDropin.php:235
951
  msgctxt "Export dropin: export format"
952
  msgid "JSON"
953
  msgstr ""
954
 
955
+ #: dropins/SimpleHistoryExportDropin.php:242
956
  msgctxt "Export dropin: export format"
957
  msgid "CSV"
958
  msgstr ""
959
 
960
+ #: dropins/SimpleHistoryExportDropin.php:260
961
  msgctxt "Export dropin: submit button"
962
  msgid "Download Export File"
963
  msgstr ""
964
 
965
+ #: dropins/SimpleHistoryFilterDropin.php:161
966
+ msgctxt "Filter label"
967
+ msgid "Dates:"
968
+ msgstr ""
969
+
970
+ #: dropins/SimpleHistoryFilterDropin.php:231
971
+ msgctxt "Filter label"
972
+ msgid "Between dates:"
973
+ msgstr ""
974
+
975
+ #: dropins/SimpleHistoryFilterDropin.php:255
976
+ msgctxt "Filter label"
977
+ msgid "Containing words:"
978
+ msgstr ""
979
+
980
+ #: dropins/SimpleHistoryFilterDropin.php:286
981
+ msgctxt "Filter label"
982
+ msgid "Log levels:"
983
+ msgstr ""
984
+
985
+ #: dropins/SimpleHistoryFilterDropin.php:323
986
+ msgctxt "Filter label"
987
+ msgid "Message types:"
988
+ msgstr ""
989
+
990
+ #: dropins/SimpleHistoryFilterDropin.php:416
991
+ msgctxt "Filter label"
992
+ msgid "Users:"
993
+ msgstr ""
994
+
995
+ #: dropins/SimpleHistoryFilterDropin.php:175
996
+ msgctxt "Filter dropin: filter custom range"
997
+ msgid "Custom date range..."
998
+ msgstr ""
999
+
1000
+ #: dropins/SimpleHistoryFilterDropin.php:183
1001
+ msgctxt "Filter dropin: filter week"
1002
+ msgid "Last day"
1003
+ msgstr ""
1004
+
1005
+ #: dropins/SimpleHistoryFilterDropin.php:190
1006
  msgctxt "Filter dropin: filter week"
1007
  msgid "Last 7 days"
1008
  msgstr ""
1009
 
1010
+ #: dropins/SimpleHistoryFilterDropin.php:197
1011
  msgctxt "Filter dropin: filter week"
1012
  msgid "Last 14 days"
1013
  msgstr ""
1014
 
1015
+ #: dropins/SimpleHistoryFilterDropin.php:204
1016
  msgctxt "Filter dropin: filter week"
1017
  msgid "Last 30 days"
1018
  msgstr ""
1019
 
1020
+ #: dropins/SimpleHistoryFilterDropin.php:211
1021
  msgctxt "Filter dropin: filter week"
1022
  msgid "Last 60 days"
1023
  msgstr ""
1024
 
1025
+ #: dropins/SimpleHistoryFilterDropin.php:269
1026
  msgctxt "Filter dropin: button to show more search options"
1027
+ msgid "Show search options"
1028
  msgstr ""
1029
 
1030
+ #: dropins/SimpleHistoryFilterDropin.php:433
1031
  msgctxt "Filter dropin: button to hide more search options"
1032
+ msgid "Hide search options"
1033
+ msgstr ""
1034
+
1035
+ #: dropins/SimpleHistoryFilterDropin.php:564
1036
+ msgctxt "Filter dropin, custom date range"
1037
+ msgid "From"
1038
+ msgstr ""
1039
+
1040
+ #: dropins/SimpleHistoryFilterDropin.php:567
1041
+ msgctxt "Filter dropin, custom date range"
1042
+ msgid "To"
1043
  msgstr ""
1044
 
1045
  #: dropins/SimpleHistoryIpInfoDropin.php:68
1047
  msgid "That IP address does not seem like a public one."
1048
  msgstr ""
1049
 
1050
+ #: dropins/SimpleHistoryIpInfoDropin.php:89
1051
  msgctxt "IP Info Dropin"
1052
  msgid "IP address"
1053
  msgstr ""
1054
 
1055
+ #: dropins/SimpleHistoryIpInfoDropin.php:100
1056
  msgctxt "IP Info Dropin"
1057
  msgid "Hostname"
1058
  msgstr ""
1059
 
1060
+ #: dropins/SimpleHistoryIpInfoDropin.php:111
1061
+ #: dropins/SimpleHistoryIpInfoDropin.php:122
1062
  msgctxt "IP Info Dropin"
1063
  msgid "Network"
1064
  msgstr ""
1065
 
1066
+ #: dropins/SimpleHistoryIpInfoDropin.php:133
1067
  msgctxt "IP Info Dropin"
1068
  msgid "City"
1069
  msgstr ""
1070
 
1071
+ #: dropins/SimpleHistoryIpInfoDropin.php:144
1072
  msgctxt "IP Info Dropin"
1073
  msgid "Region"
1074
  msgstr ""
1075
 
1076
+ #: dropins/SimpleHistoryIpInfoDropin.php:155
1077
  msgctxt "IP Info Dropin"
1078
  msgid "Country"
1079
  msgstr ""
1080
 
1081
+ #: dropins/SimpleHistoryIpInfoDropin.php:166
1082
  msgctxt "IP Info Dropin"
1083
  msgid "IP info provided by %1$s ipinfo.io %2$s"
1084
  msgstr ""
1088
  msgid "An error occured while checking for new events"
1089
  msgstr ""
1090
 
1091
+ #: dropins/SimpleHistoryRSSDropin.php:60
1092
  msgctxt "rss settings headline"
1093
  msgid "RSS feed"
1094
  msgstr ""
1095
 
1096
+ #: dropins/SimpleHistorySidebarDropin.php:32
1097
  msgctxt "Sidebar box"
1098
  msgid "Simple History is on GitHub"
1099
  msgstr ""
1100
 
1101
+ #: dropins/SimpleHistorySidebarDropin.php:35
1102
  msgctxt "Sidebar box"
1103
  msgid ""
1104
  "You can star, fork, or report issues with this plugin over at the <a "
1105
  "href=\"%1$s\">GitHub page</a>."
1106
  msgstr ""
1107
 
1108
+ #: dropins/SimpleHistorySidebarDropin.php:49
1109
  msgctxt "Sidebar box"
1110
  msgid "Donate to support development"
1111
  msgstr ""
1112
 
1113
+ #: dropins/SimpleHistorySidebarDropin.php:52
1114
  msgctxt "Sidebar box"
1115
  msgid ""
1116
  "If you like and use Simple History you should <a href=\"%1$s\">donate to "
1117
  "keep this plugin free</a>."
1118
  msgstr ""
1119
 
1120
+ #: dropins/SimpleHistorySidebarDropin.php:66
1121
  msgctxt "Sidebar box"
1122
  msgid "Review this plugin if you like it"
1123
  msgstr ""
1124
 
1125
+ #: dropins/SimpleHistorySidebarDropin.php:69
1126
  msgctxt "Sidebar box"
1127
  msgid ""
1128
  "If you like Simple History then please <a href=\"%1$s\">give it a nice "
1129
  "review over at wordpress.org</a>."
1130
  msgstr ""
1131
 
1132
+ #: dropins/SimpleHistorySidebarDropin.php:73
1133
  msgctxt "Sidebar box"
1134
  msgid ""
1135
  "A good review will help new users find this plugin. And it will make the "
1136
  "plugin author very happy :)"
1137
  msgstr ""
1138
 
1139
+ #: dropins/SimpleHistorySidebarDropin.php:107
1140
+ msgctxt "Sidebar box"
1141
+ msgid "Add more to the log"
1142
+ msgstr ""
1143
+
1144
+ #: dropins/SimpleHistorySidebarDropin.php:108
1145
+ msgctxt "Sidebar box"
1146
+ msgid "Are there things you miss in the history log?"
1147
+ msgstr ""
1148
+
1149
+ #: dropins/SimpleHistorySidebarDropin.php:120
1150
+ msgctxt "Sidebar box"
1151
+ msgid "Support"
1152
+ msgstr ""
1153
+
1154
+ #: dropins/SimpleHistorySidebarDropin.php:121
1155
+ msgctxt "Sidebar box"
1156
+ msgid ""
1157
+ "<a href=\"%1$s\">Visit the support forum</a> if you need help or have "
1158
+ "questions."
1159
+ msgstr ""
1160
+
1161
+ #: dropins/SimpleHistorySidebarStats.php:192
1162
+ #: templates/settings-statsRowsPerDay.php:38
1163
+ msgctxt "stats: date in rows per day chart"
1164
+ msgid "M j"
1165
+ msgstr ""
1166
+
1167
+ #: dropins/SimpleHistoryWPCLIDropin.php:97 loggers/SimpleLogger.php:375
1168
+ msgctxt "Event header output, when initiator is unknown"
1169
+ msgid "Other"
1170
+ msgstr ""
1171
+
1172
  #: examples/example-logger.php:50
1173
  msgctxt "User logger: 404"
1174
  msgid "Pages not found (404 errors)"
1179
  msgid "Pages not found"
1180
  msgstr ""
1181
 
1182
+ #: inc/SimpleHistory.php:389
1183
+ msgctxt "Admin bar network name"
1184
+ msgid "View History"
1185
+ msgstr ""
1186
+
1187
+ #: inc/SimpleHistory.php:456
1188
+ msgctxt "Admin bar name"
1189
+ msgid "Simple History"
1190
+ msgstr ""
1191
+
1192
+ #: inc/SimpleHistory.php:594
1193
  msgctxt "Message visible while waiting for log to load from server the first time"
1194
  msgid "Loading history..."
1195
  msgstr ""
1196
 
1197
+ #: inc/SimpleHistory.php:631
1198
  msgctxt "page n of n"
1199
  msgid "of"
1200
  msgstr ""
1201
 
1202
+ #: inc/SimpleHistory.php:725
1203
  msgctxt "API: not enought arguments passed"
1204
  msgid "Not enough args specified"
1205
  msgstr ""
1206
 
1207
+ #: inc/SimpleHistory.php:1936
1208
+ msgctxt "dashboard title name"
1209
+ msgid "Simple History"
1210
+ msgstr ""
1211
+
1212
+ #: inc/SimpleHistory.php:1937
1213
  msgctxt "dashboard menu name"
1214
  msgid "Simple History"
1215
  msgstr ""
1216
 
1217
+ #: inc/SimpleHistory.php:1955
1218
+ msgctxt "Options page menu title"
1219
+ msgid "Simple History"
1220
+ msgstr ""
1221
+
1222
+ #: inc/SimpleHistory.php:2079
1223
  msgctxt "history page headline"
1224
  msgid "Simple History"
1225
  msgstr ""
1226
 
1227
+ #: inc/SimpleHistory.php:2373
1228
+ msgctxt "Database is being cleared automagically"
1229
  msgid "Simple History removed one event that were older than {days} days"
1230
  msgid_plural "Simple History removed {num_rows} events that were older than {days} days"
1231
  msgstr[0] ""
1232
  msgstr[1] ""
1233
 
1234
+ #: inc/SimpleHistory.php:2813
1235
  msgctxt "Log level in gui"
1236
  msgid "emergency"
1237
  msgstr ""
1238
 
1239
+ #: inc/SimpleHistory.php:2817
1240
  msgctxt "Log level in gui"
1241
  msgid "alert"
1242
  msgstr ""
1243
 
1244
+ #: inc/SimpleHistory.php:2821
1245
  msgctxt "Log level in gui"
1246
  msgid "critical"
1247
  msgstr ""
1248
 
1249
+ #: inc/SimpleHistory.php:2825
1250
  msgctxt "Log level in gui"
1251
  msgid "error"
1252
  msgstr ""
1253
 
1254
+ #: inc/SimpleHistory.php:2829
1255
  msgctxt "Log level in gui"
1256
  msgid "warning"
1257
  msgstr ""
1258
 
1259
+ #: inc/SimpleHistory.php:2833
1260
  msgctxt "Log level in gui"
1261
  msgid "notice"
1262
  msgstr ""
1263
 
1264
+ #: inc/SimpleHistory.php:2837
1265
  msgctxt "Log level in gui"
1266
  msgid "info"
1267
  msgstr ""
1268
 
1269
+ #: inc/SimpleHistory.php:2841
1270
  msgctxt "Log level in gui"
1271
  msgid "debug"
1272
  msgstr ""
1273
 
1274
+ #: inc/SimpleHistory.php:2846
1275
  msgctxt "Log level in gui"
1276
  msgid "Emergency"
1277
  msgstr ""
1278
 
1279
+ #: inc/SimpleHistory.php:2850
1280
  msgctxt "Log level in gui"
1281
  msgid "Alert"
1282
  msgstr ""
1283
 
1284
+ #: inc/SimpleHistory.php:2854
1285
  msgctxt "Log level in gui"
1286
  msgid "Critical"
1287
  msgstr ""
1288
 
1289
+ #: inc/SimpleHistory.php:2858
1290
  msgctxt "Log level in gui"
1291
  msgid "Error"
1292
  msgstr ""
1293
 
1294
+ #: inc/SimpleHistory.php:2862
1295
  msgctxt "Log level in gui"
1296
  msgid "Warning"
1297
  msgstr ""
1298
 
1299
+ #: inc/SimpleHistory.php:2866
1300
  msgctxt "Log level in gui"
1301
  msgid "Notice"
1302
  msgstr ""
1303
 
1304
+ #: inc/SimpleHistory.php:2870
1305
  msgctxt "Log level in gui"
1306
  msgid "Info"
1307
  msgstr ""
1308
 
1309
+ #: inc/SimpleHistory.php:2874
1310
  msgctxt "Log level in gui"
1311
  msgid "Debug"
1312
  msgstr ""
1313
 
1314
+ #: loggers/AvailableUpdatesLogger.php:41
1315
+ msgctxt "Plugin logger: updates found"
1316
+ msgid "WordPress and plugins updates found"
1317
+ msgstr ""
1318
+
1319
+ #: loggers/AvailableUpdatesLogger.php:42
1320
+ msgctxt "Plugin logger: updates found"
1321
+ msgid "All found updates"
1322
+ msgstr ""
1323
+
1324
+ #: loggers/AvailableUpdatesLogger.php:44
1325
+ msgctxt "Plugin logger: updates found"
1326
+ msgid "WordPress updates found"
1327
+ msgstr ""
1328
+
1329
+ #: loggers/AvailableUpdatesLogger.php:47
1330
+ msgctxt "Plugin logger: updates found"
1331
+ msgid "Plugin updates found"
1332
+ msgstr ""
1333
+
1334
+ #: loggers/AvailableUpdatesLogger.php:50
1335
+ msgctxt "Plugin logger: updates found"
1336
+ msgid "Theme updates found"
1337
+ msgstr ""
1338
+
1339
+ #: loggers/FileEditsLogger.php:22
1340
+ msgctxt "Plugin logger: file edits"
1341
+ msgid "Edited theme and plugin files"
1342
+ msgstr ""
1343
+
1344
+ #: loggers/FileEditsLogger.php:23
1345
+ msgctxt "Plugin logger: file edits"
1346
+ msgid "All file edits"
1347
+ msgstr ""
1348
+
1349
+ #: loggers/FileEditsLogger.php:25
1350
+ msgctxt "Plugin logger: file edits"
1351
+ msgid "Edited theme files"
1352
+ msgstr ""
1353
+
1354
+ #: loggers/FileEditsLogger.php:28
1355
+ msgctxt "Plugin logger: file edits"
1356
+ msgid "Edited plugin files"
1357
+ msgstr ""
1358
+
1359
  #: loggers/PluginEnableMediaReplaceLogger.php:23
1360
  msgctxt "PluginEnableMediaReplaceLogger"
1361
  msgid "Enable Media Replace Logger"
1366
  msgid "Logs media updates made with the Enable Media Replace Plugin"
1367
  msgstr ""
1368
 
1369
+ #: loggers/PluginEnableMediaReplaceLogger.php:28
1370
  msgctxt "PluginEnableMediaReplaceLogger"
1371
  msgid ""
1372
  "Replaced attachment \"{prev_attachment_title}\" with new attachment "
1373
  "\"{new_attachment_title}\""
1374
  msgstr ""
1375
 
1376
+ #: loggers/PluginEnableMediaReplaceLogger.php:25
1377
+ msgctxt "PluginUserSwitchingLogger"
1378
+ msgid "Using plugin Enable Media Replace"
1379
+ msgstr ""
1380
+
1381
  #: loggers/PluginUserSwitchingLogger.php:23
1382
  msgctxt "PluginUserSwitchingLogger"
1383
  msgid "User Switching Logger"
1388
  msgid "Logs user switches"
1389
  msgstr ""
1390
 
1391
+ #: loggers/PluginUserSwitchingLogger.php:26
1392
+ msgctxt "PluginUserSwitchingLogger"
1393
+ msgid "Using plugin User Switching"
1394
+ msgstr ""
1395
+
1396
+ #: loggers/PluginUserSwitchingLogger.php:29
1397
  msgctxt "PluginUserSwitchingLogger"
1398
  msgid "Switched to user \"{user_login_to}\" from user \"{user_login_from}\""
1399
  msgstr ""
1400
 
1401
+ #: loggers/PluginUserSwitchingLogger.php:30
1402
  msgctxt "PluginUserSwitchingLogger"
1403
  msgid "Switched back to user \"{user_login_to}\" from user \"{user_login_from}\""
1404
  msgstr ""
1405
 
1406
+ #: loggers/PluginUserSwitchingLogger.php:31
1407
  msgctxt "PluginUserSwitchingLogger"
1408
  msgid "Switched back to user \"{user_login_to}\""
1409
  msgstr ""
1410
 
1411
+ #: loggers/PluginUserSwitchingLogger.php:32
1412
  msgctxt "PluginUserSwitchingLogger"
1413
  msgid "Switched off user \"{user_login}\""
1414
  msgstr ""
1415
 
1416
+ #: loggers/Plugin_ACF.php:59
1417
+ msgctxt "Logger: Plugin ACF"
1418
+ msgid "Logs ACF stuff"
1419
  msgstr ""
1420
 
1421
+ #: loggers/Plugin_ACF.php:60
1422
+ msgctxt "Logger: Plugin ACF"
1423
+ msgid "Using plugin ACF"
1424
  msgstr ""
1425
 
1426
+ #: loggers/Plugin_ACF.php:544
1427
+ msgctxt "Logger: Plugin ACF"
1428
+ msgid "Instruction placement"
1429
  msgstr ""
1430
 
1431
+ #: loggers/Plugin_ACF.php:547
1432
+ msgctxt "Logger: Plugin ACF"
1433
+ msgid "Label placement"
1434
  msgstr ""
1435
 
1436
+ #: loggers/Plugin_ACF.php:550
1437
+ msgctxt "Logger: Plugin ACF"
1438
+ msgid "Description"
1439
  msgstr ""
1440
 
1441
+ #: loggers/Plugin_ACF.php:553
1442
+ msgctxt "Logger: Plugin ACF"
1443
+ msgid "Menu order"
 
 
1444
  msgstr ""
1445
 
1446
+ #: loggers/Plugin_ACF.php:556
1447
+ msgctxt "Logger: Plugin ACF"
1448
+ msgid "Position"
 
 
1449
  msgstr ""
1450
 
1451
+ #: loggers/Plugin_ACF.php:559
1452
+ msgctxt "Logger: Plugin ACF"
1453
+ msgid "Active"
1454
  msgstr ""
1455
 
1456
+ #: loggers/Plugin_ACF.php:562
1457
+ msgctxt "Logger: Plugin ACF"
1458
+ msgid "Style"
 
 
1459
  msgstr ""
1460
 
1461
+ #: loggers/Plugin_ACF.php:594
1462
+ msgctxt "Logger: Plugin ACF"
1463
+ msgid "Checked"
 
 
1464
  msgstr ""
1465
 
1466
+ #: loggers/Plugin_ACF.php:602
1467
+ msgctxt "Logger: Plugin ACF"
1468
+ msgid "Unchecked"
1469
+ msgstr ""
1470
+
1471
+ #: loggers/Plugin_ACF.php:615
1472
+ msgctxt "Logger: Plugin ACF"
1473
+ msgid "Hide on screen"
1474
+ msgstr ""
1475
+
1476
+ #: loggers/Plugin_ACF.php:645
1477
+ msgctxt "Logger: Plugin ACF"
1478
+ msgid "Deleted field"
1479
+ msgid_plural "Deleted fields"
1480
+ msgstr[0] ""
1481
+ msgstr[1] ""
1482
+
1483
+ #: loggers/Plugin_ACF.php:674
1484
+ msgctxt "Logger: Plugin ACF"
1485
+ msgid "Added field"
1486
+ msgid_plural "Added fields"
1487
+ msgstr[0] ""
1488
+ msgstr[1] ""
1489
+
1490
+ #: loggers/Plugin_ACF.php:686
1491
+ msgctxt "Logger: Plugin ACF"
1492
+ msgid "Name: "
1493
+ msgstr ""
1494
+
1495
+ #: loggers/Plugin_ACF.php:689
1496
+ msgctxt "Logger: Plugin ACF"
1497
+ msgid "Parent: "
1498
+ msgstr ""
1499
+
1500
+ #: loggers/Plugin_ACF.php:692
1501
+ msgctxt "Logger: Plugin ACF"
1502
+ msgid "Key: "
1503
+ msgstr ""
1504
+
1505
+ #: loggers/Plugin_ACF.php:695
1506
+ msgctxt "Logger: Plugin ACF"
1507
+ msgid "Label: "
1508
+ msgstr ""
1509
+
1510
+ #: loggers/Plugin_ACF.php:698
1511
+ msgctxt "Logger: Plugin ACF"
1512
+ msgid "Type: "
1513
+ msgstr ""
1514
+
1515
+ #: loggers/Plugin_ACF.php:721
1516
+ msgctxt "Logger: Plugin ACF"
1517
+ msgid "Label: %1$s"
1518
+ msgstr ""
1519
+
1520
+ #: loggers/Plugin_ACF.php:753
1521
+ msgctxt "Logger: Plugin ACF"
1522
+ msgid "Modified field"
1523
+ msgstr ""
1524
+
1525
+ #: loggers/Plugin_DuplicatePost.php:21
1526
+ msgctxt "Logger: Plugin Duplicate Post"
1527
+ msgid "Logs posts and pages cloned using plugin Duplicate Post"
1528
+ msgstr ""
1529
+
1530
+ #: loggers/Plugin_DuplicatePost.php:22
1531
+ msgctxt "Logger: Plugin Duplicate Post"
1532
+ msgid "Using plugin Duplicate Posts"
1533
+ msgstr ""
1534
+
1535
+ #: loggers/Plugin_DuplicatePost.php:25
1536
+ msgctxt "Logger: Plugin Duplicate Post"
1537
+ msgid "Cloned \"{duplicated_post_title}\" to a new post"
1538
+ msgstr ""
1539
+
1540
+ #: loggers/Plugin_DuplicatePost.php:111
1541
+ msgctxt "Logger: Plugin Duplicate Post"
1542
+ msgid ""
1543
+ "Cloned {duplicated_post_post_type_singular_name} <a "
1544
+ "href=\"{duplicated_post_edit_link}\">\"{duplicated_post_title}\"</a> to <a "
1545
+ "href=\"{new_post_edit_link}\">a new "
1546
+ "{duplicated_post_post_type_singular_name}</a>"
1547
+ msgstr ""
1548
+
1549
+ #: loggers/Plugin_LimitLoginAttempts.php:19
1550
+ msgctxt "Logger: Plugin Limit Login Attempts"
1551
+ msgid ""
1552
+ "Logs failed login attempts, lockouts, and configuration changes made in the "
1553
+ "plugin Limit Login Attempts"
1554
+ msgstr ""
1555
+
1556
+ #: loggers/Plugin_LimitLoginAttempts.php:20
1557
+ msgctxt "Logger: Plugin Limit Login Attempts"
1558
+ msgid "Using plugin Limit Login Attempts"
1559
+ msgstr ""
1560
+
1561
+ #: loggers/Plugin_LimitLoginAttempts.php:24
1562
+ msgctxt "Logger: Plugin Limit Login Attempts"
1563
+ msgid "Failed login attempt from whitelisted IP"
1564
+ msgstr ""
1565
+
1566
+ #: loggers/Plugin_LimitLoginAttempts.php:25
1567
+ msgctxt "Logger: Plugin Limit Login Attempts"
1568
+ msgid "Was locked out because too many failed login attempts"
1569
+ msgstr ""
1570
+
1571
+ #: loggers/Plugin_LimitLoginAttempts.php:26
1572
+ msgctxt "Logger: Plugin Limit Login Attempts"
1573
+ msgid "Cleared IP log"
1574
+ msgstr ""
1575
+
1576
+ #: loggers/Plugin_LimitLoginAttempts.php:27
1577
+ msgctxt "Logger: Plugin Limit Login Attempts"
1578
+ msgid "Reseted lockout count"
1579
+ msgstr ""
1580
+
1581
+ #: loggers/Plugin_LimitLoginAttempts.php:28
1582
+ msgctxt "Logger: Plugin Limit Login Attempts"
1583
+ msgid "Cleared current lockouts"
1584
+ msgstr ""
1585
+
1586
+ #: loggers/Plugin_LimitLoginAttempts.php:29
1587
+ msgctxt "Logger: Plugin Limit Login Attempts"
1588
+ msgid "Updated options"
1589
+ msgstr ""
1590
+
1591
+ #: loggers/Plugin_LimitLoginAttempts.php:214
1592
+ msgctxt "Logger: Plugin Limit Login Attempts"
1593
+ msgid "%1$d failed login attempts (%2$d lockout(s)) from IP: %3$s"
1594
+ msgstr ""
1595
+
1596
+ #: loggers/Plugin_LimitLoginAttempts.php:222
1597
+ msgctxt "Logger: Plugin Limit Login Attempts"
1598
+ msgid "%d hour"
1599
+ msgid_plural "%d hours"
1600
+ msgstr[0] ""
1601
+ msgstr[1] ""
1602
+
1603
+ #: loggers/Plugin_LimitLoginAttempts.php:226
1604
+ msgctxt "Logger: Plugin Limit Login Attempts"
1605
+ msgid "%d minute"
1606
+ msgid_plural "%d minutes"
1607
+ msgstr[0] ""
1608
+ msgstr[1] ""
1609
+
1610
+ #: loggers/Plugin_LimitLoginAttempts.php:231
1611
+ msgctxt "Logger: Plugin Limit Login Attempts"
1612
+ msgid "IP was blocked for %1$s"
1613
+ msgstr ""
1614
+
1615
+ #: loggers/Plugin_Redirection.php:32
1616
+ msgctxt "Logger: Redirection"
1617
+ msgid "Text"
1618
+ msgstr ""
1619
+
1620
+ #: loggers/Plugin_Redirection.php:33
1621
+ msgctxt "Logger: Redirection"
1622
+ msgid "In plugin Redirection"
1623
+ msgstr ""
1624
+
1625
+ #: loggers/Plugin_Redirection.php:36
1626
+ msgctxt "Logger: Redirection"
1627
+ msgid "Added a redirection for URL \"{source_url}\""
1628
+ msgstr ""
1629
+
1630
+ #: loggers/Plugin_Redirection.php:37
1631
+ msgctxt "Logger: Redirection"
1632
+ msgid "Edited redirection for URL \"{prev_source_url}\""
1633
+ msgstr ""
1634
+
1635
+ #: loggers/Plugin_Redirection.php:38
1636
+ msgctxt "Logger: Redirection"
1637
+ msgid "Enabled redirection for {items_count} URL(s)"
1638
+ msgstr ""
1639
+
1640
+ #: loggers/Plugin_Redirection.php:39
1641
+ msgctxt "Logger: Redirection"
1642
+ msgid "Disabled redirection for {items_count} URL(s)"
1643
+ msgstr ""
1644
+
1645
+ #: loggers/Plugin_Redirection.php:40
1646
+ msgctxt "Logger: Redirection"
1647
+ msgid "Deleted redirection for {items_count} URL(s)"
1648
+ msgstr ""
1649
+
1650
+ #: loggers/Plugin_Redirection.php:41
1651
+ msgctxt "Logger: Redirection"
1652
+ msgid "Updated redirection options"
1653
+ msgstr ""
1654
+
1655
+ #: loggers/Plugin_Redirection.php:42
1656
+ msgctxt "Logger: Redirection"
1657
+ msgid "Removed all redirection options and deactivated plugin"
1658
+ msgstr ""
1659
+
1660
+ #: loggers/Plugin_Redirection.php:43
1661
+ msgctxt "Logger: Redirection"
1662
+ msgid "Added redirection group \"{group_name}\""
1663
+ msgstr ""
1664
+
1665
+ #: loggers/Plugin_Redirection.php:44
1666
+ msgctxt "Logger: Redirection"
1667
+ msgid "Enabled {items_count} redirection group(s)"
1668
+ msgstr ""
1669
+
1670
+ #: loggers/Plugin_Redirection.php:45
1671
+ msgctxt "Logger: Redirection"
1672
+ msgid "Disabled {items_count} redirection group(s)"
1673
+ msgstr ""
1674
+
1675
+ #: loggers/Plugin_Redirection.php:46
1676
+ msgctxt "Logger: Redirection"
1677
+ msgid "Deleted {items_count} redirection group(s)"
1678
+ msgstr ""
1679
+
1680
+ #: loggers/Plugin_Redirection.php:368
1681
+ msgctxt "Logger: Redirection"
1682
+ msgid "Source URL"
1683
+ msgstr ""
1684
+
1685
+ #: loggers/Plugin_Redirection.php:385
1686
+ msgctxt "Logger: Redirection"
1687
+ msgid "Target"
1688
+ msgstr ""
1689
+
1690
+ #: loggers/Plugin_UltimateMembers_Logger.php:23
1691
+ msgctxt "PluginUltimateMembersLogger"
1692
+ msgid "Ultimate Members Logger"
1693
+ msgstr ""
1694
+
1695
+ #: loggers/Plugin_UltimateMembers_Logger.php:24
1696
+ msgctxt "PluginUltimateMembersLogger"
1697
+ msgid "Logs actions from the Ultimate Members plugin"
1698
+ msgstr ""
1699
+
1700
+ #: loggers/Plugin_UltimateMembers_Logger.php:27
1701
+ msgctxt "PluginUltimateMembersLogger"
1702
+ msgid "Logged in"
1703
+ msgstr ""
1704
+
1705
+ #: loggers/SimpleCategoriesLogger.php:29
1706
+ msgctxt "Categories logger: search"
1707
+ msgid "Categories"
1708
+ msgstr ""
1709
+
1710
+ #: loggers/SimpleCategoriesLogger.php:30
1711
+ msgctxt "Category logger: search"
1712
+ msgid "All category activity"
1713
+ msgstr ""
1714
+
1715
+ #: loggers/SimpleCategoriesLogger.php:32
1716
+ msgctxt "Category logger: search"
1717
+ msgid "Term created"
1718
+ msgstr ""
1719
+
1720
+ #: loggers/SimpleCategoriesLogger.php:35
1721
+ msgctxt "Category logger: search"
1722
+ msgid "Term deleted"
1723
+ msgstr ""
1724
+
1725
+ #: loggers/SimpleCategoriesLogger.php:38
1726
+ msgctxt "Category logger: search"
1727
+ msgid "Term edited"
1728
+ msgstr ""
1729
+
1730
+ #: loggers/SimpleCategoriesLogger.php:276
1731
+ msgctxt "Categories logger: detailed plain text output for created term"
1732
+ msgid ""
1733
+ "Added term <a href=\"{term_edit_link}\">\"{term_name}\"</a> in taxonomy <a "
1734
+ "href=\"{tax_edit_link}\">\"{term_taxonomy}\"</a>"
1735
+ msgstr ""
1736
+
1737
+ #: loggers/SimpleCategoriesLogger.php:282
1738
+ msgctxt "Categories logger: detailed plain text output for deleted term"
1739
+ msgid ""
1740
+ "Deleted term \"{term_name}\" from taxonomy <a "
1741
+ "href=\"{tax_edit_link}\">\"{term_taxonomy}\"</a>"
1742
+ msgstr ""
1743
+
1744
+ #: loggers/SimpleCategoriesLogger.php:288
1745
+ msgctxt "Categories logger: detailed plain text output for edited term"
1746
+ msgid ""
1747
+ "Edited term <a href=\"{term_edit_link}\">\"{to_term_name}\"</a> in taxonomy "
1748
+ "<a href=\"{tax_edit_link}\">\"{to_term_taxonomy}\"</a>"
1749
+ msgstr ""
1750
+
1751
+ #: loggers/SimpleCommentsLogger.php:98
1752
+ msgctxt "A comment was added to the database by a non-logged in internet user"
1753
+ msgid "Added a comment to {comment_post_type} \"{comment_post_title}\""
1754
+ msgstr ""
1755
+
1756
+ #: loggers/SimpleCommentsLogger.php:104
1757
+ msgctxt "A comment was added to the database by a logged in user"
1758
+ msgid "Added a comment to {comment_post_type} \"{comment_post_title}\""
1759
+ msgstr ""
1760
+
1761
+ #: loggers/SimpleCommentsLogger.php:110
1762
+ msgctxt "A comment was approved"
1763
+ msgid ""
1764
+ "Approved a comment to \"{comment_post_title}\" by {comment_author} "
1765
+ "({comment_author_email})"
1766
+ msgstr ""
1767
+
1768
+ #: loggers/SimpleCommentsLogger.php:116
1769
+ msgctxt "A comment was was unapproved"
1770
+ msgid ""
1771
+ "Unapproved a comment to \"{comment_post_title}\" by {comment_author} "
1772
+ "({comment_author_email})"
1773
+ msgstr ""
1774
+
1775
+ #: loggers/SimpleCommentsLogger.php:122
1776
+ msgctxt "A comment was marked as spam"
1777
+ msgid "Marked a comment to post \"{comment_post_title}\" as spam"
1778
+ msgstr ""
1779
+
1780
+ #: loggers/SimpleCommentsLogger.php:128
1781
+ msgctxt "A comment was marked moved to the trash"
1782
+ msgid ""
1783
+ "Trashed a comment to \"{comment_post_title}\" by {comment_author} "
1784
+ "({comment_author_email})"
1785
+ msgstr ""
1786
+
1787
+ #: loggers/SimpleCommentsLogger.php:134
1788
+ msgctxt "A comment was restored from the trash"
1789
+ msgid ""
1790
+ "Restored a comment to \"{comment_post_title}\" by {comment_author} "
1791
+ "({comment_author_email}) from the trash"
1792
+ msgstr ""
1793
+
1794
+ #: loggers/SimpleCommentsLogger.php:140
1795
  msgctxt "A comment was deleted"
1796
  msgid ""
1797
  "Deleted a comment to \"{comment_post_title}\" by {comment_author} "
1798
  "({comment_author_email})"
1799
  msgstr ""
1800
 
1801
+ #: loggers/SimpleCommentsLogger.php:146
1802
  msgctxt "A comment was edited"
1803
  msgid ""
1804
  "Edited a comment to \"{comment_post_title}\" by {comment_author} "
1805
  "({comment_author_email})"
1806
  msgstr ""
1807
 
1808
+ #: loggers/SimpleCommentsLogger.php:153
1809
  msgctxt "A trackback was added to the database by a non-logged in internet user"
1810
  msgid "Added a trackback to {comment_post_type} \"{comment_post_title}\""
1811
  msgstr ""
1812
 
1813
+ #: loggers/SimpleCommentsLogger.php:208
1814
  msgctxt "A trackback was added to the database by a non-logged in internet user"
1815
  msgid "Added a pingback to {comment_post_type} \"{comment_post_title}\""
1816
  msgstr ""
1817
 
1818
+ #: loggers/SimpleCommentsLogger.php:159
1819
  msgctxt "A trackback was added to the database by a logged in user"
1820
  msgid "Added a trackback to {comment_post_type} \"{comment_post_title}\""
1821
  msgstr ""
1822
 
1823
+ #: loggers/SimpleCommentsLogger.php:165
1824
  msgctxt "A trackback was approved"
1825
  msgid ""
1826
  "Approved a trackback to \"{comment_post_title}\" by {comment_author} "
1827
  "({comment_author_email})"
1828
  msgstr ""
1829
 
1830
+ #: loggers/SimpleCommentsLogger.php:171
1831
  msgctxt "A trackback was was unapproved"
1832
  msgid ""
1833
  "Unapproved a trackback to \"{comment_post_title}\" by {comment_author} "
1834
  "({comment_author_email})"
1835
  msgstr ""
1836
 
1837
+ #: loggers/SimpleCommentsLogger.php:177
1838
  msgctxt "A trackback was marked as spam"
1839
  msgid "Marked a trackback to post \"{comment_post_title}\" as spam"
1840
  msgstr ""
1841
 
1842
+ #: loggers/SimpleCommentsLogger.php:183
1843
  msgctxt "A trackback was marked moved to the trash"
1844
  msgid ""
1845
  "Trashed a trackback to \"{comment_post_title}\" by {comment_author} "
1846
  "({comment_author_email})"
1847
  msgstr ""
1848
 
1849
+ #: loggers/SimpleCommentsLogger.php:189
1850
  msgctxt "A trackback was restored from the trash"
1851
  msgid ""
1852
  "Restored a trackback to \"{comment_post_title}\" by {comment_author} "
1853
  "({comment_author_email}) from the trash"
1854
  msgstr ""
1855
 
1856
+ #: loggers/SimpleCommentsLogger.php:195
1857
  msgctxt "A trackback was deleted"
1858
  msgid ""
1859
  "Deleted a trackback to \"{comment_post_title}\" by {comment_author} "
1860
  "({comment_author_email})"
1861
  msgstr ""
1862
 
1863
+ #: loggers/SimpleCommentsLogger.php:201
1864
  msgctxt "A trackback was edited"
1865
  msgid ""
1866
  "Edited a trackback to \"{comment_post_title}\" by {comment_author} "
1867
  "({comment_author_email})"
1868
  msgstr ""
1869
 
1870
+ #: loggers/SimpleCommentsLogger.php:214
1871
  msgctxt "A pingback was added to the database by a logged in user"
1872
  msgid "Added a pingback to {comment_post_type} \"{comment_post_title}\""
1873
  msgstr ""
1874
 
1875
+ #: loggers/SimpleCommentsLogger.php:220
1876
  msgctxt "A pingback was approved"
1877
  msgid ""
1878
  "Approved a pingback to \"{comment_post_title}\" by \"{comment_author}\"\" "
1879
  "({comment_author_email})"
1880
  msgstr ""
1881
 
1882
+ #: loggers/SimpleCommentsLogger.php:226
1883
  msgctxt "A pingback was was unapproved"
1884
  msgid ""
1885
  "Unapproved a pingback to \"{comment_post_title}\" by \"{comment_author}\" "
1886
  "({comment_author_email})"
1887
  msgstr ""
1888
 
1889
+ #: loggers/SimpleCommentsLogger.php:232
1890
  msgctxt "A pingback was marked as spam"
1891
  msgid "Marked a pingback to post \"{comment_post_title}\" as spam"
1892
  msgstr ""
1893
 
1894
+ #: loggers/SimpleCommentsLogger.php:238
1895
  msgctxt "A pingback was marked moved to the trash"
1896
  msgid ""
1897
  "Trashed a pingback to \"{comment_post_title}\" by {comment_author} "
1898
  "({comment_author_email})"
1899
  msgstr ""
1900
 
1901
+ #: loggers/SimpleCommentsLogger.php:244
1902
  msgctxt "A pingback was restored from the trash"
1903
  msgid ""
1904
  "Restored a pingback to \"{comment_post_title}\" by {comment_author} "
1905
  "({comment_author_email}) from the trash"
1906
  msgstr ""
1907
 
1908
+ #: loggers/SimpleCommentsLogger.php:250
1909
  msgctxt "A pingback was deleted"
1910
  msgid ""
1911
  "Deleted a pingback to \"{comment_post_title}\" by {comment_author} "
1912
  "({comment_author_email})"
1913
  msgstr ""
1914
 
1915
+ #: loggers/SimpleCommentsLogger.php:256
1916
  msgctxt "A pingback was edited"
1917
  msgid ""
1918
  "Edited a pingback to \"{comment_post_title}\" by {comment_author} "
1919
  "({comment_author_email})"
1920
  msgstr ""
1921
 
1922
+ #: loggers/SimpleCommentsLogger.php:267
1923
  msgctxt "Comments logger: search"
1924
  msgid "Comments"
1925
  msgstr ""
1926
 
1927
+ #: loggers/SimpleCommentsLogger.php:268
1928
  msgctxt "Comments logger: search"
1929
  msgid "All comments activity"
1930
  msgstr ""
1931
 
1932
+ #: loggers/SimpleCommentsLogger.php:270
1933
  msgctxt "Comments logger: search"
1934
  msgid "Added comments"
1935
  msgstr ""
1936
 
1937
+ #: loggers/SimpleCommentsLogger.php:278
1938
  msgctxt "Comments logger: search"
1939
  msgid "Edited comments"
1940
  msgstr ""
1941
 
1942
+ #: loggers/SimpleCommentsLogger.php:283
1943
  msgctxt "Comments logger: search"
1944
+ msgid "Approved comments"
1945
  msgstr ""
1946
 
1947
+ #: loggers/SimpleCommentsLogger.php:288
1948
  msgctxt "Comments logger: search"
1949
  msgid "Held comments"
1950
  msgstr ""
1951
 
1952
+ #: loggers/SimpleCommentsLogger.php:293
1953
  msgctxt "Comments logger: search"
1954
  msgid "Comments status changed to spam"
1955
  msgstr ""
1956
 
1957
+ #: loggers/SimpleCommentsLogger.php:298
1958
  msgctxt "Comments logger: search"
1959
  msgid "Trashed comments"
1960
  msgstr ""
1961
 
1962
+ #: loggers/SimpleCommentsLogger.php:303
1963
  msgctxt "Comments logger: search"
1964
  msgid "Untrashed comments"
1965
  msgstr ""
1966
 
1967
+ #: loggers/SimpleCommentsLogger.php:308
1968
  msgctxt "Comments logger: search"
1969
  msgid "Deleted comments"
1970
  msgstr ""
1971
 
1972
+ #: loggers/SimpleCommentsLogger.php:611 loggers/SimpleCommentsLogger.php:624
1973
+ #: loggers/SimpleCommentsLogger.php:638
1974
  msgctxt "comments logger - detailed output comment status"
1975
  msgid "Status"
1976
  msgstr ""
1977
 
1978
+ #: loggers/SimpleCommentsLogger.php:613 loggers/SimpleCommentsLogger.php:626
1979
+ #: loggers/SimpleCommentsLogger.php:640
1980
  msgctxt "comments logger - detailed output author"
1981
  msgid "Name"
1982
  msgstr ""
1983
 
1984
+ #: loggers/SimpleCommentsLogger.php:614 loggers/SimpleCommentsLogger.php:627
1985
+ #: loggers/SimpleCommentsLogger.php:641
1986
  msgctxt "comments logger - detailed output email"
1987
  msgid "Email"
1988
  msgstr ""
1989
 
1990
+ #: loggers/SimpleCommentsLogger.php:615 loggers/SimpleCommentsLogger.php:628
1991
  msgctxt "comments logger - detailed output content"
1992
  msgid "Content"
1993
  msgstr ""
1994
 
1995
+ #: loggers/SimpleCommentsLogger.php:642
1996
  msgctxt "comments logger - detailed output content"
1997
  msgid "Comment"
1998
  msgstr ""
1999
 
2000
+ #: loggers/SimpleCommentsLogger.php:775
2001
  msgctxt "comments logger - edit comment"
2002
  msgid "View/Edit"
2003
  msgstr ""
2004
 
2005
+ #: loggers/SimpleCoreUpdatesLogger.php:70
2006
  msgctxt "User logger: search"
2007
  msgid "WordPress Core"
2008
  msgstr ""
2009
 
2010
+ #: loggers/SimpleCoreUpdatesLogger.php:72
2011
  msgctxt "User logger: search"
2012
  msgid "WordPress core updates"
2013
  msgstr ""
2014
 
2015
+ #: loggers/SimpleUserLogger.php:72
2016
  msgctxt "User logger: search"
2017
  msgid "Users"
2018
  msgstr ""
2019
 
2020
+ #: loggers/SimpleUserLogger.php:73
2021
  msgctxt "User logger: search"
2022
  msgid "All user activity"
2023
  msgstr ""
2024
 
2025
+ #: loggers/SimpleUserLogger.php:75
2026
  msgctxt "User logger: search"
2027
  msgid "Successful user logins"
2028
  msgstr ""
2029
 
2030
+ #: loggers/SimpleUserLogger.php:79
2031
  msgctxt "User logger: search"
2032
  msgid "Failed user logins"
2033
  msgstr ""
2034
 
2035
+ #: loggers/SimpleUserLogger.php:83
2036
  msgctxt "User logger: search"
2037
  msgid "User logouts"
2038
  msgstr ""
2039
 
2040
+ #: loggers/SimpleUserLogger.php:86
2041
  msgctxt "User logger: search"
2042
  msgid "Created users"
2043
  msgstr ""
2044
 
2045
+ #: loggers/SimpleUserLogger.php:89
2046
  msgctxt "User logger: search"
2047
  msgid "User profile updates"
2048
  msgstr ""
2049
 
2050
+ #: loggers/SimpleUserLogger.php:92
2051
  msgctxt "User logger: search"
2052
  msgid "User deletions"
2053
  msgstr ""
2062
  msgid "Created exports"
2063
  msgstr ""
2064
 
2065
+ #: loggers/SimpleLogger.php:291
2066
  msgctxt "header output when initiator is the currently logged in user"
2067
  msgid "You"
2068
  msgstr ""
2069
 
 
 
 
 
 
2070
  #: loggers/SimpleMediaLogger.php:31
2071
  msgctxt "Media logger: search"
2072
  msgid "Media"
2117
  msgid "Deleted menus"
2118
  msgstr ""
2119
 
2120
+ #: loggers/SimpleMenuLogger.php:324
2121
  msgctxt "menu logger"
2122
  msgid "%1$s menu item added"
2123
  msgid_plural "%1$s menu items added"
2124
  msgstr[0] ""
2125
  msgstr[1] ""
2126
 
2127
+ #: loggers/SimpleMenuLogger.php:331
2128
  msgctxt "menu logger"
2129
  msgid "%1$s menu item removed"
2130
  msgid_plural "%1$s menu items removed"
2131
  msgstr[0] ""
2132
  msgstr[1] ""
2133
 
2134
+ #: loggers/SimpleOptionsLogger.php:38
2135
  msgctxt "Options logger: search"
2136
  msgid "Options"
2137
  msgstr ""
2138
 
2139
+ #: loggers/SimpleOptionsLogger.php:40
2140
  msgctxt "Options logger: search"
2141
  msgid "Changed options"
2142
  msgstr ""
2143
 
2144
+ #: loggers/SimplePluginLogger.php:39
2145
  msgctxt "Plugin was non-silently activated by a user"
2146
  msgid "Activated plugin \"{plugin_name}\""
2147
  msgstr ""
2148
 
2149
+ #: loggers/SimplePluginLogger.php:45
2150
  msgctxt "Plugin was non-silently deactivated by a user"
2151
  msgid "Deactivated plugin \"{plugin_name}\""
2152
  msgstr ""
2153
 
2154
+ #: loggers/SimplePluginLogger.php:51
2155
  msgctxt "Plugin was installed"
2156
  msgid "Installed plugin \"{plugin_name}\""
2157
  msgstr ""
2158
 
2159
+ #: loggers/SimplePluginLogger.php:57
2160
  msgctxt "Plugin failed to install"
2161
  msgid "Failed to install plugin \"{plugin_name}\""
2162
  msgstr ""
2163
 
2164
+ #: loggers/SimplePluginLogger.php:63
2165
  msgctxt "Plugin was updated"
2166
  msgid ""
2167
  "Updated plugin \"{plugin_name}\" to version {plugin_version} from "
2168
  "{plugin_prev_version}"
2169
  msgstr ""
2170
 
2171
+ #: loggers/SimplePluginLogger.php:69
2172
  msgctxt "Plugin update failed"
2173
+ msgid "Failed to update plugin \"{plugin_name}\""
2174
  msgstr ""
2175
 
2176
+ #: loggers/SimplePluginLogger.php:75
 
 
 
 
 
2177
  msgctxt "Plugin files was deleted"
2178
  msgid "Deleted plugin \"{plugin_name}\""
2179
  msgstr ""
2180
 
2181
+ #: loggers/SimplePluginLogger.php:82
2182
  msgctxt "Plugin was updated in bulk"
2183
  msgid ""
2184
  "Updated plugin \"{plugin_name}\" to {plugin_version} from "
2185
  "{plugin_prev_version}"
2186
  msgstr ""
2187
 
2188
+ #: loggers/SimplePluginLogger.php:89
2189
+ msgctxt "Plugin was disabled because of an error"
2190
+ msgid ""
2191
+ "Deactivated plugin \"{plugin_slug}\" because of an error "
2192
+ "(\"{deactivation_reason}\")."
2193
+ msgstr ""
2194
+
2195
+ #: loggers/SimplePluginLogger.php:98
2196
  msgctxt "Plugin logger: search"
2197
  msgid "Plugins"
2198
  msgstr ""
2199
 
2200
+ #: loggers/SimplePluginLogger.php:99
2201
  msgctxt "Plugin logger: search"
2202
  msgid "All plugin activity"
2203
  msgstr ""
2204
 
2205
+ #: loggers/SimplePluginLogger.php:101
2206
  msgctxt "Plugin logger: search"
2207
  msgid "Activated plugins"
2208
  msgstr ""
2209
 
2210
+ #: loggers/SimplePluginLogger.php:104
2211
  msgctxt "Plugin logger: search"
2212
  msgid "Deactivated plugins"
2213
  msgstr ""
2214
 
2215
+ #: loggers/SimplePluginLogger.php:108
2216
  msgctxt "Plugin logger: search"
2217
  msgid "Installed plugins"
2218
  msgstr ""
2219
 
2220
+ #: loggers/SimplePluginLogger.php:111
2221
  msgctxt "Plugin logger: search"
2222
  msgid "Failed plugin installs"
2223
  msgstr ""
2224
 
2225
+ #: loggers/SimplePluginLogger.php:114
2226
  msgctxt "Plugin logger: search"
2227
  msgid "Updated plugins"
2228
  msgstr ""
2229
 
2230
+ #: loggers/SimplePluginLogger.php:118
2231
  msgctxt "Plugin logger: search"
2232
  msgid "Failed plugin updates"
2233
  msgstr ""
2234
 
2235
+ #: loggers/SimplePluginLogger.php:121
 
 
 
 
 
2236
  msgctxt "Plugin logger: search"
2237
  msgid "Deleted plugins"
2238
  msgstr ""
2239
 
2240
+ #: loggers/SimplePluginLogger.php:1034
2241
  msgctxt "plugin logger - detailed output"
2242
  msgid "Description"
2243
  msgstr ""
2244
 
2245
+ #: loggers/SimplePluginLogger.php:1035
2246
  msgctxt "plugin logger - detailed output install source"
2247
  msgid "Source"
2248
  msgstr ""
2249
 
2250
+ #: loggers/SimplePluginLogger.php:1036
2251
  msgctxt "plugin logger - detailed output install source"
2252
  msgid "Source file name"
2253
  msgstr ""
2254
 
2255
+ #: loggers/SimplePluginLogger.php:1037
2256
  msgctxt "plugin logger - detailed output version"
2257
  msgid "Version"
2258
  msgstr ""
2259
 
2260
+ #: loggers/SimplePluginLogger.php:1038
2261
  msgctxt "plugin logger - detailed output author"
2262
  msgid "Author"
2263
  msgstr ""
2264
 
2265
+ #: loggers/SimplePluginLogger.php:1039
2266
  msgctxt "plugin logger - detailed output url"
2267
  msgid "URL"
2268
  msgstr ""
2269
 
2270
+ #: loggers/SimplePluginLogger.php:1144 loggers/SimplePluginLogger.php:1161
2271
+ #: loggers/SimplePluginLogger.php:1205
2272
  msgctxt "plugin logger: plugin info thickbox title view all info"
2273
  msgid "View plugin info"
2274
  msgstr ""
2275
 
2276
+ #: loggers/SimplePluginLogger.php:1175
2277
  msgctxt "plugin logger: plugin info thickbox title"
2278
  msgid "View plugin info"
2279
  msgstr ""
2280
 
2281
+ #: loggers/SimplePluginLogger.php:1180
2282
  msgctxt "plugin logger: plugin info thickbox title"
2283
  msgid "View changelog"
2284
  msgstr ""
2285
 
2286
+ #: loggers/SimplePostLogger.php:232
2287
  msgctxt "Post logger: search"
2288
  msgid "Posts & Pages"
2289
  msgstr ""
2290
 
2291
+ #: loggers/SimplePostLogger.php:233
2292
  msgctxt "Post logger: search"
2293
  msgid "All posts & pages activity"
2294
  msgstr ""
2295
 
2296
+ #: loggers/SimplePostLogger.php:235
2297
  msgctxt "Post logger: search"
2298
  msgid "Posts created"
2299
  msgstr ""
2300
 
2301
+ #: loggers/SimplePostLogger.php:238
2302
  msgctxt "Post logger: search"
2303
  msgid "Posts updated"
2304
  msgstr ""
2305
 
2306
+ #: loggers/SimplePostLogger.php:241
2307
  msgctxt "Post logger: search"
2308
  msgid "Posts trashed"
2309
  msgstr ""
2310
 
2311
+ #: loggers/SimplePostLogger.php:244
2312
  msgctxt "Post logger: search"
2313
  msgid "Posts deleted"
2314
  msgstr ""
2315
 
2316
+ #: loggers/SimplePostLogger.php:247
2317
  msgctxt "Post logger: search"
2318
  msgid "Posts restored"
2319
  msgstr ""
2320
 
2321
+ #: loggers/SimpleThemeLogger.php:40
2322
  msgctxt "Theme logger: search"
2323
  msgid "Themes & Widgets"
2324
  msgstr ""
2325
 
2326
+ #: loggers/SimpleThemeLogger.php:41
2327
  msgctxt "Theme logger: search"
2328
  msgid "All theme activity"
2329
  msgstr ""
2330
 
2331
+ #: loggers/SimpleThemeLogger.php:43
2332
+ msgctxt "Theme logger: search"
2333
+ msgid "Updated themes"
2334
+ msgstr ""
2335
+
2336
+ #: loggers/SimpleThemeLogger.php:46
2337
+ msgctxt "Theme logger: search"
2338
+ msgid "Deleted themes"
2339
+ msgstr ""
2340
+
2341
+ #: loggers/SimpleThemeLogger.php:49
2342
+ msgctxt "Theme logger: search"
2343
+ msgid "Installed themes"
2344
+ msgstr ""
2345
+
2346
+ #: loggers/SimpleThemeLogger.php:52
2347
  msgctxt "Theme logger: search"
2348
  msgid "Switched themes"
2349
  msgstr ""
2350
 
2351
+ #: loggers/SimpleThemeLogger.php:55
2352
  msgctxt "Theme logger: search"
2353
  msgid "Changed appearance of themes"
2354
  msgstr ""
2355
 
2356
+ #: loggers/SimpleThemeLogger.php:58
2357
  msgctxt "Theme logger: search"
2358
  msgid "Added widgets"
2359
  msgstr ""
2360
 
2361
+ #: loggers/SimpleThemeLogger.php:61
2362
  msgctxt "Theme logger: search"
2363
  msgid "Removed widgets"
2364
  msgstr ""
2365
 
2366
+ #: loggers/SimpleThemeLogger.php:64
2367
  msgctxt "Theme logger: search"
2368
  msgid "Changed widgets order"
2369
  msgstr ""
2370
 
2371
+ #: loggers/SimpleThemeLogger.php:67
2372
  msgctxt "Theme logger: search"
2373
  msgid "Edited widgets"
2374
  msgstr ""
2375
 
2376
+ #: loggers/SimpleThemeLogger.php:70
2377
  msgctxt "Theme logger: search"
2378
  msgid "Background of themes changed"
2379
  msgstr ""
2380
 
2381
+ #: loggers/SimpleUserLogger.php:54
2382
  msgctxt "User destroys other login sessions for themself"
2383
  msgid "Logged out from all other sessions"
2384
  msgstr ""
2385
 
2386
+ #: loggers/SimpleUserLogger.php:63
2387
  msgctxt "User destroys all login sessions for a user"
2388
  msgid "Logged out \"{user_display_name}\" from all sessions"
2389
  msgstr ""
2390
 
2391
+ #: loggers/SimpleUserLogger.php:780 loggers/SimpleUserLogger.php:879
2392
+ msgctxt "User logger"
2393
+ msgid "First name"
2394
+ msgstr ""
2395
+
2396
+ #: loggers/SimpleUserLogger.php:783 loggers/SimpleUserLogger.php:882
2397
+ msgctxt "User logger"
2398
+ msgid "Last name"
2399
+ msgstr ""
2400
+
2401
+ #: loggers/SimpleUserLogger.php:786
2402
+ msgctxt "User logger"
2403
+ msgid "Nickname"
2404
+ msgstr ""
2405
+
2406
+ #: loggers/SimpleUserLogger.php:789
2407
+ msgctxt "User logger"
2408
+ msgid "Description"
2409
+ msgstr ""
2410
+
2411
+ #: loggers/SimpleUserLogger.php:793
2412
+ msgctxt "User logger"
2413
+ msgid "Visual editor"
2414
+ msgstr ""
2415
+
2416
+ #: loggers/SimpleUserLogger.php:797
2417
+ msgctxt "User logger"
2418
+ msgid "Keyboard shortcuts"
2419
+ msgstr ""
2420
+
2421
+ #: loggers/SimpleUserLogger.php:801
2422
+ msgctxt "User logger"
2423
+ msgid "Show Toolbar"
2424
+ msgstr ""
2425
+
2426
+ #: loggers/SimpleUserLogger.php:805
2427
+ msgctxt "User logger"
2428
+ msgid "Colour Scheme"
2429
+ msgstr ""
2430
+
2431
+ #: loggers/SimpleUserLogger.php:808
2432
+ msgctxt "User logger"
2433
+ msgid "AIM"
2434
+ msgstr ""
2435
+
2436
+ #: loggers/SimpleUserLogger.php:811
2437
+ msgctxt "User logger"
2438
+ msgid "Yahoo IM"
2439
+ msgstr ""
2440
+
2441
+ #: loggers/SimpleUserLogger.php:814
2442
+ msgctxt "User logger"
2443
+ msgid "Jabber / Google Talk "
2444
+ msgstr ""
2445
+
2446
+ #: loggers/SimpleUserLogger.php:821
2447
+ msgctxt "User logger"
2448
+ msgid "Email"
2449
+ msgstr ""
2450
+
2451
+ #: loggers/SimpleUserLogger.php:825
2452
+ msgctxt "User logger"
2453
+ msgid "Display name"
2454
+ msgstr ""
2455
+
2456
+ #: loggers/SimpleUserLogger.php:828 loggers/SimpleUserLogger.php:885
2457
+ msgctxt "User logger"
2458
+ msgid "Website"
2459
+ msgstr ""
2460
+
2461
+ #: loggers/SimpleUserLogger.php:831
2462
+ msgctxt "User logger"
2463
+ msgid "Role"
2464
+ msgstr ""
2465
+
2466
+ #: loggers/SimpleUserLogger.php:834
2467
+ msgctxt "User logger"
2468
+ msgid "Locale"
2469
+ msgstr ""
2470
+
2471
+ #: loggers/SimpleUserLogger.php:865
2472
+ msgctxt "User logger"
2473
+ msgid "Password"
2474
+ msgstr ""
2475
+
2476
+ #: loggers/SimpleUserLogger.php:866
2477
+ msgctxt "User logger"
2478
+ msgid "Changed"
2479
+ msgstr ""
2480
+
2481
+ #: loggers/SimpleUserLogger.php:888
2482
+ msgctxt "User logger"
2483
+ msgid "User notification email sent"
2484
+ msgstr ""
2485
+
2486
+ #: loggers/SimpleUserLogger.php:896
2487
+ msgctxt "User logger"
2488
+ msgid "Yes, email with account details was sent"
2489
+ msgstr ""
2490
+
2491
+ #: loggers/SimpleUserLogger.php:913
2492
+ msgctxt "User logger"
2493
+ msgid "Notification"
2494
+ msgstr ""
2495
+
2496
+ #: loggers/class-sh-jetpack-logger.php:30
2497
+ msgctxt "Logger: Jetpack"
2498
+ msgid "Log Jetpack settings changes"
2499
+ msgstr ""
2500
+
2501
+ #: loggers/class-sh-jetpack-logger.php:32
2502
+ msgctxt "Logger: Jetpack"
2503
+ msgid "Using plugin Jetpack"
2504
+ msgstr ""
2505
+
2506
+ #: loggers/class-sh-jetpack-logger.php:34
2507
+ msgctxt "Logger: Jetpack"
2508
+ msgid "Activated Jetpack module \"{module_name}\""
2509
+ msgstr ""
2510
+
2511
+ #: loggers/class-sh-jetpack-logger.php:35
2512
+ msgctxt "Logger: Jetpack"
2513
+ msgid "Deactivated Jetpack module \"{module_name}\""
2514
+ msgstr ""
2515
+
2516
+ #: loggers/class-sh-privacy-logger.php:39
2517
+ msgctxt "Logger: Privacy"
2518
+ msgid "Log WordPress privacy related things"
2519
+ msgstr ""
2520
+
2521
+ #: loggers/class-sh-privacy-logger.php:42
2522
+ msgctxt "Logger: Privacy"
2523
+ msgid "Created a new privacy page \"{new_post_title}\""
2524
+ msgstr ""
2525
+
2526
+ #: loggers/class-sh-privacy-logger.php:43
2527
+ msgctxt "Logger: Privacy"
2528
+ msgid "Set privacy page to page \"{new_post_title}\""
2529
+ msgstr ""
2530
+
2531
+ #: loggers/class-sh-privacy-logger.php:44
2532
+ msgctxt "Logger: Privacy"
2533
+ msgid "Requested a privacy data export for user \"{user_email}\""
2534
+ msgstr ""
2535
+
2536
+ #: loggers/class-sh-privacy-logger.php:45
2537
+ msgctxt "Logger: Privacy"
2538
+ msgid "Downloaded personal data export file for user \"{user_email}\""
2539
+ msgstr ""
2540
+
2541
+ #: loggers/class-sh-privacy-logger.php:46
2542
+ msgctxt "Logger: Privacy"
2543
+ msgid "Sent email with personal data export download info for user \"{user_email}\""
2544
+ msgstr ""
2545
+
2546
+ #: loggers/class-sh-privacy-logger.php:47
2547
+ msgctxt "Logger: Privacy"
2548
+ msgid "Confirmed data export request for \"{user_email}\""
2549
+ msgstr ""
2550
+
2551
+ #: loggers/class-sh-privacy-logger.php:48
2552
+ msgctxt "Logger: Privacy"
2553
+ msgid "Removed data export request for \"{user_email}\""
2554
+ msgstr ""
2555
+
2556
+ #: loggers/class-sh-privacy-logger.php:49
2557
+ msgctxt "Logger: Privacy"
2558
+ msgid "Sent data erasure request for \"{user_email}\""
2559
+ msgstr ""
2560
+
2561
+ #: loggers/class-sh-privacy-logger.php:50
2562
+ msgctxt "Logger: Privacy"
2563
+ msgid "Confirmed data erasure request for \"{user_email}\""
2564
+ msgstr ""
2565
+
2566
+ #: loggers/class-sh-privacy-logger.php:51
2567
+ msgctxt "Logger: Privacy"
2568
+ msgid "Erased personal data for \"{user_email}\""
2569
+ msgstr ""
2570
+
2571
+ #: loggers/class-sh-privacy-logger.php:52
2572
+ msgctxt "Logger: Privacy"
2573
+ msgid "Removed personal data removal request for \"{user_email}\""
2574
+ msgstr ""
2575
+
2576
+ #: loggers/class-sh-translations-logger.php:30
2577
+ msgctxt "Logger: Translations"
2578
+ msgid "Log WordPress translation related things"
2579
+ msgstr ""
2580
+
2581
+ #: loggers/class-sh-translations-logger.php:33
2582
+ msgctxt "Logger: Translations"
2583
+ msgid "Updated translations for \"{name}\" ({language})"
2584
+ msgstr ""
2585
+
2586
+ #: templates/template-settings-tab-debug.php:23
2587
+ msgctxt "debug dropin"
2588
+ msgid "Database size"
2589
+ msgstr ""
2590
+
2591
+ #: templates/template-settings-tab-debug.php:58
2592
+ msgctxt "debug dropin"
2593
+ msgid "Table name"
2594
+ msgstr ""
2595
+
2596
+ #: templates/template-settings-tab-debug.php:59
2597
+ msgctxt "debug dropin"
2598
+ msgid "Size"
2599
+ msgstr ""
2600
+
2601
+ #: templates/template-settings-tab-debug.php:60
2602
+ msgctxt "debug dropin"
2603
+ msgid "Rows"
2604
+ msgstr ""
2605
+
2606
+ #: templates/template-settings-tab-debug.php:67
2607
+ msgctxt "debug dropin"
2608
+ msgid "%s MB"
2609
+ msgstr ""
2610
+
2611
+ #: templates/template-settings-tab-debug.php:72
2612
+ msgctxt "debug dropin"
2613
+ msgid "%s rows"
2614
+ msgstr ""
2615
+
2616
+ #: templates/template-settings-tab-debug.php:102
2617
+ msgctxt "debug dropin"
2618
+ msgid "Total %s rows, when grouped by occasion id."
2619
+ msgstr ""
2620
+
2621
+ #: templates/template-settings-tab-debug.php:146
2622
+ msgctxt "debug dropin"
2623
+ msgid "Loggers"
2624
+ msgstr ""
2625
+
2626
+ #: templates/template-settings-tab-debug.php:151
2627
+ msgctxt "debug dropin"
2628
+ msgid "Listing %1$d loggers, ordered by rows count in database."
2629
+ msgstr ""
2630
+
2631
+ #: templates/template-settings-tab-debug.php:170
2632
+ msgctxt "debug dropin"
2633
+ msgid "Logger name"
2634
+ msgstr ""
2635
+
2636
+ #: templates/template-settings-tab-debug.php:171
2637
+ msgctxt "debug dropin"
2638
+ msgid "Slug"
2639
+ msgstr ""
2640
+
2641
+ #: templates/template-settings-tab-debug.php:172
2642
+ msgctxt "debug dropin"
2643
+ msgid "Description"
2644
+ msgstr ""
2645
+
2646
+ #: templates/template-settings-tab-debug.php:173
2647
+ msgctxt "debug dropin"
2648
+ msgid "Messages"
2649
+ msgstr ""
2650
+
2651
+ #: templates/template-settings-tab-debug.php:174
2652
+ msgctxt "debug dropin"
2653
+ msgid "Capability"
2654
+ msgstr ""
2655
+
2656
+ #: templates/template-settings-tab-debug.php:175
2657
+ msgctxt "debug dropin"
2658
+ msgid "Rows count"
2659
+ msgstr ""
2660
+
2661
+ #: templates/template-settings-tab-debug.php:208
2662
+ msgctxt "debug dropin"
2663
+ msgid "%1$s message strings"
2664
+ msgstr ""
2665
+
2666
+ #: templates/template-settings-tab-debug.php:223
2667
+ msgctxt "debug dropin"
2668
+ msgid "No message strings"
2669
+ msgstr ""
2670
+
2671
+ #: templates/template-settings-tab-debug.php:265
2672
+ msgctxt "debug dropin"
2673
+ msgid "Plugins"
2674
+ msgstr ""
2675
+
2676
+ #: templates/template-settings-tab-debug.php:267
2677
+ msgctxt "debug dropin"
2678
+ msgid "As returned from <code>get_plugins()</code>"
2679
+ msgstr ""
2680
+
2681
+ #: templates/template-settings-tab-debug.php:281
2682
+ msgctxt "debug dropin"
2683
+ msgid "Plugin name"
2684
+ msgstr ""
2685
+
2686
+ #: templates/template-settings-tab-debug.php:282
2687
+ msgctxt "debug dropin"
2688
+ msgid "Plugin file path"
2689
+ msgstr ""
2690
+
2691
+ #: templates/template-settings-tab-debug.php:283
2692
+ msgctxt "debug dropin"
2693
+ msgid "Active"
2694
+ msgstr ""
2695
+
2696
+ #: templates/template-settings-tab-debug.php:299
2697
+ msgctxt "debug dropin"
2698
+ msgid "Yes"
2699
+ msgstr ""
2700
+
2701
+ #: templates/template-settings-tab-debug.php:300
2702
+ msgctxt "debug dropin"
2703
+ msgid "No"
2704
  msgstr ""
loggers/Plugin_BeaverBuilder.php ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ defined('ABSPATH') or die();
4
+
5
+ /**
6
+ * Logger for Beaver Builder
7
+ */
8
+ if (!class_exists('Plugin_BeaverBuilder')) {
9
+ class Plugin_BeaverBuilder extends SimpleLogger
10
+ {
11
+ public $slug = __CLASS__;
12
+
13
+ function getInfo()
14
+ {
15
+ $arr_info = array(
16
+ 'name' => 'Plugin Beaver Builder',
17
+ 'description' => _x(
18
+ 'Logs various things in Beaver Builder',
19
+ 'Logger: Plugin Beaver Builder',
20
+ 'simple-history'
21
+ ),
22
+ 'name_via' => _x(
23
+ 'Using plugin Beaver Builder',
24
+ 'Logger: Plugin Beaver Builder',
25
+ 'simple-history'
26
+ ),
27
+ 'capability' => 'manage_options',
28
+ 'messages' => array(
29
+ 'layout_saved' => __(
30
+ 'Layout "{layout_name}" updated',
31
+ 'simple-history'
32
+ ),
33
+ 'template_saved' => __(
34
+ 'Template "{layout_name}" updated',
35
+ 'simple-history'
36
+ ),
37
+ 'draft_saved' => __(
38
+ 'Draft "{layout_name}" updated',
39
+ 'simple-history'
40
+ ),
41
+ 'admin_saved' => __(
42
+ 'Beaver Builder settings saved',
43
+ 'simple-history'
44
+ )
45
+ )
46
+ );
47
+
48
+ return $arr_info;
49
+ }
50
+
51
+ function loaded()
52
+ {
53
+ if (!class_exists('FLBuilder')) {
54
+ return;
55
+ }
56
+
57
+ add_action(
58
+ 'fl_builder_after_save_layout',
59
+ array($this, 'save_layout'),
60
+ 10,
61
+ 4
62
+ );
63
+ add_action(
64
+ 'fl_builder_after_save_user_template',
65
+ array($this, 'save_layout'),
66
+ 10,
67
+ 4
68
+ );
69
+ add_action(
70
+ 'fl_builder_after_save_draft',
71
+ array($this, 'save_layout'),
72
+ 10,
73
+ 4
74
+ );
75
+ add_action('fl_builder_admin_settings_save', array(
76
+ $this,
77
+ 'save_admin'
78
+ ));
79
+ }
80
+
81
+ function save_layout($post_id, $publish, $data, $settings)
82
+ {
83
+ $post = get_post($post_id);
84
+ $context = array(
85
+ 'layout_name' => $post->post_name
86
+ );
87
+ $this->noticeMessage('layout_saved', $context);
88
+ }
89
+
90
+ function save_admin()
91
+ {
92
+ $this->noticeMessage('admin_saved');
93
+ }
94
+ } // class
95
+ } // End if().
loggers/SimpleCommentsLogger.php CHANGED
@@ -280,7 +280,7 @@ class SimpleCommentsLogger extends SimpleLogger {
280
  'trackback_edited',
281
  'pingback_edited',
282
  ),
283
- _x( 'Approved comments', 'Comments logger: search', 'simple-history' ) => array(
284
  'comment_status_approve',
285
  'trackback_status_approve',
286
  'pingback_status_approve',
280
  'trackback_edited',
281
  'pingback_edited',
282
  ),
283
+ _x( 'Approved comments', 'Comments logger: search', 'simple-history' ) => array(
284
  'comment_status_approve',
285
  'trackback_status_approve',
286
  'pingback_status_approve',
loggers/SimpleLogger.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
 
3
- defined( 'ABSPATH' ) or die();
4
 
5
  /**
6
  * A PSR-3 inspired logger class
@@ -10,8 +10,8 @@ defined( 'ABSPATH' ) or die();
10
  *
11
  * @link https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md PSR-3 specification
12
  */
13
- class SimpleLogger {
14
-
15
  /**
16
  * Unique slug for this logger
17
  * Will be saved in DB and used to associate each log row with its logger
@@ -62,23 +62,23 @@ class SimpleLogger {
62
  *
63
  * @param $simpleHistory history class objectinstance
64
  */
65
- public function __construct( $simpleHistory = null ) {
66
-
67
  global $wpdb;
68
 
69
  $this->db_table = $wpdb->prefix . SimpleHistory::DBTABLE;
70
- $this->db_table_contexts = $wpdb->prefix . SimpleHistory::DBTABLE_CONTEXTS;
 
71
 
72
  $this->simpleHistory = $simpleHistory;
73
-
74
  }
75
 
76
  /**
77
  * Method that is called automagically when logger is loaded by Simple History
78
  * Add your init stuff here
79
  */
80
- public function loaded() {
81
-
82
  }
83
 
84
  /**
@@ -86,10 +86,9 @@ class SimpleLogger {
86
  *
87
  * @return array
88
  */
89
- function getInfo() {
90
-
91
  $arr_info = array(
92
-
93
  // The logger slug. Defaulting to the class name is nice and logical I think
94
  'slug' => __CLASS__,
95
 
@@ -103,12 +102,10 @@ class SimpleLogger {
103
  'messages' => array(
104
  // No pre-defined variants
105
  // when adding messages __() or _x() must be used
106
- ),
107
-
108
  );
109
 
110
  return $arr_info;
111
-
112
  }
113
 
114
  /**
@@ -118,12 +115,11 @@ class SimpleLogger {
118
  * @since 2.5.4
119
  * @return Mixed
120
  */
121
- function getInfoValueByKey( $key ) {
122
-
123
  $arr_info = $this->getInfo();
124
 
125
- return isset( $arr_info[ $key ] ) ? $arr_info[ $key ] : null;
126
-
127
  }
128
 
129
  /**
@@ -131,18 +127,17 @@ class SimpleLogger {
131
  *
132
  * @return $string capability
133
  */
134
- public function getCapability() {
135
-
136
  $arr_info = $this->getInfo();
137
 
138
  $capability = 'manage_options';
139
 
140
- if ( ! empty( $arr_info['capability'] ) ) {
141
  $capability = $arr_info['capability'];
142
  }
143
 
144
  return $capability;
145
-
146
  }
147
 
148
  /**
@@ -152,9 +147,9 @@ class SimpleLogger {
152
  * @param array $context
153
  * @param array $row Currently not always passed, because loggers need to be updated to support this...
154
  */
155
- function interpolate( $message, $context = array(), $row = null ) {
156
-
157
- if ( ! is_array( $context ) ) {
158
  return $message;
159
  }
160
 
@@ -163,26 +158,29 @@ class SimpleLogger {
163
  *
164
  * @since 2.2.4
165
  */
166
- $context = apply_filters( 'simple_history/logger/interpolate/context', $context, $message, $row );
 
 
 
 
 
167
 
168
  // Build a replacement array with braces around the context keys
169
  $replace = array();
170
- foreach ( $context as $key => $val ) {
171
-
172
  // Both key and val must be strings or number (for vals)
173
- if ( is_string( $key ) || is_numeric( $key ) ) {
174
  // key ok
175
  }
176
 
177
- if ( is_string( $val ) || is_numeric( $val ) ) {
178
  // val ok
179
  } else {
180
  // not a value we can replace
181
  continue;
182
  }
183
 
184
- $replace[ '{' . $key . '}' ] = $val;
185
-
186
  }
187
 
188
  // Interpolate replacement values into the message and return
@@ -199,8 +197,7 @@ class SimpleLogger {
199
  }
200
  // */
201
 
202
- return strtr( $message, $replace );
203
-
204
  }
205
 
206
  /**
@@ -210,38 +207,44 @@ class SimpleLogger {
210
  *
211
  * @return string HTML
212
  */
213
- function getLogRowHeaderOutput( $row ) {
214
-
215
  // HTML for initiator
216
  $initiator_html = '';
217
 
218
  $initiator = $row->initiator;
219
  $context = $row->context;
220
 
221
- switch ( $initiator ) {
222
-
223
  case 'wp':
224
- $initiator_html .= '<strong class="SimpleHistoryLogitem__inlineDivided">WordPress</strong> ';
 
225
  break;
226
 
227
  case 'wp_cli':
228
- $initiator_html .= '<strong class="SimpleHistoryLogitem__inlineDivided">WP-CLI</strong> ';
 
229
  break;
230
 
231
  // wp_user = wordpress uses, but user may have been deleted since log entry was added
232
  case 'wp_user':
233
- $user_id = isset( $row->context['_user_id'] ) ? $row->context['_user_id'] : null;
234
-
235
- if ( $user_id > 0 && $user = get_user_by( 'id', $user_id ) ) {
236
 
 
237
  // Sender is user and user still exists
238
- $is_current_user = ( get_current_user_id() == $user_id ) ? true : false;
 
239
 
240
  // get user role, as done in user-edit.php
241
  $wp_roles = $GLOBALS['wp_roles'];
242
  $all_roles = (array) $wp_roles->roles;
243
- $user_roles = array_intersect( array_values( (array) $user->roles ), array_keys( (array) $wp_roles->roles ) );
244
- $user_role = array_shift( $user_roles );
 
 
 
245
 
246
  $user_display_name = $user->display_name;
247
 
@@ -252,25 +255,24 @@ class SimpleLogger {
252
  * @param bool If you should be used
253
  * @since 2.1
254
  */
255
- $use_you = apply_filters( 'simple_history/header_initiator_use_you', true );
256
-
257
- if ( $use_you && $is_current_user ) {
 
258
 
 
259
  $tmpl_initiator_html = '
260
  <a href="%6$s" class="SimpleHistoryLogitem__headerUserProfileLink">
261
  <strong class="SimpleHistoryLogitem__inlineDivided">%5$s</strong>
262
  </a>
263
  ';
264
-
265
  } else {
266
-
267
  $tmpl_initiator_html = '
268
  <a href="%6$s" class="SimpleHistoryLogitem__headerUserProfileLink">
269
  <strong class="SimpleHistoryLogitem__inlineDivided">%3$s</strong>
270
  <span class="SimpleHistoryLogitem__inlineDivided SimpleHistoryLogitem__headerEmail">%2$s</span>
271
  </a>
272
  ';
273
-
274
  }
275
 
276
  /**
@@ -280,20 +282,25 @@ class SimpleLogger {
280
  *
281
  * @param string $format.
282
  */
283
- $tmpl_initiator_html = apply_filters( 'simple_history/header_initiator_html_existing_user', $tmpl_initiator_html );
 
 
 
284
 
285
  $initiator_html .= sprintf(
286
  $tmpl_initiator_html,
287
- esc_html( $user->user_login ), // 1
288
- esc_html( $user->user_email ), // 2
289
- esc_html( $user_display_name ), // 3
290
  $user_role, // 4
291
- _x( 'You', 'header output when initiator is the currently logged in user', 'simple-history' ), // 5
292
- get_edit_user_link( $user_id ) // 6
 
 
 
 
293
  );
294
-
295
- } elseif ( $user_id > 0 ) {
296
-
297
  // Sender was a user, but user is deleted now
298
  // output all info we have
299
  // _user_id
@@ -302,14 +309,16 @@ class SimpleLogger {
302
  // _user_email
303
  $initiator_html .= sprintf(
304
  '<strong class="SimpleHistoryLogitem__inlineDivided">' .
305
- __( 'Deleted user (had id %1$s, email %2$s, login %3$s)', 'simple-history' ) .
306
- '</strong>',
307
- esc_html( $context['_user_id'] ), // 1
308
- esc_html( $context['_user_email'] ), // 2
309
- esc_html( $context['_user_login'] ) // 3
 
 
 
310
  );
311
-
312
- }// End if().
313
 
314
  break;
315
 
@@ -323,26 +332,29 @@ class SimpleLogger {
323
  */
324
 
325
  // Check if additional IP addresses are stored, from http_x_forwarded_for and so on
326
- $arr_found_additional_ip_headers = $this->get_event_ip_number_headers( $row );
327
-
328
- if ( empty( $context['_server_remote_addr'] ) ) {
329
-
330
- $initiator_html .= "<strong class='SimpleHistoryLogitem__inlineDivided'>" . __( 'Anonymous web user', 'simple-history' ) . '</strong> ';
331
-
 
 
 
332
  } else {
333
-
334
- $initiator_html .= "<strong class='SimpleHistoryLogitem__inlineDivided SimpleHistoryLogitem__anonUserWithIp'>";
335
 
336
  // if ( sizeof( $arr_found_additional_ip_headers ) ) {
337
- // $iplookup_link = sprintf('https://ipinfo.io/%1$s', esc_attr($context["_server_remote_addr"]));
338
- // $ip_numbers_joined = wp_sprintf_l('%l', array("_server_remote_addr" => $context["_server_remote_addr"]) + $arr_found_additional_ip_headers);
339
- /*
340
  $initiator_html .= sprintf(
341
  __('Anonymous user with multiple IP addresses detected: %1$s', "simple-history"),
342
  "<a target='_blank' href={$iplookup_link} class='SimpleHistoryLogitem__anonUserWithIp__theIp'>" . esc_html( $ip_numbers_joined ) . "</a>"
343
  );*/
344
 
345
- /*
346
  print_r($arr_found_additional_ip_headers);
347
  Array
348
  (
@@ -352,13 +364,18 @@ class SimpleLogger {
352
  */
353
 
354
  // } else {
355
- // single ip address
356
- $iplookup_link = sprintf( 'https://ipinfo.io/%1$s', esc_attr( $context['_server_remote_addr'] ) );
 
 
 
357
 
358
- $initiator_html .= sprintf(
359
- __( 'Anonymous user from %1$s', 'simple-history' ),
360
- "<a target='_blank' href={$iplookup_link} class='SimpleHistoryLogitem__anonUserWithIp__theIp'>" . esc_html( $context['_server_remote_addr'] ) . '</a>'
361
- );
 
 
362
 
363
  // } // multiple ip
364
  $initiator_html .= '</strong> ';
@@ -367,12 +384,19 @@ class SimpleLogger {
367
  // $initiator_html .= "<strong>" . __("<br><br>{$context["_server_remote_addr"]}") . "</strong>";
368
  // $initiator_html .= "<strong>" . __("<br><br>User from IP {$context["_server_remote_addr"]}") . "</strong>";
369
  // $initiator_html .= "<strong>" . __("<br><br>Non-logged in user from IP {$context["_server_remote_addr"]}") . "</strong>";
370
- }// End if().
371
 
372
  break;
373
 
374
  case 'other':
375
- $initiator_html .= "<strong class='SimpleHistoryLogitem__inlineDivided'>" . _x( 'Other', 'Event header output, when initiator is unknown', 'simple-history' ) . '</strong>';
 
 
 
 
 
 
 
376
  break;
377
 
378
  // no initiator
@@ -381,9 +405,11 @@ class SimpleLogger {
381
  break;
382
 
383
  default:
384
- $initiator_html .= "<strong class='SimpleHistoryLogitem__inlineDivided'>" . esc_html( $initiator ) . '</strong>';
385
-
386
- }// End switch().
 
 
387
 
388
  /**
389
  * Filter generated html for the initiator row header html
@@ -393,7 +419,11 @@ class SimpleLogger {
393
  * @param string $initiator_html
394
  * @param object $row Log row
395
  */
396
- $initiator_html = apply_filters( 'simple_history/row_header_initiator_output', $initiator_html, $row );
 
 
 
 
397
 
398
  // HTML for date
399
  // Date (should...) always exist
@@ -402,10 +432,10 @@ class SimpleLogger {
402
  $str_when = '';
403
 
404
  // $row->date is in GMT
405
- $date_datetime = new DateTime( $row->date, new DateTimeZone( 'GMT' ) );
406
 
407
  // Current datetime in GMT
408
- $time_current = strtotime( current_time( 'mysql', 1 ) );
409
 
410
  /**
411
  * Filter how many seconds as most that can pass since an
@@ -416,7 +446,10 @@ class SimpleLogger {
416
  * @param int $time_ago_max_time Seconds
417
  */
418
  $time_ago_max_time = DAY_IN_SECONDS * 2;
419
- $time_ago_max_time = apply_filters( 'simple_history/header_time_ago_max_time', $time_ago_max_time );
 
 
 
420
 
421
  /**
422
  * Filter how many seconds as most that can pass since an
@@ -427,62 +460,90 @@ class SimpleLogger {
427
  * @param int $time_ago_max_time Seconds
428
  */
429
  $time_ago_just_now_max_time = 30;
430
- $time_ago_just_now_max_time = apply_filters( 'simple_history/header_just_now_max_time', $time_ago_just_now_max_time );
 
 
 
431
 
432
- $date_format = get_option( 'date_format' );
433
- $time_format = get_option( 'time_format' );
434
  $date_and_time_format = $date_format . ' - ' . $time_format;
435
 
436
  // Show local time as hours an minutes when event is recent.
437
  $local_date_format = $time_format;
438
 
439
  // Show local time as date and hours when event is a bit older.
440
- if ( ( $time_current - HOUR_IN_SECONDS * 6 ) > $date_datetime->getTimestamp() ) {
 
 
 
441
  $local_date_format = $date_and_time_format;
442
  }
443
 
444
- if ( $time_current - $date_datetime->getTimestamp() <= $time_ago_just_now_max_time ) {
 
 
 
445
  // Show "just now" if event is very recent.
446
- $str_when = __( 'Just now', 'simple-history' );
447
- } elseif ( $time_current - $date_datetime->getTimestamp() > $time_ago_max_time ) {
 
 
 
448
  /* Translators: Date format for log row header, see http://php.net/date */
449
- $datef = __( 'M j, Y \a\t G:i', 'simple-history' );
450
- $str_when = date_i18n( $datef, strtotime( get_date_from_gmt( $row->date ) ) );
 
 
 
451
  } else {
452
  // Show "nn minutes ago" when event is xx seconds ago or earlier
453
- $date_human_time_diff = human_time_diff( $date_datetime->getTimestamp(), $time_current );
 
 
 
454
  /* Translators: 1: last modified date and time in human time diff-format */
455
- $str_when = sprintf( __( '%1$s ago', 'simple-history' ), $date_human_time_diff );
 
 
 
456
  }
457
 
458
- $item_permalink = admin_url( 'index.php?page=simple_history_page' );
459
- if ( ! empty( $row->id ) ) {
460
  $item_permalink .= "#item/{$row->id}";
461
  }
462
 
463
  // Datetime attribute on <time> element.
464
  $str_datetime_title = sprintf(
465
- __( '%1$s local time %3$s (%2$s GMT time)', 'simple-history' ),
466
- get_date_from_gmt( $date_datetime->format( 'Y-m-d H:i:s' ), $date_and_time_format ), // 1 local time
467
- $date_datetime->format( $date_and_time_format ), // GMT time
 
 
 
468
  PHP_EOL // 3, new line
469
  );
470
 
471
  // Time and date before live updated relative date.
472
  $str_datetime_local = sprintf(
473
  '%1$s',
474
- get_date_from_gmt( $date_datetime->format( 'Y-m-d H:i:s' ), $local_date_format ) // 1 local time
 
 
 
475
  );
476
 
477
  // HTML for whole span with date info.
478
- $date_html = "<span class='SimpleHistoryLogitem__permalink SimpleHistoryLogitem__when SimpleHistoryLogitem__inlineDivided'>";
 
479
  $date_html .= "<a class='' href='{$item_permalink}'>";
480
  $date_html .= sprintf(
481
  '<span title="%1$s">%4$s (<time datetime="%3$s" class="SimpleHistoryLogitem__when__liveRelative">%2$s</time>)</span>',
482
- esc_attr( $str_datetime_title ), // 1 datetime attribute
483
- esc_html( $str_when ), // 2 date text, visible in log, but overridden by JS relative date script.
484
- $date_datetime->format( DateTime::RFC3339 ), // 3
485
- esc_html( $str_datetime_local ) // 4
486
  );
487
  $date_html .= '</a>';
488
  $date_html .= '</span>';
@@ -495,20 +556,23 @@ class SimpleLogger {
495
  * @param String $date_html
496
  * @param array $row
497
  */
498
- $date_html = apply_filters( 'simple_history/row_header_date_output', $date_html, $row );
 
 
 
 
499
 
500
  // Logger "via" info in header, i.e. output some extra
501
  // info next to the time to make it more clear what plugin etc.
502
  // that "caused" this event
503
  $via_html = '';
504
- $logger_name_via = $this->getInfoValueByKey( 'name_via' );
505
-
506
- if ( $logger_name_via ) {
507
 
508
- $via_html = "<span class='SimpleHistoryLogitem__inlineDivided SimpleHistoryLogitem__via'>";
 
 
509
  $via_html .= $logger_name_via;
510
  $via_html .= '</span>';
511
-
512
  }
513
 
514
  // Loglevel
@@ -544,10 +608,9 @@ class SimpleLogger {
544
  * @param string $html
545
  * @param object $row Log row
546
  */
547
- $html = apply_filters( 'simple_history/row_header_output', $html, $row );
548
 
549
  return $html;
550
-
551
  }
552
 
553
  /**
@@ -566,37 +629,37 @@ class SimpleLogger {
566
  * Image that the name of the user is added in front of the text:
567
  * Jessie James: Edited post "About the company"
568
  */
569
- public function getLogRowPlainTextOutput( $row ) {
570
-
571
  $message = $row->message;
572
- $message_key = isset( $row->context['_message_key'] ) ? $row->context['_message_key'] : null;
 
 
573
 
574
  // Message is translated here, but translation must be added in
575
  // plain text before
576
- if ( empty( $message_key ) ) {
577
-
578
  // Message key did not exist, so check if we should translate using textdomain
579
- if ( ! empty( $row->context['_gettext_domain'] ) ) {
580
- $message = __( $message, $row->context['_gettext_domain'] );
581
  }
582
  } else {
583
-
584
  // Check that messages does exist
585
  // If we for example disable a Logger we may have references
586
  // to message keys that are unavailable. If so then fallback to message.
587
- if ( isset( $this->messages[ $message_key ]['translated_text'] ) ) {
588
- $message = $this->messages[ $message_key ]['translated_text'];
589
  } else {
590
  // Not message exists for message key. Just keep using message.
591
  }
592
  }
593
 
594
- $html = $this->interpolate( $message, $row->context, $row );
595
 
596
  // All messages are escaped by default.
597
  // If you need unescaped output override this method
598
  // in your own logger
599
- $html = esc_html( $html );
600
 
601
  /**
602
  * Filter generated output for plain text output
@@ -606,10 +669,13 @@ class SimpleLogger {
606
  * @param string $html
607
  * @param object $row Log row
608
  */
609
- $html = apply_filters( 'simple_history/row_plain_text_output', $html, $row );
 
 
 
 
610
 
611
  return $html;
612
-
613
  }
614
 
615
  /**
@@ -617,38 +683,40 @@ class SimpleLogger {
617
  * Image can be for example gravar if sender is user,
618
  * or other images if sender i system, wordpress, and so on
619
  */
620
- public function getLogRowSenderImageOutput( $row ) {
621
-
622
  $sender_image_html = '';
623
  $sender_image_size = 32;
624
 
625
  $initiator = $row->initiator;
626
 
627
- switch ( $initiator ) {
628
-
629
  // wp_user = wordpress uses, but user may have been deleted since log entry was added
630
  case 'wp_user':
 
 
 
631
 
632
- $user_id = isset( $row->context['_user_id'] ) ? $row->context['_user_id'] : null;
633
-
634
- if ( $user_id > 0 && $user = get_user_by( 'id', $user_id ) ) {
635
-
636
  // Sender was user
637
- $sender_image_html = $this->simpleHistory->get_avatar( $user->user_email, $sender_image_size );
638
-
639
- } elseif ( $user_id > 0 ) {
640
-
 
641
  // Sender was a user, but user is deleted now
642
- $sender_image_html = $this->simpleHistory->get_avatar( '', $sender_image_size );
643
-
 
 
644
  } else {
645
-
646
- $sender_image_html = $this->simpleHistory->get_avatar( '', $sender_image_size );
647
-
 
648
  }
649
 
650
  break;
651
-
652
  }
653
 
654
  /**
@@ -659,10 +727,13 @@ class SimpleLogger {
659
  * @param string $sender_image_html
660
  * @param object $row Log row
661
  */
662
- $sender_image_html = apply_filters( 'simple_history/row_sender_image_output', $sender_image_html, $row );
 
 
 
 
663
 
664
  return $sender_image_html;
665
-
666
  }
667
 
668
  /**
@@ -673,8 +744,8 @@ class SimpleLogger {
673
  * @param object $row
674
  * @return string HTML-formatted output
675
  */
676
- public function getLogRowDetailsOutput( $row ) {
677
-
678
  $html = '';
679
 
680
  /**
@@ -685,10 +756,9 @@ class SimpleLogger {
685
  * @param string $html
686
  * @param object $row Log row
687
  */
688
- $html = apply_filters( 'simple_history/row_details_output', $html, $row );
689
 
690
  return $html;
691
-
692
  }
693
 
694
  /**
@@ -698,10 +768,9 @@ class SimpleLogger {
698
  * @param array $context
699
  * @return null
700
  */
701
- public function emergency( $message, array $context = array() ) {
702
-
703
- return $this->log( SimpleLoggerLogLevels::EMERGENCY, $message, $context );
704
-
705
  }
706
 
707
  /**
@@ -711,10 +780,13 @@ class SimpleLogger {
711
  * @param array $context
712
  * @return null
713
  */
714
- public function emergencyMessage( $message, array $context = array() ) {
715
-
716
- return $this->logByMessageKey( SimpleLoggerLogLevels::EMERGENCY, $message, $context );
717
-
 
 
 
718
  }
719
 
720
  /**
@@ -725,10 +797,13 @@ class SimpleLogger {
725
  *
726
  * return $this->logByMessageKey(SimpleLoggerLogLevels::EMERGENCY, $message, $context);
727
  */
728
- private function logByMessageKey( $SimpleLoggerLogLevelsLevel, $messageKey, $context ) {
729
-
 
 
 
730
  // When logging by message then the key must exist
731
- if ( ! isset( $this->messages[ $messageKey ]['untranslated_text'] ) ) {
732
  return;
733
  }
734
 
@@ -744,20 +819,25 @@ class SimpleLogger {
744
  * @param array context
745
  * @return bool false to abort logging
746
  */
747
- $doLog = apply_filters( 'simple_history/simple_logger/log_message_key', true, $this->slug, $messageKey, $SimpleLoggerLogLevelsLevel, $context );
 
 
 
 
 
 
 
748
 
749
- if ( ! $doLog ) {
750
  return;
751
  }
752
 
753
  $context['_message_key'] = $messageKey;
754
- $message = $this->messages[ $messageKey ]['untranslated_text'];
755
-
756
- $this->log( $SimpleLoggerLogLevelsLevel, $message, $context );
757
 
 
758
  }
759
 
760
-
761
  /**
762
  * Action must be taken immediately.
763
  *
@@ -765,9 +845,9 @@ class SimpleLogger {
765
  * @param array $context
766
  * @return null
767
  */
768
- public function alert( $message, array $context = array() ) {
769
- return $this->log( SimpleLoggerLogLevels::ALERT, $message, $context );
770
-
771
  }
772
 
773
  /**
@@ -777,10 +857,13 @@ class SimpleLogger {
777
  * @param array $context
778
  * @return null
779
  */
780
- public function alertMessage( $message, array $context = array() ) {
781
-
782
- return $this->logByMessageKey( SimpleLoggerLogLevels::ALERT, $message, $context );
783
-
 
 
 
784
  }
785
 
786
  /**
@@ -792,10 +875,9 @@ class SimpleLogger {
792
  * @param array $context
793
  * @return null
794
  */
795
- public function critical( $message, array $context = array() ) {
796
-
797
- return $this->log( SimpleLoggerLogLevels::CRITICAL, $message, $context );
798
-
799
  }
800
 
801
  /**
@@ -805,17 +887,16 @@ class SimpleLogger {
805
  * @param array $context
806
  * @return null
807
  */
808
- public function criticalMessage( $message, array $context = array() ) {
809
-
810
- if ( ! isset( $this->messages[ $message ]['untranslated_text'] ) ) {
811
  return;
812
  }
813
 
814
  $context['_message_key'] = $message;
815
- $message = $this->messages[ $message ]['untranslated_text'];
816
-
817
- $this->log( SimpleLoggerLogLevels::CRITICAL, $message, $context );
818
 
 
819
  }
820
 
821
  /**
@@ -826,10 +907,9 @@ class SimpleLogger {
826
  * @param array $context
827
  * @return null
828
  */
829
- public function error( $message, array $context = array() ) {
830
-
831
- return $this->log( SimpleLoggerLogLevels::ERROR, $message, $context );
832
-
833
  }
834
 
835
  /**
@@ -840,10 +920,13 @@ class SimpleLogger {
840
  * @param array $context
841
  * @return null
842
  */
843
- public function errorMessage( $message, array $context = array() ) {
844
-
845
- return $this->logByMessageKey( SimpleLoggerLogLevels::ERROR, $message, $context );
846
-
 
 
 
847
  }
848
 
849
  /**
@@ -856,10 +939,9 @@ class SimpleLogger {
856
  * @param array $context
857
  * @return null
858
  */
859
- public function warning( $message, array $context = array() ) {
860
-
861
- return $this->log( SimpleLoggerLogLevels::WARNING, $message, $context );
862
-
863
  }
864
 
865
  /**
@@ -869,10 +951,13 @@ class SimpleLogger {
869
  * @param array $context
870
  * @return null
871
  */
872
- public function warningMessage( $message, array $context = array() ) {
873
-
874
- return $this->logByMessageKey( SimpleLoggerLogLevels::WARNING, $message, $context );
875
-
 
 
 
876
  }
877
 
878
  /**
@@ -882,10 +967,9 @@ class SimpleLogger {
882
  * @param array $context
883
  * @return null
884
  */
885
- public function notice( $message, array $context = array() ) {
886
-
887
- return $this->log( SimpleLoggerLogLevels::NOTICE, $message, $context );
888
-
889
  }
890
 
891
  /**
@@ -895,10 +979,13 @@ class SimpleLogger {
895
  * @param array $context
896
  * @return null
897
  */
898
- public function noticeMessage( $message, array $context = array() ) {
899
-
900
- return $this->logByMessageKey( SimpleLoggerLogLevels::NOTICE, $message, $context );
901
-
 
 
 
902
  }
903
 
904
  /**
@@ -910,10 +997,9 @@ class SimpleLogger {
910
  * @param array $context
911
  * @return null
912
  */
913
- public function info( $message, array $context = array() ) {
914
-
915
- return $this->log( SimpleLoggerLogLevels::INFO, $message, $context );
916
-
917
  }
918
 
919
  /**
@@ -925,10 +1011,13 @@ class SimpleLogger {
925
  * @param array $context
926
  * @return null
927
  */
928
- public function infoMessage( $message, array $context = array() ) {
929
-
930
- return $this->logByMessageKey( SimpleLoggerLogLevels::INFO, $message, $context );
931
-
 
 
 
932
  }
933
 
934
  /**
@@ -938,10 +1027,9 @@ class SimpleLogger {
938
  * @param array $context
939
  * @return null
940
  */
941
- public function debug( $message, array $context = array() ) {
942
-
943
- return $this->log( SimpleLoggerLogLevels::DEBUG, $message, $context );
944
-
945
  }
946
 
947
  /**
@@ -951,10 +1039,13 @@ class SimpleLogger {
951
  * @param array $context
952
  * @return null
953
  */
954
- public function debugMessage( $message, array $context = array() ) {
955
-
956
- return $this->logByMessageKey( SimpleLoggerLogLevels::DEBUG, $message, $context );
957
-
 
 
 
958
  }
959
 
960
  /**
@@ -965,22 +1056,22 @@ class SimpleLogger {
965
  * @param array $context The log context. Default empty array.
966
  * @return class SimpleLogger instance
967
  */
968
- public function log( $level = 'info', $message = '', $context = array() ) {
969
-
970
  global $wpdb;
971
 
972
  // Check that passed args are of correct types.
973
- if ( ! is_string( $level ) || ! is_string( $message ) ) {
974
  return $this;
975
  }
976
 
977
  // Context must be array, but can be passed as null and so on.
978
- if ( ! is_array( $context ) ) {
979
  $context = array();
980
  }
981
 
982
  // Don't go on if message is empty.
983
- if ( empty( $message ) ) {
984
  return $this;
985
  }
986
 
@@ -990,8 +1081,15 @@ class SimpleLogger {
990
  *
991
  * @since 2.3.1
992
  */
993
- $do_log = apply_filters( 'simple_history/log/do_log', true, $level, $message, $context, $this );
994
- if ( false === $do_log ) {
 
 
 
 
 
 
 
995
  return $this;
996
  }
997
 
@@ -1008,8 +1106,11 @@ class SimpleLogger {
1008
  *
1009
  * @since 2.nn
1010
  */
1011
- $do_log = apply_filters( "simple_history/log/do_log/{$this->slug}", true );
1012
- if ( false === $do_log ) {
 
 
 
1013
  return $this;
1014
  }
1015
 
@@ -1023,27 +1124,32 @@ class SimpleLogger {
1023
  *
1024
  * @since 2.nn
1025
  */
1026
- $message_key = isset( $context['_message_key'] ) ? $context['_message_key'] : null;
1027
- $do_log = apply_filters( "simple_history/log/do_log/{$this->slug}/{$message_key}", true );
1028
- if ( false === $do_log ) {
 
 
 
 
 
1029
  return $this;
1030
  }
1031
 
1032
  // Check if $message is a translated message, and if so then fetch original
1033
- $sh_latest_translations = $this->simpleHistory->gettextLatestTranslations;
1034
-
1035
- if ( ! empty( $sh_latest_translations ) ) {
1036
-
1037
- if ( isset( $sh_latest_translations[ $message ] ) ) {
1038
 
 
 
1039
  // Translation of this phrase was found, so use original phrase instead of translated one
1040
  // Store textdomain since it's required to translate
1041
- $context['_gettext_domain'] = $sh_latest_translations[ $message ]['domain'];
 
1042
 
1043
  // These are good to keep when debugging
1044
  // $context["_gettext_org_message"] = $sh_latest_translations[$message]["text"];
1045
  // $context["_gettext_translated_message"] = $sh_latest_translations[$message]["translation"];
1046
- $message = $sh_latest_translations[ $message ]['text'];
1047
  }
1048
  }
1049
 
@@ -1057,17 +1163,41 @@ class SimpleLogger {
1057
  * @param array $context
1058
  * @param object SimpleLogger object
1059
  */
1060
- apply_filters( 'simple_history/log_arguments', $level, $message, $context, $this );
1061
- $context = apply_filters( 'simple_history/log_argument/context', $context, $level, $message, $this );
1062
- $level = apply_filters( 'simple_history/log_argument/level', $level, $context, $message, $this );
1063
- $message = apply_filters( 'simple_history/log_argument/message', $message, $level, $context, $this );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1064
 
1065
  /*
1066
  Store date as GMT date, i.e. not local date/time
1067
  * Some info here:
1068
  * http://www.skyverge.com/blog/down-the-rabbit-hole-wordpress-and-timezones/
1069
  */
1070
- $localtime = current_time( 'mysql', 1 );
1071
 
1072
  $db_table = $wpdb->prefix . SimpleHistory::DBTABLE;
1073
 
@@ -1078,80 +1208,69 @@ class SimpleLogger {
1078
  *
1079
  * @param string $db_table
1080
  */
1081
- $db_table = apply_filters( 'simple_history/db_table', $db_table );
1082
 
1083
  $data = array(
1084
  'logger' => $this->slug,
1085
  'level' => $level,
1086
  'date' => $localtime,
1087
- 'message' => $message,
1088
  );
1089
 
1090
  // Allow date to be overriden.
1091
  // Date must be in format 'Y-m-d H:i:s'.
1092
- if ( isset( $context['_date'] ) ) {
1093
  $data['date'] = $context['_date'];
1094
- unset( $context['_date'] );
1095
  }
1096
 
1097
  // Add occasions id.
1098
  $occasions_id = null;
1099
- if ( isset( $context['_occasionsID'] ) ) {
1100
-
1101
  // Minimize risk of similar loggers logging same messages and such and resulting in same occasions id
1102
  // by always adding logger slug.
1103
  $occasions_data = array(
1104
  '_occasionsID' => $context['_occasionsID'],
1105
- '_loggerSlug' => $this->slug,
1106
  );
1107
- $occasions_id = md5( json_encode( $occasions_data ) );
1108
- unset( $context['_occasionsID'] );
1109
-
1110
  } else {
1111
-
1112
  // No occasions id specified, create one bases on the data array.
1113
  $occasions_data = $data + $context;
1114
 
1115
  // Don't include date in context data.
1116
- unset( $occasions_data['date'] );
1117
-
1118
- $occasions_id = md5( json_encode( $occasions_data ) );
1119
 
 
1120
  }
1121
 
1122
  $data['occasionsID'] = $occasions_id;
1123
 
1124
  // Log initiator, defaults to current user if exists, or other if not user exist
1125
- if ( isset( $context['_initiator'] ) ) {
1126
-
1127
  // Manually set in context
1128
  $data['initiator'] = $context['_initiator'];
1129
- unset( $context['_initiator'] );
1130
-
1131
  } else {
1132
-
1133
  // No initiator set, try to determine
1134
  // Default to other
1135
  $data['initiator'] = SimpleLoggerLogInitiators::OTHER;
1136
 
1137
  // Check if user is responsible.
1138
- if ( function_exists( 'wp_get_current_user' ) ) {
1139
-
1140
  $current_user = wp_get_current_user();
1141
 
1142
- if ( isset( $current_user->ID ) && $current_user->ID ) {
1143
-
1144
  $data['initiator'] = SimpleLoggerLogInitiators::WP_USER;
1145
  $context['_user_id'] = $current_user->ID;
1146
  $context['_user_login'] = $current_user->user_login;
1147
  $context['_user_email'] = $current_user->user_email;
1148
-
1149
  }
1150
  }
1151
 
1152
  // If cron then set WordPress as responsible
1153
- if ( defined( 'DOING_CRON' ) && DOING_CRON ) {
1154
-
1155
  // Seems to be wp cron running and doing this.
1156
  $data['initiator'] = SimpleLoggerLogInitiators::WORDPRESS;
1157
  $context['_wp_cron_running'] = true;
@@ -1159,7 +1278,6 @@ class SimpleLogger {
1159
  // To aid debugging we log the current filter and a list of all filters.
1160
  global $wp_current_filter;
1161
  $context['_wp_cron_current_filter'] = current_filter();
1162
-
1163
  }
1164
 
1165
  // If running as CLI and WP_CLI_PHP_USED is set then it is WP CLI that is doing it
@@ -1169,22 +1287,30 @@ class SimpleLogger {
1169
  // - it is a specific user, but we don't know who
1170
  // - sounds like a special case, set initiator to wp_cli
1171
  // Can be used by plugins/themes to check if WP-CLI is running or not
1172
- if ( defined( 'WP_CLI' ) && WP_CLI ) {
1173
-
1174
  $data['initiator'] = SimpleLoggerLogInitiators::WP_CLI;
1175
-
1176
  }
1177
- }// End if().
1178
-
1179
- // Detect XML-RPC calls and append to context, if not already there
1180
- if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST && ! isset( $context['_xmlrpc_request'] ) ) {
1181
-
 
 
 
1182
  $context['_xmlrpc_request'] = true;
 
1183
 
 
 
 
 
 
 
1184
  }
1185
 
1186
  // Trim message.
1187
- $data['message'] = trim( $data['message'] );
1188
 
1189
  /**
1190
  * Filter data to be saved to db.
@@ -1193,23 +1319,21 @@ class SimpleLogger {
1193
  *
1194
  * @param array $data
1195
  */
1196
- $data = apply_filters( 'simple_history/log_insert_data', $data );
1197
 
1198
  // Insert data into db.
1199
- $result = $wpdb->insert( $db_table, $data );
1200
 
1201
  $data_parent_row = null;
1202
 
1203
  // Only save context if able to store row.
1204
- if ( false === $result ) {
1205
-
1206
  $history_inserted_id = null;
1207
-
1208
  } else {
1209
-
1210
  $history_inserted_id = $wpdb->insert_id;
1211
 
1212
- $db_table_contexts = $wpdb->prefix . SimpleHistory::DBTABLE_CONTEXTS;
 
1213
 
1214
  /**
1215
  * Filter table name for contexts.
@@ -1218,23 +1342,24 @@ class SimpleLogger {
1218
  *
1219
  * @param string $db_table_contexts
1220
  */
1221
- $db_table_contexts = apply_filters( 'simple_history/logger_db_table_contexts', $db_table_contexts );
 
 
 
1222
 
1223
- if ( ! is_array( $context ) ) {
1224
  $context = array();
1225
  }
1226
 
1227
  // Append user id to context, if not already added.
1228
- if ( ! isset( $context['_user_id'] ) ) {
1229
-
1230
  // wp_get_current_user is not available early.
1231
  // http://codex.wordpress.org/Function_Reference/wp_get_current_user
1232
  // https://core.trac.wordpress.org/ticket/14024
1233
- if ( function_exists( 'wp_get_current_user' ) ) {
1234
-
1235
  $current_user = wp_get_current_user();
1236
 
1237
- if ( isset( $current_user->ID ) && $current_user->ID ) {
1238
  $context['_user_id'] = $current_user->ID;
1239
  $context['_user_login'] = $current_user->user_login;
1240
  $context['_user_email'] = $current_user->user_email;
@@ -1243,9 +1368,10 @@ class SimpleLogger {
1243
  }
1244
 
1245
  // Add remote addr to context.
1246
- if ( ! isset( $context['_server_remote_addr'] ) ) {
1247
-
1248
- $remote_addr = empty( $_SERVER['REMOTE_ADDR'] ) ? '' : wp_unslash( $_SERVER['REMOTE_ADDR'] );
 
1249
 
1250
  /**
1251
  * Filter to control if ip addresses should be anonymized or not.
@@ -1255,10 +1381,16 @@ class SimpleLogger {
1255
  * @param bool true to anonymize ip address, false to keep original ip address.
1256
  * @return bool
1257
  */
1258
- $anonymize_ip_address = apply_filters( 'simple_history/privacy/anonymize_ip_address', true );
1259
-
1260
- if ( $anonymize_ip_address && function_exists( 'wp_privacy_anonymize_ip' ) ) {
1261
- $remote_addr = wp_privacy_anonymize_ip( $remote_addr );
 
 
 
 
 
 
1262
  }
1263
 
1264
  $context['_server_remote_addr'] = $remote_addr;
@@ -1274,40 +1406,42 @@ class SimpleLogger {
1274
  // http://blackbe.lt/advanced-method-to-obtain-the-client-ip-in-php/
1275
  $ip_keys = $this->get_ip_number_header_keys();
1276
 
1277
- foreach ( $ip_keys as $key ) {
1278
-
1279
- if ( array_key_exists( $key, $_SERVER ) === true ) {
1280
-
1281
  // Loop through all IPs.
1282
  $ip_loop_num = 0;
1283
- foreach ( explode( ',', $_SERVER[ $key ] ) as $ip ) {
1284
-
1285
  // trim for safety measures.
1286
- $ip = trim( $ip );
1287
 
1288
  // attempt to validate IP.
1289
- if ( $this->validate_ip( $ip ) ) {
1290
-
1291
  // valid, add to context, with loop index appended so we can store many IPs.
1292
- $key_lower = strtolower( $key );
1293
 
1294
- if ( $anonymize_ip_address && function_exists( 'wp_privacy_anonymize_ip' ) ) {
1295
- $ip = wp_privacy_anonymize_ip( $ip );
 
 
 
1296
  }
1297
 
1298
- $context[ "_server_{$key_lower}_{$ip_loop_num}" ] = $ip;
1299
-
 
1300
  }
1301
 
1302
  $ip_loop_num++;
1303
-
1304
  }
1305
  }
1306
  }
1307
- }// End if().
1308
 
1309
  // Append http referer.
1310
- if ( ! isset( $context['_server_http_referer'] ) && isset( $_SERVER['HTTP_REFERER'] ) ) {
 
 
 
1311
  $context['_server_http_referer'] = $_SERVER['HTTP_REFERER'];
1312
  }
1313
 
@@ -1320,17 +1454,22 @@ class SimpleLogger {
1320
  * @param array $data Array with data used for parent row.
1321
  * @param array $this Reference to this logger instance.
1322
  */
1323
- $context = apply_filters( 'simple_history/log_insert_context', $context, $data, $this );
 
 
 
 
 
1324
  $data_parent_row = $data;
1325
 
1326
  // Insert all context values into db.
1327
- $this->append_context( $history_inserted_id, $context );
1328
- }// End if().
1329
 
1330
  $this->lastInsertID = $history_inserted_id;
1331
  $this->lastInsertContext = $context;
1332
 
1333
- $this->simpleHistory->get_cache_incrementor( true );
1334
 
1335
  /**
1336
  * Action that is called after an event has been logged
@@ -1341,11 +1480,15 @@ class SimpleLogger {
1341
  * @param array $data Array with data used for parent row.
1342
  * @param array $this Reference to this logger instance
1343
  */
1344
- do_action( 'simple_history/log/inserted', $context, $data_parent_row, $this );
 
 
 
 
 
1345
 
1346
  // Return $this so we can chain methods.
1347
  return $this;
1348
-
1349
  } // log
1350
 
1351
  /**
@@ -1355,8 +1498,9 @@ class SimpleLogger {
1355
  * @param array $context Context to append to existing context for the row.
1356
  * @return bool True if context was added, false if not (beacuse row_id or context is empty).
1357
  */
1358
- public function append_context( $history_id, $context ) {
1359
- if ( empty( $history_id ) || empty( $context ) ) {
 
1360
  return false;
1361
  }
1362
 
@@ -1364,20 +1508,19 @@ class SimpleLogger {
1364
 
1365
  $db_table_contexts = $wpdb->prefix . SimpleHistory::DBTABLE_CONTEXTS;
1366
 
1367
- foreach ( $context as $key => $value ) {
1368
-
1369
  // Everything except strings should be json_encoded, ie. arrays and objects.
1370
- if ( ! is_string( $value ) ) {
1371
- $value = simpleHistory::json_encode( $value );
1372
  }
1373
 
1374
  $data = array(
1375
  'history_id' => $history_id,
1376
  'key' => $key,
1377
- 'value' => $value,
1378
  );
1379
 
1380
- $result = $wpdb->insert( $db_table_contexts, $data );
1381
  }
1382
 
1383
  return true;
@@ -1388,19 +1531,18 @@ class SimpleLogger {
1388
  *
1389
  * @since 2.0.29
1390
  */
1391
- public function get_ip_number_header_keys() {
1392
-
1393
  $arr = array(
1394
  'HTTP_CLIENT_IP',
1395
  'HTTP_X_FORWARDED_FOR',
1396
  'HTTP_X_FORWARDED',
1397
  'HTTP_X_CLUSTER_CLIENT_IP',
1398
  'HTTP_FORWARDED_FOR',
1399
- 'HTTP_FORWARDED',
1400
  );
1401
 
1402
  return $arr;
1403
-
1404
  }
1405
 
1406
  /**
@@ -1410,28 +1552,31 @@ class SimpleLogger {
1410
  * @param array $row Row with info.
1411
  * @return array Headers
1412
  */
1413
- function get_event_ip_number_headers( $row ) {
1414
-
1415
  $ip_keys = $this->get_ip_number_header_keys();
1416
  $arr_found_additional_ip_headers = array();
1417
  $context = $row->context;
1418
 
1419
- foreach ( $ip_keys as $one_ip_header_key ) {
1420
-
1421
- $one_ip_header_key_lower = strtolower( $one_ip_header_key );
1422
-
1423
- foreach ( $context as $context_key => $context_val ) {
1424
 
 
1425
  // $key_check_for = "_server_" . strtolower($one_ip_header_key) . "_0";
1426
- $match = preg_match( "/^_server_{$one_ip_header_key_lower}_[\d+]/", $context_key, $matches );
1427
- if ( $match ) {
1428
- $arr_found_additional_ip_headers[ $context_key ] = $context_val;
 
 
 
 
 
 
1429
  }
1430
  }
1431
  } // End foreach().
1432
 
1433
  return $arr_found_additional_ip_headers;
1434
-
1435
  }
1436
 
1437
  /**
@@ -1441,14 +1586,21 @@ class SimpleLogger {
1441
  * @param string $ip IP number.
1442
  * @return bool
1443
  */
1444
- function validate_ip( $ip ) {
1445
-
1446
- if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE ) === false ) {
 
 
 
 
 
 
 
 
1447
  return false;
1448
  }
1449
 
1450
  return true;
1451
-
1452
  }
1453
 
1454
  /**
@@ -1456,7 +1608,8 @@ class SimpleLogger {
1456
  * The CSS that you output will only be outputed
1457
  * on pages where Simple History is used.
1458
  */
1459
- function adminCSS() {
 
1460
  /*
1461
  ?>
1462
  <style>
@@ -1473,7 +1626,8 @@ class SimpleLogger {
1473
  * The JS that you output will only be outputed
1474
  * on pages where Simple History is used.
1475
  */
1476
- function adminJS() {
 
1477
  /*
1478
  ?>
1479
  <script>
@@ -1482,14 +1636,13 @@ class SimpleLogger {
1482
  <?php
1483
  */
1484
  }
1485
-
1486
  }
1487
 
1488
  /**
1489
  * Describes log initiator, i.e. who caused to log event to happend
1490
  */
1491
- class SimpleLoggerLogInitiators {
1492
-
1493
  // A wordpress user that at the log event created did exist in the wp database
1494
  // May have been deleted when the log is viewed.
1495
  const WP_USER = 'wp_user';
@@ -1516,7 +1669,8 @@ class SimpleLoggerLogInitiators {
1516
  * More may be added later on if needed
1517
  * Note: not in use at the moment
1518
  */
1519
- class SimpleLoggerLogTypes {
 
1520
  const CREATE = 'create';
1521
  const READ = 'read';
1522
  const UPDATE = 'update';
@@ -1527,7 +1681,8 @@ class SimpleLoggerLogTypes {
1527
  /**
1528
  * Describes log levels
1529
  */
1530
- class SimpleLoggerLogLevels {
 
1531
  const EMERGENCY = 'emergency';
1532
  const ALERT = 'alert';
1533
  const CRITICAL = 'critical';
1
  <?php
2
 
3
+ defined('ABSPATH') or die();
4
 
5
  /**
6
  * A PSR-3 inspired logger class
10
  *
11
  * @link https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md PSR-3 specification
12
  */
13
+ class SimpleLogger
14
+ {
15
  /**
16
  * Unique slug for this logger
17
  * Will be saved in DB and used to associate each log row with its logger
62
  *
63
  * @param $simpleHistory history class objectinstance
64
  */
65
+ public function __construct($simpleHistory = null)
66
+ {
67
  global $wpdb;
68
 
69
  $this->db_table = $wpdb->prefix . SimpleHistory::DBTABLE;
70
+ $this->db_table_contexts =
71
+ $wpdb->prefix . SimpleHistory::DBTABLE_CONTEXTS;
72
 
73
  $this->simpleHistory = $simpleHistory;
 
74
  }
75
 
76
  /**
77
  * Method that is called automagically when logger is loaded by Simple History
78
  * Add your init stuff here
79
  */
80
+ public function loaded()
81
+ {
82
  }
83
 
84
  /**
86
  *
87
  * @return array
88
  */
89
+ function getInfo()
90
+ {
91
  $arr_info = array(
 
92
  // The logger slug. Defaulting to the class name is nice and logical I think
93
  'slug' => __CLASS__,
94
 
102
  'messages' => array(
103
  // No pre-defined variants
104
  // when adding messages __() or _x() must be used
105
+ )
 
106
  );
107
 
108
  return $arr_info;
 
109
  }
110
 
111
  /**
115
  * @since 2.5.4
116
  * @return Mixed
117
  */
118
+ function getInfoValueByKey($key)
119
+ {
120
  $arr_info = $this->getInfo();
121
 
122
+ return isset($arr_info[$key]) ? $arr_info[$key] : null;
 
123
  }
124
 
125
  /**
127
  *
128
  * @return $string capability
129
  */
130
+ public function getCapability()
131
+ {
132
  $arr_info = $this->getInfo();
133
 
134
  $capability = 'manage_options';
135
 
136
+ if (!empty($arr_info['capability'])) {
137
  $capability = $arr_info['capability'];
138
  }
139
 
140
  return $capability;
 
141
  }
142
 
143
  /**
147
  * @param array $context
148
  * @param array $row Currently not always passed, because loggers need to be updated to support this...
149
  */
150
+ function interpolate($message, $context = array(), $row = null)
151
+ {
152
+ if (!is_array($context)) {
153
  return $message;
154
  }
155
 
158
  *
159
  * @since 2.2.4
160
  */
161
+ $context = apply_filters(
162
+ 'simple_history/logger/interpolate/context',
163
+ $context,
164
+ $message,
165
+ $row
166
+ );
167
 
168
  // Build a replacement array with braces around the context keys
169
  $replace = array();
170
+ foreach ($context as $key => $val) {
 
171
  // Both key and val must be strings or number (for vals)
172
+ if (is_string($key) || is_numeric($key)) {
173
  // key ok
174
  }
175
 
176
+ if (is_string($val) || is_numeric($val)) {
177
  // val ok
178
  } else {
179
  // not a value we can replace
180
  continue;
181
  }
182
 
183
+ $replace['{' . $key . '}'] = $val;
 
184
  }
185
 
186
  // Interpolate replacement values into the message and return
197
  }
198
  // */
199
 
200
+ return strtr($message, $replace);
 
201
  }
202
 
203
  /**
207
  *
208
  * @return string HTML
209
  */
210
+ function getLogRowHeaderOutput($row)
211
+ {
212
  // HTML for initiator
213
  $initiator_html = '';
214
 
215
  $initiator = $row->initiator;
216
  $context = $row->context;
217
 
218
+ switch ($initiator) {
 
219
  case 'wp':
220
+ $initiator_html .=
221
+ '<strong class="SimpleHistoryLogitem__inlineDivided">WordPress</strong> ';
222
  break;
223
 
224
  case 'wp_cli':
225
+ $initiator_html .=
226
+ '<strong class="SimpleHistoryLogitem__inlineDivided">WP-CLI</strong> ';
227
  break;
228
 
229
  // wp_user = wordpress uses, but user may have been deleted since log entry was added
230
  case 'wp_user':
231
+ $user_id = isset($row->context['_user_id'])
232
+ ? $row->context['_user_id']
233
+ : null;
234
 
235
+ if ($user_id > 0 && ($user = get_user_by('id', $user_id))) {
236
  // Sender is user and user still exists
237
+ $is_current_user =
238
+ get_current_user_id() == $user_id ? true : false;
239
 
240
  // get user role, as done in user-edit.php
241
  $wp_roles = $GLOBALS['wp_roles'];
242
  $all_roles = (array) $wp_roles->roles;
243
+ $user_roles = array_intersect(
244
+ array_values((array) $user->roles),
245
+ array_keys((array) $wp_roles->roles)
246
+ );
247
+ $user_role = array_shift($user_roles);
248
 
249
  $user_display_name = $user->display_name;
250
 
255
  * @param bool If you should be used
256
  * @since 2.1
257
  */
258
+ $use_you = apply_filters(
259
+ 'simple_history/header_initiator_use_you',
260
+ true
261
+ );
262
 
263
+ if ($use_you && $is_current_user) {
264
  $tmpl_initiator_html = '
265
  <a href="%6$s" class="SimpleHistoryLogitem__headerUserProfileLink">
266
  <strong class="SimpleHistoryLogitem__inlineDivided">%5$s</strong>
267
  </a>
268
  ';
 
269
  } else {
 
270
  $tmpl_initiator_html = '
271
  <a href="%6$s" class="SimpleHistoryLogitem__headerUserProfileLink">
272
  <strong class="SimpleHistoryLogitem__inlineDivided">%3$s</strong>
273
  <span class="SimpleHistoryLogitem__inlineDivided SimpleHistoryLogitem__headerEmail">%2$s</span>
274
  </a>
275
  ';
 
276
  }
277
 
278
  /**
282
  *
283
  * @param string $format.
284
  */
285
+ $tmpl_initiator_html = apply_filters(
286
+ 'simple_history/header_initiator_html_existing_user',
287
+ $tmpl_initiator_html
288
+ );
289
 
290
  $initiator_html .= sprintf(
291
  $tmpl_initiator_html,
292
+ esc_html($user->user_login), // 1
293
+ esc_html($user->user_email), // 2
294
+ esc_html($user_display_name), // 3
295
  $user_role, // 4
296
+ _x(
297
+ 'You',
298
+ 'header output when initiator is the currently logged in user',
299
+ 'simple-history'
300
+ ), // 5
301
+ get_edit_user_link($user_id) // 6
302
  );
303
+ } elseif ($user_id > 0) {
 
 
304
  // Sender was a user, but user is deleted now
305
  // output all info we have
306
  // _user_id
309
  // _user_email
310
  $initiator_html .= sprintf(
311
  '<strong class="SimpleHistoryLogitem__inlineDivided">' .
312
+ __(
313
+ 'Deleted user (had id %1$s, email %2$s, login %3$s)',
314
+ 'simple-history'
315
+ ) .
316
+ '</strong>',
317
+ esc_html($context['_user_id']), // 1
318
+ esc_html($context['_user_email']), // 2
319
+ esc_html($context['_user_login']) // 3
320
  );
321
+ } // End if().
 
322
 
323
  break;
324
 
332
  */
333
 
334
  // Check if additional IP addresses are stored, from http_x_forwarded_for and so on
335
+ $arr_found_additional_ip_headers = $this->get_event_ip_number_headers(
336
+ $row
337
+ );
338
+
339
+ if (empty($context['_server_remote_addr'])) {
340
+ $initiator_html .=
341
+ "<strong class='SimpleHistoryLogitem__inlineDivided'>" .
342
+ __('Anonymous web user', 'simple-history') .
343
+ '</strong> ';
344
  } else {
345
+ $initiator_html .=
346
+ "<strong class='SimpleHistoryLogitem__inlineDivided SimpleHistoryLogitem__anonUserWithIp'>";
347
 
348
  // if ( sizeof( $arr_found_additional_ip_headers ) ) {
349
+ // $iplookup_link = sprintf('https://ipinfo.io/%1$s', esc_attr($context["_server_remote_addr"]));
350
+ // $ip_numbers_joined = wp_sprintf_l('%l', array("_server_remote_addr" => $context["_server_remote_addr"]) + $arr_found_additional_ip_headers);
351
+ /*
352
  $initiator_html .= sprintf(
353
  __('Anonymous user with multiple IP addresses detected: %1$s', "simple-history"),
354
  "<a target='_blank' href={$iplookup_link} class='SimpleHistoryLogitem__anonUserWithIp__theIp'>" . esc_html( $ip_numbers_joined ) . "</a>"
355
  );*/
356
 
357
+ /*
358
  print_r($arr_found_additional_ip_headers);
359
  Array
360
  (
364
  */
365
 
366
  // } else {
367
+ // single ip address
368
+ $iplookup_link = sprintf(
369
+ 'https://ipinfo.io/%1$s',
370
+ esc_attr($context['_server_remote_addr'])
371
+ );
372
 
373
+ $initiator_html .= sprintf(
374
+ __('Anonymous user from %1$s', 'simple-history'),
375
+ "<a target='_blank' href={$iplookup_link} class='SimpleHistoryLogitem__anonUserWithIp__theIp'>" .
376
+ esc_html($context['_server_remote_addr']) .
377
+ '</a>'
378
+ );
379
 
380
  // } // multiple ip
381
  $initiator_html .= '</strong> ';
384
  // $initiator_html .= "<strong>" . __("<br><br>{$context["_server_remote_addr"]}") . "</strong>";
385
  // $initiator_html .= "<strong>" . __("<br><br>User from IP {$context["_server_remote_addr"]}") . "</strong>";
386
  // $initiator_html .= "<strong>" . __("<br><br>Non-logged in user from IP {$context["_server_remote_addr"]}") . "</strong>";
387
+ } // End if().
388
 
389
  break;
390
 
391
  case 'other':
392
+ $initiator_html .=
393
+ "<strong class='SimpleHistoryLogitem__inlineDivided'>" .
394
+ _x(
395
+ 'Other',
396
+ 'Event header output, when initiator is unknown',
397
+ 'simple-history'
398
+ ) .
399
+ '</strong>';
400
  break;
401
 
402
  // no initiator
405
  break;
406
 
407
  default:
408
+ $initiator_html .=
409
+ "<strong class='SimpleHistoryLogitem__inlineDivided'>" .
410
+ esc_html($initiator) .
411
+ '</strong>';
412
+ } // End switch().
413
 
414
  /**
415
  * Filter generated html for the initiator row header html
419
  * @param string $initiator_html
420
  * @param object $row Log row
421
  */
422
+ $initiator_html = apply_filters(
423
+ 'simple_history/row_header_initiator_output',
424
+ $initiator_html,
425
+ $row
426
+ );
427
 
428
  // HTML for date
429
  // Date (should...) always exist
432
  $str_when = '';
433
 
434
  // $row->date is in GMT
435
+ $date_datetime = new DateTime($row->date, new DateTimeZone('GMT'));
436
 
437
  // Current datetime in GMT
438
+ $time_current = strtotime(current_time('mysql', 1));
439
 
440
  /**
441
  * Filter how many seconds as most that can pass since an
446
  * @param int $time_ago_max_time Seconds
447
  */
448
  $time_ago_max_time = DAY_IN_SECONDS * 2;
449
+ $time_ago_max_time = apply_filters(
450
+ 'simple_history/header_time_ago_max_time',
451
+ $time_ago_max_time
452
+ );
453
 
454
  /**
455
  * Filter how many seconds as most that can pass since an
460
  * @param int $time_ago_max_time Seconds
461
  */
462
  $time_ago_just_now_max_time = 30;
463
+ $time_ago_just_now_max_time = apply_filters(
464
+ 'simple_history/header_just_now_max_time',
465
+ $time_ago_just_now_max_time
466
+ );
467
 
468
+ $date_format = get_option('date_format');
469
+ $time_format = get_option('time_format');
470
  $date_and_time_format = $date_format . ' - ' . $time_format;
471
 
472
  // Show local time as hours an minutes when event is recent.
473
  $local_date_format = $time_format;
474
 
475
  // Show local time as date and hours when event is a bit older.
476
+ if (
477
+ $time_current - HOUR_IN_SECONDS * 6 >
478
+ $date_datetime->getTimestamp()
479
+ ) {
480
  $local_date_format = $date_and_time_format;
481
  }
482
 
483
+ if (
484
+ $time_current - $date_datetime->getTimestamp() <=
485
+ $time_ago_just_now_max_time
486
+ ) {
487
  // Show "just now" if event is very recent.
488
+ $str_when = __('Just now', 'simple-history');
489
+ } elseif (
490
+ $time_current - $date_datetime->getTimestamp() >
491
+ $time_ago_max_time
492
+ ) {
493
  /* Translators: Date format for log row header, see http://php.net/date */
494
+ $datef = __('M j, Y \a\t G:i', 'simple-history');
495
+ $str_when = date_i18n(
496
+ $datef,
497
+ strtotime(get_date_from_gmt($row->date))
498
+ );
499
  } else {
500
  // Show "nn minutes ago" when event is xx seconds ago or earlier
501
+ $date_human_time_diff = human_time_diff(
502
+ $date_datetime->getTimestamp(),
503
+ $time_current
504
+ );
505
  /* Translators: 1: last modified date and time in human time diff-format */
506
+ $str_when = sprintf(
507
+ __('%1$s ago', 'simple-history'),
508
+ $date_human_time_diff
509
+ );
510
  }
511
 
512
+ $item_permalink = admin_url('index.php?page=simple_history_page');
513
+ if (!empty($row->id)) {
514
  $item_permalink .= "#item/{$row->id}";
515
  }
516
 
517
  // Datetime attribute on <time> element.
518
  $str_datetime_title = sprintf(
519
+ __('%1$s local time %3$s (%2$s GMT time)', 'simple-history'),
520
+ get_date_from_gmt(
521
+ $date_datetime->format('Y-m-d H:i:s'),
522
+ $date_and_time_format
523
+ ), // 1 local time
524
+ $date_datetime->format($date_and_time_format), // GMT time
525
  PHP_EOL // 3, new line
526
  );
527
 
528
  // Time and date before live updated relative date.
529
  $str_datetime_local = sprintf(
530
  '%1$s',
531
+ get_date_from_gmt(
532
+ $date_datetime->format('Y-m-d H:i:s'),
533
+ $local_date_format
534
+ ) // 1 local time
535
  );
536
 
537
  // HTML for whole span with date info.
538
+ $date_html =
539
+ "<span class='SimpleHistoryLogitem__permalink SimpleHistoryLogitem__when SimpleHistoryLogitem__inlineDivided'>";
540
  $date_html .= "<a class='' href='{$item_permalink}'>";
541
  $date_html .= sprintf(
542
  '<span title="%1$s">%4$s (<time datetime="%3$s" class="SimpleHistoryLogitem__when__liveRelative">%2$s</time>)</span>',
543
+ esc_attr($str_datetime_title), // 1 datetime attribute
544
+ esc_html($str_when), // 2 date text, visible in log, but overridden by JS relative date script.
545
+ $date_datetime->format(DateTime::RFC3339), // 3
546
+ esc_html($str_datetime_local) // 4
547
  );
548
  $date_html .= '</a>';
549
  $date_html .= '</span>';
556
  * @param String $date_html
557
  * @param array $row
558
  */
559
+ $date_html = apply_filters(
560
+ 'simple_history/row_header_date_output',
561
+ $date_html,
562
+ $row
563
+ );
564
 
565
  // Logger "via" info in header, i.e. output some extra
566
  // info next to the time to make it more clear what plugin etc.
567
  // that "caused" this event
568
  $via_html = '';
569
+ $logger_name_via = $this->getInfoValueByKey('name_via');
 
 
570
 
571
+ if ($logger_name_via) {
572
+ $via_html =
573
+ "<span class='SimpleHistoryLogitem__inlineDivided SimpleHistoryLogitem__via'>";
574
  $via_html .= $logger_name_via;
575
  $via_html .= '</span>';
 
576
  }
577
 
578
  // Loglevel
608
  * @param string $html
609
  * @param object $row Log row
610
  */
611
+ $html = apply_filters('simple_history/row_header_output', $html, $row);
612
 
613
  return $html;
 
614
  }
615
 
616
  /**
629
  * Image that the name of the user is added in front of the text:
630
  * Jessie James: Edited post "About the company"
631
  */
632
+ public function getLogRowPlainTextOutput($row)
633
+ {
634
  $message = $row->message;
635
+ $message_key = isset($row->context['_message_key'])
636
+ ? $row->context['_message_key']
637
+ : null;
638
 
639
  // Message is translated here, but translation must be added in
640
  // plain text before
641
+ if (empty($message_key)) {
 
642
  // Message key did not exist, so check if we should translate using textdomain
643
+ if (!empty($row->context['_gettext_domain'])) {
644
+ $message = __($message, $row->context['_gettext_domain']);
645
  }
646
  } else {
 
647
  // Check that messages does exist
648
  // If we for example disable a Logger we may have references
649
  // to message keys that are unavailable. If so then fallback to message.
650
+ if (isset($this->messages[$message_key]['translated_text'])) {
651
+ $message = $this->messages[$message_key]['translated_text'];
652
  } else {
653
  // Not message exists for message key. Just keep using message.
654
  }
655
  }
656
 
657
+ $html = $this->interpolate($message, $row->context, $row);
658
 
659
  // All messages are escaped by default.
660
  // If you need unescaped output override this method
661
  // in your own logger
662
+ $html = esc_html($html);
663
 
664
  /**
665
  * Filter generated output for plain text output
669
  * @param string $html
670
  * @param object $row Log row
671
  */
672
+ $html = apply_filters(
673
+ 'simple_history/row_plain_text_output',
674
+ $html,
675
+ $row
676
+ );
677
 
678
  return $html;
 
679
  }
680
 
681
  /**
683
  * Image can be for example gravar if sender is user,
684
  * or other images if sender i system, wordpress, and so on
685
  */
686
+ public function getLogRowSenderImageOutput($row)
687
+ {
688
  $sender_image_html = '';
689
  $sender_image_size = 32;
690
 
691
  $initiator = $row->initiator;
692
 
693
+ switch ($initiator) {
 
694
  // wp_user = wordpress uses, but user may have been deleted since log entry was added
695
  case 'wp_user':
696
+ $user_id = isset($row->context['_user_id'])
697
+ ? $row->context['_user_id']
698
+ : null;
699
 
700
+ if ($user_id > 0 && ($user = get_user_by('id', $user_id))) {
 
 
 
701
  // Sender was user
702
+ $sender_image_html = $this->simpleHistory->get_avatar(
703
+ $user->user_email,
704
+ $sender_image_size
705
+ );
706
+ } elseif ($user_id > 0) {
707
  // Sender was a user, but user is deleted now
708
+ $sender_image_html = $this->simpleHistory->get_avatar(
709
+ '',
710
+ $sender_image_size
711
+ );
712
  } else {
713
+ $sender_image_html = $this->simpleHistory->get_avatar(
714
+ '',
715
+ $sender_image_size
716
+ );
717
  }
718
 
719
  break;
 
720
  }
721
 
722
  /**
727
  * @param string $sender_image_html
728
  * @param object $row Log row
729
  */
730
+ $sender_image_html = apply_filters(
731
+ 'simple_history/row_sender_image_output',
732
+ $sender_image_html,
733
+ $row
734
+ );
735
 
736
  return $sender_image_html;
 
737
  }
738
 
739
  /**
744
  * @param object $row
745
  * @return string HTML-formatted output
746
  */
747
+ public function getLogRowDetailsOutput($row)
748
+ {
749
  $html = '';
750
 
751
  /**
756
  * @param string $html
757
  * @param object $row Log row
758
  */
759
+ $html = apply_filters('simple_history/row_details_output', $html, $row);
760
 
761
  return $html;
 
762
  }
763
 
764
  /**
768
  * @param array $context
769
  * @return null
770
  */
771
+ public function emergency($message, array $context = array())
772
+ {
773
+ return $this->log(SimpleLoggerLogLevels::EMERGENCY, $message, $context);
 
774
  }
775
 
776
  /**
780
  * @param array $context
781
  * @return null
782
  */
783
+ public function emergencyMessage($message, array $context = array())
784
+ {
785
+ return $this->logByMessageKey(
786
+ SimpleLoggerLogLevels::EMERGENCY,
787
+ $message,
788
+ $context
789
+ );
790
  }
791
 
792
  /**
797
  *
798
  * return $this->logByMessageKey(SimpleLoggerLogLevels::EMERGENCY, $message, $context);
799
  */
800
+ private function logByMessageKey(
801
+ $SimpleLoggerLogLevelsLevel,
802
+ $messageKey,
803
+ $context
804
+ ) {
805
  // When logging by message then the key must exist
806
+ if (!isset($this->messages[$messageKey]['untranslated_text'])) {
807
  return;
808
  }
809
 
819
  * @param array context
820
  * @return bool false to abort logging
821
  */
822
+ $doLog = apply_filters(
823
+ 'simple_history/simple_logger/log_message_key',
824
+ true,
825
+ $this->slug,
826
+ $messageKey,
827
+ $SimpleLoggerLogLevelsLevel,
828
+ $context
829
+ );
830
 
831
+ if (!$doLog) {
832
  return;
833
  }
834
 
835
  $context['_message_key'] = $messageKey;
836
+ $message = $this->messages[$messageKey]['untranslated_text'];
 
 
837
 
838
+ $this->log($SimpleLoggerLogLevelsLevel, $message, $context);
839
  }
840
 
 
841
  /**
842
  * Action must be taken immediately.
843
  *
845
  * @param array $context
846
  * @return null
847
  */
848
+ public function alert($message, array $context = array())
849
+ {
850
+ return $this->log(SimpleLoggerLogLevels::ALERT, $message, $context);
851
  }
852
 
853
  /**
857
  * @param array $context
858
  * @return null
859
  */
860
+ public function alertMessage($message, array $context = array())
861
+ {
862
+ return $this->logByMessageKey(
863
+ SimpleLoggerLogLevels::ALERT,
864
+ $message,
865
+ $context
866
+ );
867
  }
868
 
869
  /**
875
  * @param array $context
876
  * @return null
877
  */
878
+ public function critical($message, array $context = array())
879
+ {
880
+ return $this->log(SimpleLoggerLogLevels::CRITICAL, $message, $context);
 
881
  }
882
 
883
  /**
887
  * @param array $context
888
  * @return null
889
  */
890
+ public function criticalMessage($message, array $context = array())
891
+ {
892
+ if (!isset($this->messages[$message]['untranslated_text'])) {
893
  return;
894
  }
895
 
896
  $context['_message_key'] = $message;
897
+ $message = $this->messages[$message]['untranslated_text'];
 
 
898
 
899
+ $this->log(SimpleLoggerLogLevels::CRITICAL, $message, $context);
900
  }
901
 
902
  /**
907
  * @param array $context
908
  * @return null
909
  */
910
+ public function error($message, array $context = array())
911
+ {
912
+ return $this->log(SimpleLoggerLogLevels::ERROR, $message, $context);
 
913
  }
914
 
915
  /**
920
  * @param array $context
921
  * @return null
922
  */
923
+ public function errorMessage($message, array $context = array())
924
+ {
925
+ return $this->logByMessageKey(
926
+ SimpleLoggerLogLevels::ERROR,
927
+ $message,
928
+ $context
929
+ );
930
  }
931
 
932
  /**
939
  * @param array $context
940
  * @return null
941
  */
942
+ public function warning($message, array $context = array())
943
+ {
944
+ return $this->log(SimpleLoggerLogLevels::WARNING, $message, $context);
 
945
  }
946
 
947
  /**
951
  * @param array $context
952
  * @return null
953
  */
954
+ public function warningMessage($message, array $context = array())
955
+ {
956
+ return $this->logByMessageKey(
957
+ SimpleLoggerLogLevels::WARNING,
958
+ $message,
959
+ $context
960
+ );
961
  }
962
 
963
  /**
967
  * @param array $context
968
  * @return null
969
  */
970
+ public function notice($message, array $context = array())
971
+ {
972
+ return $this->log(SimpleLoggerLogLevels::NOTICE, $message, $context);
 
973
  }
974
 
975
  /**
979
  * @param array $context
980
  * @return null
981
  */
982
+ public function noticeMessage($message, array $context = array())
983
+ {
984
+ return $this->logByMessageKey(
985
+ SimpleLoggerLogLevels::NOTICE,
986
+ $message,
987
+ $context
988
+ );
989
  }
990
 
991
  /**
997
  * @param array $context
998
  * @return null
999
  */
1000
+ public function info($message, array $context = array())
1001
+ {
1002
+ return $this->log(SimpleLoggerLogLevels::INFO, $message, $context);
 
1003
  }
1004
 
1005
  /**
1011
  * @param array $context
1012
  * @return null
1013
  */
1014
+ public function infoMessage($message, array $context = array())
1015
+ {
1016
+ return $this->logByMessageKey(
1017
+ SimpleLoggerLogLevels::INFO,
1018
+ $message,
1019
+ $context
1020
+ );
1021
  }
1022
 
1023
  /**
1027
  * @param array $context
1028
  * @return null
1029
  */
1030
+ public function debug($message, array $context = array())
1031
+ {
1032
+ return $this->log(SimpleLoggerLogLevels::DEBUG, $message, $context);
 
1033
  }
1034
 
1035
  /**
1039
  * @param array $context
1040
  * @return null
1041
  */
1042
+ public function debugMessage($message, array $context = array())
1043
+ {
1044
+ return $this->logByMessageKey(
1045
+ SimpleLoggerLogLevels::DEBUG,
1046
+ $message,
1047
+ $context
1048
+ );
1049
  }
1050
 
1051
  /**
1056
  * @param array $context The log context. Default empty array.
1057
  * @return class SimpleLogger instance
1058
  */
1059
+ public function log($level = 'info', $message = '', $context = array())
1060
+ {
1061
  global $wpdb;
1062
 
1063
  // Check that passed args are of correct types.
1064
+ if (!is_string($level) || !is_string($message)) {
1065
  return $this;
1066
  }
1067
 
1068
  // Context must be array, but can be passed as null and so on.
1069
+ if (!is_array($context)) {
1070
  $context = array();
1071
  }
1072
 
1073
  // Don't go on if message is empty.
1074
+ if (empty($message)) {
1075
  return $this;
1076
  }
1077
 
1081
  *
1082
  * @since 2.3.1
1083
  */
1084
+ $do_log = apply_filters(
1085
+ 'simple_history/log/do_log',
1086
+ true,
1087
+ $level,
1088
+ $message,
1089
+ $context,
1090
+ $this
1091
+ );
1092
+ if (false === $do_log) {
1093
  return $this;
1094
  }
1095
 
1106
  *
1107
  * @since 2.nn
1108
  */
1109
+ $do_log = apply_filters(
1110
+ "simple_history/log/do_log/{$this->slug}",
1111
+ true
1112
+ );
1113
+ if (false === $do_log) {
1114
  return $this;
1115
  }
1116
 
1124
  *
1125
  * @since 2.nn
1126
  */
1127
+ $message_key = isset($context['_message_key'])
1128
+ ? $context['_message_key']
1129
+ : null;
1130
+ $do_log = apply_filters(
1131
+ "simple_history/log/do_log/{$this->slug}/{$message_key}",
1132
+ true
1133
+ );
1134
+ if (false === $do_log) {
1135
  return $this;
1136
  }
1137
 
1138
  // Check if $message is a translated message, and if so then fetch original
1139
+ $sh_latest_translations =
1140
+ $this->simpleHistory->gettextLatestTranslations;
 
 
 
1141
 
1142
+ if (!empty($sh_latest_translations)) {
1143
+ if (isset($sh_latest_translations[$message])) {
1144
  // Translation of this phrase was found, so use original phrase instead of translated one
1145
  // Store textdomain since it's required to translate
1146
+ $context['_gettext_domain'] =
1147
+ $sh_latest_translations[$message]['domain'];
1148
 
1149
  // These are good to keep when debugging
1150
  // $context["_gettext_org_message"] = $sh_latest_translations[$message]["text"];
1151
  // $context["_gettext_translated_message"] = $sh_latest_translations[$message]["translation"];
1152
+ $message = $sh_latest_translations[$message]['text'];
1153
  }
1154
  }
1155
 
1163
  * @param array $context
1164
  * @param object SimpleLogger object
1165
  */
1166
+ apply_filters(
1167
+ 'simple_history/log_arguments',
1168
+ $level,
1169
+ $message,
1170
+ $context,
1171
+ $this
1172
+ );
1173
+ $context = apply_filters(
1174
+ 'simple_history/log_argument/context',
1175
+ $context,
1176
+ $level,
1177
+ $message,
1178
+ $this
1179
+ );
1180
+ $level = apply_filters(
1181
+ 'simple_history/log_argument/level',
1182
+ $level,
1183
+ $context,
1184
+ $message,
1185
+ $this
1186
+ );
1187
+ $message = apply_filters(
1188
+ 'simple_history/log_argument/message',
1189
+ $message,
1190
+ $level,
1191
+ $context,
1192
+ $this
1193
+ );
1194
 
1195
  /*
1196
  Store date as GMT date, i.e. not local date/time
1197
  * Some info here:
1198
  * http://www.skyverge.com/blog/down-the-rabbit-hole-wordpress-and-timezones/
1199
  */
1200
+ $localtime = current_time('mysql', 1);
1201
 
1202
  $db_table = $wpdb->prefix . SimpleHistory::DBTABLE;
1203
 
1208
  *
1209
  * @param string $db_table
1210
  */
1211
+ $db_table = apply_filters('simple_history/db_table', $db_table);
1212
 
1213
  $data = array(
1214
  'logger' => $this->slug,
1215
  'level' => $level,
1216
  'date' => $localtime,
1217
+ 'message' => $message
1218
  );
1219
 
1220
  // Allow date to be overriden.
1221
  // Date must be in format 'Y-m-d H:i:s'.
1222
+ if (isset($context['_date'])) {
1223
  $data['date'] = $context['_date'];
1224
+ unset($context['_date']);
1225
  }
1226
 
1227
  // Add occasions id.
1228
  $occasions_id = null;
1229
+ if (isset($context['_occasionsID'])) {
 
1230
  // Minimize risk of similar loggers logging same messages and such and resulting in same occasions id
1231
  // by always adding logger slug.
1232
  $occasions_data = array(
1233
  '_occasionsID' => $context['_occasionsID'],
1234
+ '_loggerSlug' => $this->slug
1235
  );
1236
+ $occasions_id = md5(json_encode($occasions_data));
1237
+ unset($context['_occasionsID']);
 
1238
  } else {
 
1239
  // No occasions id specified, create one bases on the data array.
1240
  $occasions_data = $data + $context;
1241
 
1242
  // Don't include date in context data.
1243
+ unset($occasions_data['date']);
 
 
1244
 
1245
+ $occasions_id = md5(json_encode($occasions_data));
1246
  }
1247
 
1248
  $data['occasionsID'] = $occasions_id;
1249
 
1250
  // Log initiator, defaults to current user if exists, or other if not user exist
1251
+ if (isset($context['_initiator'])) {
 
1252
  // Manually set in context
1253
  $data['initiator'] = $context['_initiator'];
1254
+ unset($context['_initiator']);
 
1255
  } else {
 
1256
  // No initiator set, try to determine
1257
  // Default to other
1258
  $data['initiator'] = SimpleLoggerLogInitiators::OTHER;
1259
 
1260
  // Check if user is responsible.
1261
+ if (function_exists('wp_get_current_user')) {
 
1262
  $current_user = wp_get_current_user();
1263
 
1264
+ if (isset($current_user->ID) && $current_user->ID) {
 
1265
  $data['initiator'] = SimpleLoggerLogInitiators::WP_USER;
1266
  $context['_user_id'] = $current_user->ID;
1267
  $context['_user_login'] = $current_user->user_login;
1268
  $context['_user_email'] = $current_user->user_email;
 
1269
  }
1270
  }
1271
 
1272
  // If cron then set WordPress as responsible
1273
+ if (defined('DOING_CRON') && DOING_CRON) {
 
1274
  // Seems to be wp cron running and doing this.
1275
  $data['initiator'] = SimpleLoggerLogInitiators::WORDPRESS;
1276
  $context['_wp_cron_running'] = true;
1278
  // To aid debugging we log the current filter and a list of all filters.
1279
  global $wp_current_filter;
1280
  $context['_wp_cron_current_filter'] = current_filter();
 
1281
  }
1282
 
1283
  // If running as CLI and WP_CLI_PHP_USED is set then it is WP CLI that is doing it
1287
  // - it is a specific user, but we don't know who
1288
  // - sounds like a special case, set initiator to wp_cli
1289
  // Can be used by plugins/themes to check if WP-CLI is running or not
1290
+ if (defined('WP_CLI') && WP_CLI) {
 
1291
  $data['initiator'] = SimpleLoggerLogInitiators::WP_CLI;
 
1292
  }
1293
+ } // End if().
1294
+
1295
+ // Detect XML-RPC calls and append to context, if not already there.
1296
+ if (
1297
+ defined('XMLRPC_REQUEST') &&
1298
+ XMLRPC_REQUEST &&
1299
+ !isset($context['_xmlrpc_request'])
1300
+ ) {
1301
  $context['_xmlrpc_request'] = true;
1302
+ }
1303
 
1304
+ // Detect REST calls and append to context, if not already there.
1305
+ $isRestApiRequest =
1306
+ (defined('REST_API_REQUEST') && REST_API_REQUEST) ||
1307
+ (defined('REST_REQUEST') && REST_REQUEST);
1308
+ if ($isRestApiRequest) {
1309
+ $context['_rest_api_request'] = true;
1310
  }
1311
 
1312
  // Trim message.
1313
+ $data['message'] = trim($data['message']);
1314
 
1315
  /**
1316
  * Filter data to be saved to db.
1319
  *
1320
  * @param array $data
1321
  */
1322
+ $data = apply_filters('simple_history/log_insert_data', $data);
1323
 
1324
  // Insert data into db.
1325
+ $result = $wpdb->insert($db_table, $data);
1326
 
1327
  $data_parent_row = null;
1328
 
1329
  // Only save context if able to store row.
1330
+ if (false === $result) {
 
1331
  $history_inserted_id = null;
 
1332
  } else {
 
1333
  $history_inserted_id = $wpdb->insert_id;
1334
 
1335
+ $db_table_contexts =
1336
+ $wpdb->prefix . SimpleHistory::DBTABLE_CONTEXTS;
1337
 
1338
  /**
1339
  * Filter table name for contexts.
1342
  *
1343
  * @param string $db_table_contexts
1344
  */
1345
+ $db_table_contexts = apply_filters(
1346
+ 'simple_history/logger_db_table_contexts',
1347
+ $db_table_contexts
1348
+ );
1349
 
1350
+ if (!is_array($context)) {
1351
  $context = array();
1352
  }
1353
 
1354
  // Append user id to context, if not already added.
1355
+ if (!isset($context['_user_id'])) {
 
1356
  // wp_get_current_user is not available early.
1357
  // http://codex.wordpress.org/Function_Reference/wp_get_current_user
1358
  // https://core.trac.wordpress.org/ticket/14024
1359
+ if (function_exists('wp_get_current_user')) {
 
1360
  $current_user = wp_get_current_user();
1361
 
1362
+ if (isset($current_user->ID) && $current_user->ID) {
1363
  $context['_user_id'] = $current_user->ID;
1364
  $context['_user_login'] = $current_user->user_login;
1365
  $context['_user_email'] = $current_user->user_email;
1368
  }
1369
 
1370
  // Add remote addr to context.
1371
+ if (!isset($context['_server_remote_addr'])) {
1372
+ $remote_addr = empty($_SERVER['REMOTE_ADDR'])
1373
+ ? ''
1374
+ : wp_unslash($_SERVER['REMOTE_ADDR']);
1375
 
1376
  /**
1377
  * Filter to control if ip addresses should be anonymized or not.
1381
  * @param bool true to anonymize ip address, false to keep original ip address.
1382
  * @return bool
1383
  */
1384
+ $anonymize_ip_address = apply_filters(
1385
+ 'simple_history/privacy/anonymize_ip_address',
1386
+ true
1387
+ );
1388
+
1389
+ if (
1390
+ $anonymize_ip_address &&
1391
+ function_exists('wp_privacy_anonymize_ip')
1392
+ ) {
1393
+ $remote_addr = wp_privacy_anonymize_ip($remote_addr);
1394
  }
1395
 
1396
  $context['_server_remote_addr'] = $remote_addr;
1406
  // http://blackbe.lt/advanced-method-to-obtain-the-client-ip-in-php/
1407
  $ip_keys = $this->get_ip_number_header_keys();
1408
 
1409
+ foreach ($ip_keys as $key) {
1410
+ if (array_key_exists($key, $_SERVER) === true) {
 
 
1411
  // Loop through all IPs.
1412
  $ip_loop_num = 0;
1413
+ foreach (explode(',', $_SERVER[$key]) as $ip) {
 
1414
  // trim for safety measures.
1415
+ $ip = trim($ip);
1416
 
1417
  // attempt to validate IP.
1418
+ if ($this->validate_ip($ip)) {
 
1419
  // valid, add to context, with loop index appended so we can store many IPs.
1420
+ $key_lower = strtolower($key);
1421
 
1422
+ if (
1423
+ $anonymize_ip_address &&
1424
+ function_exists('wp_privacy_anonymize_ip')
1425
+ ) {
1426
+ $ip = wp_privacy_anonymize_ip($ip);
1427
  }
1428
 
1429
+ $context[
1430
+ "_server_{$key_lower}_{$ip_loop_num}"
1431
+ ] = $ip;
1432
  }
1433
 
1434
  $ip_loop_num++;
 
1435
  }
1436
  }
1437
  }
1438
+ } // End if().
1439
 
1440
  // Append http referer.
1441
+ if (
1442
+ !isset($context['_server_http_referer']) &&
1443
+ isset($_SERVER['HTTP_REFERER'])
1444
+ ) {
1445
  $context['_server_http_referer'] = $_SERVER['HTTP_REFERER'];
1446
  }
1447
 
1454
  * @param array $data Array with data used for parent row.
1455
  * @param array $this Reference to this logger instance.
1456
  */
1457
+ $context = apply_filters(
1458
+ 'simple_history/log_insert_context',
1459
+ $context,
1460
+ $data,
1461
+ $this
1462
+ );
1463
  $data_parent_row = $data;
1464
 
1465
  // Insert all context values into db.
1466
+ $this->append_context($history_inserted_id, $context);
1467
+ } // End if().
1468
 
1469
  $this->lastInsertID = $history_inserted_id;
1470
  $this->lastInsertContext = $context;
1471
 
1472
+ $this->simpleHistory->get_cache_incrementor(true);
1473
 
1474
  /**
1475
  * Action that is called after an event has been logged
1480
  * @param array $data Array with data used for parent row.
1481
  * @param array $this Reference to this logger instance
1482
  */
1483
+ do_action(
1484
+ 'simple_history/log/inserted',
1485
+ $context,
1486
+ $data_parent_row,
1487
+ $this
1488
+ );
1489
 
1490
  // Return $this so we can chain methods.
1491
  return $this;
 
1492
  } // log
1493
 
1494
  /**
1498
  * @param array $context Context to append to existing context for the row.
1499
  * @return bool True if context was added, false if not (beacuse row_id or context is empty).
1500
  */
1501
+ public function append_context($history_id, $context)
1502
+ {
1503
+ if (empty($history_id) || empty($context)) {
1504
  return false;
1505
  }
1506
 
1508
 
1509
  $db_table_contexts = $wpdb->prefix . SimpleHistory::DBTABLE_CONTEXTS;
1510
 
1511
+ foreach ($context as $key => $value) {
 
1512
  // Everything except strings should be json_encoded, ie. arrays and objects.
1513
+ if (!is_string($value)) {
1514
+ $value = simpleHistory::json_encode($value);
1515
  }
1516
 
1517
  $data = array(
1518
  'history_id' => $history_id,
1519
  'key' => $key,
1520
+ 'value' => $value
1521
  );
1522
 
1523
+ $result = $wpdb->insert($db_table_contexts, $data);
1524
  }
1525
 
1526
  return true;
1531
  *
1532
  * @since 2.0.29
1533
  */
1534
+ public function get_ip_number_header_keys()
1535
+ {
1536
  $arr = array(
1537
  'HTTP_CLIENT_IP',
1538
  'HTTP_X_FORWARDED_FOR',
1539
  'HTTP_X_FORWARDED',
1540
  'HTTP_X_CLUSTER_CLIENT_IP',
1541
  'HTTP_FORWARDED_FOR',
1542
+ 'HTTP_FORWARDED'
1543
  );
1544
 
1545
  return $arr;
 
1546
  }
1547
 
1548
  /**
1552
  * @param array $row Row with info.
1553
  * @return array Headers
1554
  */
1555
+ function get_event_ip_number_headers($row)
1556
+ {
1557
  $ip_keys = $this->get_ip_number_header_keys();
1558
  $arr_found_additional_ip_headers = array();
1559
  $context = $row->context;
1560
 
1561
+ foreach ($ip_keys as $one_ip_header_key) {
1562
+ $one_ip_header_key_lower = strtolower($one_ip_header_key);
 
 
 
1563
 
1564
+ foreach ($context as $context_key => $context_val) {
1565
  // $key_check_for = "_server_" . strtolower($one_ip_header_key) . "_0";
1566
+ $match = preg_match(
1567
+ "/^_server_{$one_ip_header_key_lower}_[\d+]/",
1568
+ $context_key,
1569
+ $matches
1570
+ );
1571
+ if ($match) {
1572
+ $arr_found_additional_ip_headers[
1573
+ $context_key
1574
+ ] = $context_val;
1575
  }
1576
  }
1577
  } // End foreach().
1578
 
1579
  return $arr_found_additional_ip_headers;
 
1580
  }
1581
 
1582
  /**
1586
  * @param string $ip IP number.
1587
  * @return bool
1588
  */
1589
+ function validate_ip($ip)
1590
+ {
1591
+ if (
1592
+ filter_var(
1593
+ $ip,
1594
+ FILTER_VALIDATE_IP,
1595
+ FILTER_FLAG_IPV4 |
1596
+ FILTER_FLAG_NO_PRIV_RANGE |
1597
+ FILTER_FLAG_NO_RES_RANGE
1598
+ ) === false
1599
+ ) {
1600
  return false;
1601
  }
1602
 
1603
  return true;
 
1604
  }
1605
 
1606
  /**
1608
  * The CSS that you output will only be outputed
1609
  * on pages where Simple History is used.
1610
  */
1611
+ function adminCSS()
1612
+ {
1613
  /*
1614
  ?>
1615
  <style>
1626
  * The JS that you output will only be outputed
1627
  * on pages where Simple History is used.
1628
  */
1629
+ function adminJS()
1630
+ {
1631
  /*
1632
  ?>
1633
  <script>
1636
  <?php
1637
  */
1638
  }
 
1639
  }
1640
 
1641
  /**
1642
  * Describes log initiator, i.e. who caused to log event to happend
1643
  */
1644
+ class SimpleLoggerLogInitiators
1645
+ {
1646
  // A wordpress user that at the log event created did exist in the wp database
1647
  // May have been deleted when the log is viewed.
1648
  const WP_USER = 'wp_user';
1669
  * More may be added later on if needed
1670
  * Note: not in use at the moment
1671
  */
1672
+ class SimpleLoggerLogTypes
1673
+ {
1674
  const CREATE = 'create';
1675
  const READ = 'read';
1676
  const UPDATE = 'update';
1681
  /**
1682
  * Describes log levels
1683
  */
1684
+ class SimpleLoggerLogLevels
1685
+ {
1686
  const EMERGENCY = 'emergency';
1687
  const ALERT = 'alert';
1688
  const CRITICAL = 'critical';
loggers/SimplePluginLogger.php CHANGED
@@ -336,11 +336,11 @@ class SimplePluginLogger extends SimpleLogger {
336
 
337
  $response_body = wp_remote_retrieve_body( $response );
338
 
339
- $repo_info = sprintf(
340
- __( '<p>Viewing <code>readme</code> from repository <code><a target="_blank" href="%1$s">%2$s</a></code>.</p>', 'simple-history' ),
341
  esc_url( $repo ),
342
  esc_html( $repo )
343
- );
344
 
345
  $github_markdown_css_path = SIMPLE_HISTORY_PATH . '/css/github-markdown.css';
346
 
336
 
337
  $response_body = wp_remote_retrieve_body( $response );
338
 
339
+ $repo_info = '<p>' . sprintf(
340
+ __( 'Viewing <code>readme</code> from repository <code><a target="_blank" href="%1$s">%2$s</a></code>.', 'simple-history' ),
341
  esc_url( $repo ),
342
  esc_html( $repo )
343
+ ) . '</p>';
344
 
345
  $github_markdown_css_path = SIMPLE_HISTORY_PATH . '/css/github-markdown.css';
346
 
loggers/SimplePostLogger.php CHANGED
@@ -1,36 +1,159 @@
1
  <?php
2
 
3
- defined( 'ABSPATH' ) or die();
4
 
5
  /**
6
- * Logs changes to posts and pages, including custom post types
 
 
 
 
 
 
 
7
  */
8
- class SimplePostLogger extends SimpleLogger {
9
 
10
- // The logger slug. Defaulting to the class name is nice and logical I think
 
 
 
 
 
11
  public $slug = __CLASS__;
12
 
13
- // Array that will contain previous post data, before data is updated
 
 
 
14
  private $old_post_data = array();
15
 
16
- public function loaded() {
17
-
18
- add_action( 'admin_action_editpost', array( $this, 'on_admin_action_editpost' ) );
19
- add_action( 'transition_post_status', array( $this, 'on_transition_post_status' ), 10, 3 );
20
- add_action( 'delete_post', array( $this, 'on_delete_post' ) );
21
- add_action( 'untrash_post', array( $this, 'on_untrash_post' ) );
 
 
 
 
 
 
 
 
22
 
23
  $this->add_xml_rpc_hooks();
 
 
 
 
 
 
 
 
 
24
 
25
- add_filter( 'simple_history/rss_item_link', array( $this, 'filter_rss_item_link' ), 10, 2 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
 
 
 
27
  }
28
 
29
  /**
30
- * Filters to XML RPC calls needs to be added early, admin_init is to late
 
 
 
 
 
 
 
 
31
  */
32
- function add_xml_rpc_hooks() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  // Debug: log all XML-RPC requests
35
  /*
36
  add_action("xmlrpc_call", function($method) {
@@ -38,151 +161,214 @@ class SimplePostLogger extends SimpleLogger {
38
  }, 10, 1);
39
  */
40
 
41
- add_action( 'xmlrpc_call_success_blogger_newPost', array( $this, 'on_xmlrpc_newPost' ), 10, 2 );
42
- add_action( 'xmlrpc_call_success_mw_newPost', array( $this, 'on_xmlrpc_newPost' ), 10,2 );
43
-
44
- add_action( 'xmlrpc_call_success_blogger_editPost', array( $this, 'on_xmlrpc_editPost' ), 10, 2 );
45
- add_action( 'xmlrpc_call_success_mw_editPost', array( $this, 'on_xmlrpc_editPost' ), 10, 2 );
 
 
 
 
 
 
 
46
 
47
- add_action( 'xmlrpc_call_success_blogger_deletePost', array( $this, 'on_xmlrpc_deletePost' ), 10, 2 );
48
- add_action( 'xmlrpc_call_success_wp_deletePage', array( $this, 'on_xmlrpc_deletePost' ), 10, 2 );
 
 
 
 
 
 
 
 
 
 
49
 
50
- add_action( 'xmlrpc_call', array( $this, 'on_xmlrpc_call' ), 10, 1 );
 
 
 
 
 
 
 
 
 
 
 
51
 
 
52
  }
53
 
54
- function on_xmlrpc_call( $method ) {
55
-
56
- $arr_methods_to_act_on = array(
57
- 'wp.deletePost'
58
- );
59
 
60
  $raw_post_data = null;
61
  $message = null;
62
  $context = array();
63
 
64
- if ( in_array( $method, $arr_methods_to_act_on ) ) {
65
-
66
  // Setup common stuff
67
- $raw_post_data = file_get_contents( 'php://input' );
68
- $context['wp.deletePost.xmldata'] = $this->simpleHistory->json_encode( $raw_post_data );
69
- $message = new IXR_Message( $raw_post_data );
 
 
70
 
71
- if ( ! $message->parse() ) {
72
  return;
73
  }
74
 
75
- $context['wp.deletePost.xmlrpc_message'] = $this->simpleHistory->json_encode( $message );
76
- $context['wp.deletePost.xmlrpc_message.messageType'] = $this->simpleHistory->json_encode( $message->messageType );
77
- $context['wp.deletePost.xmlrpc_message.methodName'] = $this->simpleHistory->json_encode( $message->methodName );
78
- $context['wp.deletePost.xmlrpc_message.messageParams'] = $this->simpleHistory->json_encode( $message->params );
 
 
 
 
 
 
 
 
79
 
80
  // Actions for delete post
81
- if ( 'wp.deletePost' == $method ) {
82
-
83
  // 4 params, where the last is the post id
84
- if ( ! isset( $message->params[3] ) ) {
85
  return;
86
  }
87
 
88
  $post_ID = $message->params[3];
89
 
90
- $post = get_post( $post_ID );
91
 
92
  $context = array(
93
  'post_id' => $post->ID,
94
- 'post_type' => get_post_type( $post ),
95
- 'post_title' => get_the_title( $post ),
96
  );
97
 
98
- $this->infoMessage( 'post_trashed', $context );
99
-
100
  }
101
- }// End if().
102
-
103
  }
104
 
105
-
106
  /**
107
  * Get array with information about this logger
108
  *
109
  * @return array
110
  */
111
- function getInfo() {
112
-
113
  $arr_info = array(
114
  'name' => 'Post Logger',
115
- 'description' => 'Logs the creation and modification of posts and pages',
 
116
  'capability' => 'edit_pages',
117
  'messages' => array(
118
- 'post_created' => __( 'Created {post_type} "{post_title}"', 'simple-history' ),
119
- 'post_updated' => __( 'Updated {post_type} "{post_title}"', 'simple-history' ),
120
- 'post_restored' => __( 'Restored {post_type} "{post_title}" from trash', 'simple-history' ),
121
- 'post_deleted' => __( 'Deleted {post_type} "{post_title}"', 'simple-history' ),
122
- 'post_trashed' => __( 'Moved {post_type} "{post_title}" to the trash', 'simple-history' ),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
123
  ),
124
  'labels' => array(
125
  'search' => array(
126
- 'label' => _x( 'Posts & Pages', 'Post logger: search', 'simple-history' ),
127
- 'label_all' => _x( 'All posts & pages activity', 'Post logger: search', 'simple-history' ),
128
- 'options' => array(
129
- _x( 'Posts created', 'Post logger: search', 'simple-history' ) => array(
130
- 'post_created'
131
- ),
132
- _x( 'Posts updated', 'Post logger: search', 'simple-history' ) => array(
133
- 'post_updated'
134
- ),
135
- _x( 'Posts trashed', 'Post logger: search', 'simple-history' ) => array(
136
- 'post_trashed'
137
- ),
138
- _x( 'Posts deleted', 'Post logger: search', 'simple-history' ) => array(
139
- 'post_deleted'
140
- ),
141
- _x( 'Posts restored', 'Post logger: search', 'simple-history' ) => array(
142
- 'post_restored'
143
- ),
144
  ),
145
- ),// end search array
146
- ),// end labels
147
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  );
149
 
150
  return $arr_info;
151
-
152
  }
153
 
154
  /**
155
  * Get and store old info about a post that is being edited.
156
  * Needed to later compare old data with new data, to detect differences.
157
- * This function is called on edit screen, but before post edits are saved
158
  *
159
  * Can't use the regular filters like "pre_post_update" because custom fields are already written by then.
160
  *
161
  * @since 2.0.29
162
  */
163
- function on_admin_action_editpost() {
 
 
164
 
165
- $post_ID = isset( $_POST['post_ID'] ) ? (int) $_POST['post_ID'] : 0;
166
-
167
- if ( ! $post_ID ) {
168
  return;
169
  }
170
 
171
- if ( ! current_user_can( 'edit_post', $post_ID ) ) {
172
  return;
173
- };
174
 
175
- $prev_post_data = get_post( $post_ID );
176
 
177
  if (is_wp_error($prev_post_data)) {
178
  return;
179
  }
180
 
181
  $this->old_post_data[$post_ID] = array(
182
- "post_data" => $prev_post_data,
183
- "post_meta" => get_post_custom( $post_ID )
184
  );
185
-
186
  }
187
 
188
  /**
@@ -193,18 +379,17 @@ class SimplePostLogger extends SimpleLogger {
193
  * @param int $post_ID ID of the deleted post.
194
  * @param array $args An array of arguments to delete the post.
195
  */
196
- function on_xmlrpc_deletePost( $post_ID, $args ) {
197
-
198
- $post = get_post( $post_ID );
199
 
200
  $context = array(
201
  'post_id' => $post->ID,
202
- 'post_type' => get_post_type( $post ),
203
- 'post_title' => get_the_title( $post ),
204
  );
205
 
206
- $this->infoMessage( 'post_deleted', $context );
207
-
208
  }
209
 
210
  /**
@@ -215,18 +400,17 @@ class SimplePostLogger extends SimpleLogger {
215
  * @param int $post_ID ID of the updated post.
216
  * @param array $args An array of arguments for the post to edit.
217
  */
218
- function on_xmlrpc_editPost( $post_ID, $args ) {
219
-
220
- $post = get_post( $post_ID );
221
 
222
  $context = array(
223
  'post_id' => $post->ID,
224
- 'post_type' => get_post_type( $post ),
225
- 'post_title' => get_the_title( $post ),
226
  );
227
 
228
- $this->infoMessage( 'post_updated', $context );
229
-
230
  }
231
 
232
  /**
@@ -237,40 +421,36 @@ class SimplePostLogger extends SimpleLogger {
237
  * @param int $post_ID ID of the new post.
238
  * @param array $args An array of new post arguments.
239
  */
240
- function on_xmlrpc_newPost( $post_ID, $args ) {
241
-
242
- $post = get_post( $post_ID );
243
 
244
  $context = array(
245
  'post_id' => $post->ID,
246
- 'post_type' => get_post_type( $post ),
247
- 'post_title' => get_the_title( $post ),
248
  );
249
 
250
- $this->infoMessage( 'post_created', $context );
251
-
252
  }
253
 
254
  /**
255
  * Called when a post is restored from the trash
 
256
  */
257
- function on_untrash_post( $post_id ) {
258
-
259
- $post = get_post( $post_id );
260
 
261
- if ( ! $this->ok_to_log_post_posttype( $post ) ) {
262
  return;
263
  }
264
 
265
- $this->infoMessage(
266
- 'post_restored',
267
- array(
268
- 'post_id' => $post_id,
269
- 'post_type' => get_post_type( $post ),
270
- 'post_title' => get_the_title( $post ),
271
- )
272
- );
273
-
274
  }
275
 
276
  /**
@@ -278,21 +458,24 @@ class SimplePostLogger extends SimpleLogger {
278
  *
279
  * @param int $postid Post ID.
280
  */
281
- function on_delete_post( $post_id ) {
282
-
283
- $post = get_post( $post_id );
284
 
285
- if ( wp_is_post_revision( $post_id ) ) {
286
  return;
287
  }
288
 
289
- if ( $post->post_status === 'auto-draft' || $post->post_status === 'inherit' ) {
 
 
 
290
  return;
291
  }
292
 
293
  $ok_to_log = true;
294
 
295
- if ( ! $this->ok_to_log_post_posttype( $post ) ) {
296
  $ok_to_log = false;
297
  }
298
 
@@ -306,9 +489,13 @@ class SimplePostLogger extends SimpleLogger {
306
  *
307
  * @since 2.21
308
  */
309
- $ok_to_log = apply_filters( 'simple_history/post_logger/post_deleted/ok_to_log', $ok_to_log, $post_id );
 
 
 
 
310
 
311
- if ( ! $ok_to_log ) {
312
  return;
313
  }
314
 
@@ -325,27 +512,26 @@ class SimplePostLogger extends SimpleLogger {
325
  ]
326
  */
327
  global $wp_current_filter;
328
- if ( isset( $wp_current_filter ) && is_array( $wp_current_filter ) ) {
329
- if ( in_array( 'wp_scheduled_delete', $wp_current_filter, true ) ) {
330
  return;
331
  }
332
  }
333
 
334
- $this->infoMessage(
335
- 'post_deleted',
336
- array(
337
- 'post_id' => $post_id,
338
- 'post_type' => get_post_type( $post ),
339
- 'post_title' => get_the_title( $post ),
340
- )
341
- );
342
-
343
  }
344
 
345
  /**
346
  * Get an array of post types that should not be logged by this logger.
 
 
347
  */
348
- public function get_skip_posttypes() {
 
349
  $skip_posttypes = array(
350
  // Don't log nav_menu_updates.
351
  'nav_menu_item',
@@ -354,7 +540,7 @@ class SimplePostLogger extends SimpleLogger {
354
  'jetpack_migration',
355
  'jp_sitemap',
356
  'jp_img_sitemap',
357
- 'jp_sitemap_master',
358
  );
359
 
360
  /**
@@ -362,7 +548,10 @@ class SimplePostLogger extends SimpleLogger {
362
  *
363
  * @since 2.18
364
  */
365
- $skip_posttypes = apply_filters( 'simple_history/post_logger/skip_posttypes', $skip_posttypes );
 
 
 
366
 
367
  return $skip_posttypes;
368
  }
@@ -374,11 +563,12 @@ class SimplePostLogger extends SimpleLogger {
374
  *
375
  * @return bool
376
  */
377
- public function ok_to_log_post_posttype( $post ) {
 
378
  $ok_to_log = true;
379
  $skip_posttypes = $this->get_skip_posttypes();
380
 
381
- if ( in_array( get_post_type( $post ), $skip_posttypes, true ) ) {
382
  $ok_to_log = false;
383
  }
384
 
@@ -386,34 +576,100 @@ class SimplePostLogger extends SimpleLogger {
386
  }
387
 
388
  /**
389
- * Fired when a post has changed status
390
- * Only run in certain cases,
391
- * because when always enabled it catches a lots of edits made by plugins during cron jobs etc,
392
- * which by definition is not wrong, but perhaps not wanted/annoying
393
- */
394
- function on_transition_post_status( $new_status, $old_status, $post ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
395
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
396
  $ok_to_log = true;
397
 
398
- // calls from the WordPress ios app/jetpack comes from non-admin-area
399
  // i.e. is_admin() is false
400
- // so don't log when outside admin area
401
- if ( ! is_admin() ) {
402
  $ok_to_log = false;
403
  }
404
 
405
- // except when calls are from/for jetpack/wordpress apps
406
- // seems to be jetpack/app request when $_GET["for"] == "jetpack
407
- if ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST && isset( $_GET['for'] ) && $_GET['for'] === 'jetpack' ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
408
  $ok_to_log = true;
409
  }
410
 
411
  // Don't log revisions.
412
- if ( wp_is_post_revision( $post ) ) {
413
  $ok_to_log = false;
414
  }
415
 
416
- if ( ! $this->ok_to_log_post_posttype( $post ) ) {
 
 
 
 
 
417
  $ok_to_log = false;
418
  }
419
 
@@ -429,9 +685,15 @@ class SimplePostLogger extends SimpleLogger {
429
  *
430
  * @since 2.21
431
  */
432
- $ok_to_log = apply_filters( 'simple_history/post_logger/post_updated/ok_to_log', $ok_to_log, $new_status, $old_status, $post );
 
 
 
 
 
 
433
 
434
- if ( ! $ok_to_log ) {
435
  return;
436
  }
437
 
@@ -449,45 +711,41 @@ class SimplePostLogger extends SimpleLogger {
449
  */
450
  $context = array(
451
  'post_id' => $post->ID,
452
- 'post_type' => get_post_type( $post ),
453
- 'post_title' => get_the_title( $post ),
454
  );
455
 
456
- if ( $old_status == 'auto-draft' && ($new_status != 'auto-draft' && $new_status != 'inherit') ) {
457
-
 
 
458
  // Post created
459
- $this->infoMessage( 'post_created', $context );
460
-
461
- } elseif ( $new_status == 'auto-draft' || ($old_status == 'new' && $new_status == 'inherit') ) {
462
-
 
463
  // Post was automagically saved by WordPress
464
  return;
465
-
466
- } elseif ( $new_status == 'trash' ) {
467
-
468
  // Post trashed
469
- $this->infoMessage( 'post_trashed', $context );
470
-
471
  } else {
 
472
 
473
- // Post updated
474
- // Also add diff between previod saved data and new data
475
- if ( isset( $this->old_post_data[ $post->ID ] ) ) {
476
-
477
- $old_post_data = $this->old_post_data[ $post->ID ];
478
-
479
- $new_post_data = array(
480
- 'post_data' => $post,
481
- 'post_meta' => get_post_custom( $post->ID ),
482
- );
483
-
484
  // Now we have both old and new post data, including custom fields, in the same format
485
  // So let's compare!
486
- $context = $this->add_post_data_diff_to_context( $context, $old_post_data, $new_post_data );
487
-
 
 
 
488
  }
489
 
490
- $context['_occasionsID'] = __CLASS__ . '/' . __FUNCTION__ . "/post_updated/{$post->ID}";
 
491
 
492
  /**
493
  * Modify the context saved.
@@ -495,12 +753,58 @@ class SimplePostLogger extends SimpleLogger {
495
  * @param array $context
496
  * @param WP_Post $post
497
  */
498
- $context = apply_filters( 'simple_history/post_logger/post_updated/context', $context, $post );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
499
 
500
- $this->infoMessage( "post_updated", $context );
501
 
502
- }// End if().
 
503
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
504
  }
505
 
506
  /**
@@ -509,16 +813,19 @@ class SimplePostLogger extends SimpleLogger {
509
  * Since 2.0.29
510
  *
511
  * To detect
512
- * - categories
513
- * - tags
514
  *
515
  * @param array $context Array with context.
516
  * @param array $old_post_data Old/prev post data.
517
  * @param array $new_post_data New post data.
518
  * @return array $context with diff data added.
519
  */
520
- function add_post_data_diff_to_context( $context, $old_post_data, $new_post_data ) {
521
-
 
 
 
522
  $old_data = $old_post_data['post_data'];
523
  $new_data = $new_post_data['post_data'];
524
 
@@ -537,42 +844,50 @@ class SimplePostLogger extends SimpleLogger {
537
  'comment_status',
538
  'ping_status',
539
  'post_parent', // only id, need to get context for that, like name of parent at least?
540
- 'post_author', // only id, need to get context for that, like name, login, email at least?
541
  );
542
 
543
- foreach ( $arr_keys_to_diff as $key ) {
544
-
545
- if ( isset( $old_data->$key ) && isset( $new_data->$key ) ) {
546
- $post_data_diff = $this->add_diff( $post_data_diff, $key, $old_data->$key, $new_data->$key );
 
 
 
 
547
  }
548
  }
549
 
550
  // If changes where detected.
551
- if ( $post_data_diff ) {
552
-
553
  // Save at least 2 values for each detected value change, i.e. the old value and the new value.
554
- foreach ( $post_data_diff as $diff_key => $diff_values ) {
555
-
556
- $context[ "post_prev_{$diff_key}" ] = $diff_values['old'];
557
- $context[ "post_new_{$diff_key}" ] = $diff_values['new'];
558
 
559
  // If post_author then get more author info,
560
  // because just a user ID does not get us far.
561
- if ( 'post_author' == $diff_key ) {
562
-
563
- $old_author_user = get_userdata( (int) $diff_values['old'] );
564
- $new_author_user = get_userdata( (int) $diff_values['new'] );
565
-
566
- if ( is_a( $old_author_user, 'WP_User' ) && is_a( $new_author_user, 'WP_User' ) ) {
567
-
568
- $context[ "post_prev_{$diff_key}/user_login" ] = $old_author_user->user_login;
569
- $context[ "post_prev_{$diff_key}/user_email" ] = $old_author_user->user_email;
570
- $context[ "post_prev_{$diff_key}/display_name" ] = $old_author_user->display_name;
571
-
572
- $context[ "post_new_{$diff_key}/user_login" ] = $new_author_user->user_login;
573
- $context[ "post_new_{$diff_key}/user_email" ] = $new_author_user->user_email;
574
- $context[ "post_new_{$diff_key}/display_name" ] = $new_author_user->display_name;
575
-
 
 
 
 
 
 
576
  }
577
  }
578
  }
@@ -585,62 +900,79 @@ class SimplePostLogger extends SimpleLogger {
585
  '_edit_last',
586
  '_post_restored_from',
587
  '_wp_page_template',
588
- '_thumbnail_id',
589
  );
590
 
591
  $meta_changes = array(
592
  'added' => array(),
593
  'removed' => array(),
594
- 'changed' => array(),
595
  );
596
 
597
- $old_meta = $old_post_data['post_meta'];
598
- $new_meta = $new_post_data['post_meta'];
 
 
 
 
599
 
600
  // Add post featured thumb data.
601
- $context = $this->add_post_thumb_diff( $context, $old_meta, $new_meta );
602
 
603
  // Page template is stored in _wp_page_template.
604
- if ( isset( $old_meta['_wp_page_template'][0] ) && isset( $new_meta['_wp_page_template'][0] ) ) {
 
 
 
605
  /*
606
  Var is string with length 7: default
607
  Var is string with length 20: template-builder.php
608
  */
609
 
610
- if ( $old_meta['_wp_page_template'][0] !== $new_meta['_wp_page_template'][0] ) {
 
 
 
611
  // Prev page template is different from new page template,
612
  // store template php file name.
613
- $context['post_prev_page_template'] = $old_meta['_wp_page_template'][0];
614
- $context['post_new_page_template'] = $new_meta['_wp_page_template'][0];
 
 
615
 
616
  $theme_templates = (array) $this->get_theme_templates();
617
 
618
- if ( isset( $theme_templates[ $context['post_prev_page_template'] ] ) ) {
619
- $context['post_prev_page_template_name'] = $theme_templates[ $context['post_prev_page_template'] ];
 
 
 
620
  }
621
 
622
- if ( isset( $theme_templates[ $context['post_new_page_template'] ] ) ) {
623
- $context['post_new_page_template_name'] = $theme_templates[ $context['post_new_page_template'] ];
 
 
 
624
  }
625
  }
626
  }
627
 
628
  // Remove fields that we have checked already and other that should be ignored.
629
- foreach ( $arr_meta_keys_to_ignore as $key_to_ignore ) {
630
- unset( $old_meta[ $key_to_ignore ] );
631
- unset( $new_meta[ $key_to_ignore ] );
632
  }
633
 
634
  // Look for added custom fields.
635
- foreach ( $new_meta as $meta_key => $meta_value ) {
636
-
637
- if ( ! isset( $old_meta[ $meta_key ] ) ) {
638
- $meta_changes['added'][ $meta_key ] = true;
639
  }
640
  }
641
 
642
- // Look for removed meta
643
- // Does not work, if user clicks "delete" in edit screen then meta is removed using ajax
644
  /*
645
  foreach ( $old_meta as $meta_key => $meta_value ) {
646
 
@@ -652,30 +984,92 @@ class SimplePostLogger extends SimpleLogger {
652
  */
653
 
654
  // Look for changed meta.
655
- foreach ( $old_meta as $meta_key => $meta_value ) {
656
-
657
- if ( isset( $new_meta[ $meta_key ] ) ) {
658
-
659
- if ( json_encode( $old_meta[ $meta_key ] ) != json_encode( $new_meta[ $meta_key ] ) ) {
660
- $meta_changes['changed'][ $meta_key ] = true;
 
661
  }
662
  }
663
  }
664
 
665
- if ( $meta_changes['added'] ) {
666
- $context['post_meta_added'] = count( $meta_changes['added'] );
667
  }
668
 
669
- if ( $meta_changes['removed'] ) {
670
- $context['post_meta_removed'] = count( $meta_changes['removed'] );
671
  }
672
 
673
- if ( $meta_changes['changed'] ) {
674
- $context['post_meta_changed'] = count( $meta_changes['changed'] );
675
  }
676
 
677
- return $context;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
678
 
 
679
  }
680
 
681
  /**
@@ -685,22 +1079,27 @@ class SimplePostLogger extends SimpleLogger {
685
  *
686
  * @since 2.0.29
687
  */
688
- function get_theme_templates() {
689
-
690
  $theme = wp_get_theme();
691
  $page_templates = array();
692
 
693
- $files = (array) $theme->get_files( 'php', 1 );
694
 
695
- foreach ( $files as $file => $full_path ) {
696
- if ( ! preg_match( '|Template Name:(.*)$|mi', file_get_contents( $full_path ), $header ) ) {
 
 
 
 
 
 
697
  continue;
698
  }
699
- $page_templates[ $file ] = _cleanup_header_comment( $header[1] );
700
  }
701
 
702
  return $page_templates;
703
-
704
  }
705
 
706
  /**
@@ -714,19 +1113,16 @@ class SimplePostLogger extends SimpleLogger {
714
  * @param mixed $new_value New value.
715
  * @return array
716
  */
717
- function add_diff( $post_data_diff, $key, $old_value, $new_value ) {
718
-
719
- if ( $old_value != $new_value ) {
720
-
721
- $post_data_diff[ $key ] = array(
722
  'old' => $old_value,
723
- 'new' => $new_value,
724
  );
725
-
726
  }
727
 
728
  return $post_data_diff;
729
-
730
  }
731
 
732
  /**
@@ -734,10 +1130,10 @@ class SimplePostLogger extends SimpleLogger {
734
  *
735
  * @param array $row Row data.
736
  */
737
- public function getLogRowPlainTextOutput( $row ) {
738
-
739
  $context = $row->context;
740
- $post_id = isset( $context['post_id'] ) ? $context['post_id'] : 0;
741
 
742
  // Default to original log message.
743
  $message = $row->message;
@@ -745,52 +1141,61 @@ class SimplePostLogger extends SimpleLogger {
745
  // Check if post still is available.
746
  // It will return a WP_Post Object if post still is in system.
747
  // If post is deleted from trash (not just moved there), then null is returned.
748
- $post = get_post( $post_id );
749
- $post_is_available = is_a( $post, 'WP_Post' );
750
 
751
- $message_key = isset( $context['_message_key'] ) ? $context['_message_key'] : null;
 
 
752
 
753
  // Try to get singular name.
754
- $post_type = isset( $context['post_type'] ) ? $context['post_type'] : '';
755
- $post_type_obj = get_post_type_object( $post_type );
756
- if ( ! is_null( $post_type_obj ) ) {
757
-
758
- if ( ! empty( $post_type_obj->labels->singular_name ) ) {
759
- $context['post_type'] = strtolower( $post_type_obj->labels->singular_name );
 
760
  }
761
  }
762
 
763
- $context['edit_link'] = get_edit_post_link( $post_id );
764
 
765
  // If post is not available any longer then we can't link to it, so keep plain message then.
766
  // Also keep plain format if user is not allowed to edit post (edit link is empty).
767
- if ( $post_is_available && $context['edit_link'] ) {
768
-
769
- if ( 'post_updated' == $message_key ) {
770
-
771
- $message = __( 'Updated {post_type} <a href="{edit_link}">"{post_title}"</a>', 'simple-history' );
772
-
773
- } elseif ( 'post_deleted' == $message_key ) {
774
-
775
- $message = __( 'Deleted {post_type} "{post_title}"', 'simple-history' );
776
-
777
- } elseif ( 'post_created' == $message_key ) {
778
-
779
- $message = __( 'Created {post_type} <a href="{edit_link}">"{post_title}"</a>', 'simple-history' );
780
-
781
- } elseif ( 'post_trashed' == $message_key ) {
782
-
 
783
  // While in trash we can still get actions to delete or restore if we follow the edit link.
784
- $message = __( 'Moved {post_type} <a href="{edit_link}">"{post_title}"</a> to the trash', 'simple-history' );
785
-
 
 
786
  }
787
  } // End if().
788
 
789
- $context['post_type'] = isset( $context['post_type'] ) ? esc_html( $context['post_type'] ) : '';
790
- $context['post_title'] = isset( $context['post_title'] ) ? esc_html( $context['post_title'] ) : '';
791
-
792
- return $this->interpolate( $message, $context, $row );
 
 
793
 
 
794
  }
795
 
796
  /**
@@ -798,77 +1203,70 @@ class SimplePostLogger extends SimpleLogger {
798
  *
799
  * @param array $row Row data.
800
  */
801
- public function getLogRowDetailsOutput( $row ) {
802
-
803
  $context = $row->context;
804
  $message_key = $context['_message_key'];
805
- $post_id = isset( $context['post_id'] ) ? $context['post_id'] : 0;
806
 
807
  $out = '';
808
 
809
- if ( 'post_updated' == $message_key ) {
810
-
811
  // Check for keys like "post_prev_post_title" and "post_new_post_title".
812
  $diff_table_output = '';
813
  $has_diff_values = false;
814
 
815
- foreach ( $context as $key => $val ) {
816
-
817
- if ( strpos( $key, 'post_prev_' ) !== false ) {
818
-
819
  // Old value exists, new value must also exist for diff to be calculates.
820
- $key_to_diff = substr( $key, strlen( 'post_prev_' ) );
821
 
822
  $key_for_new_val = "post_new_{$key_to_diff}";
823
 
824
- if ( isset( $context[ $key_for_new_val ] ) ) {
825
-
826
- $post_old_value = $context[ $key ];
827
- $post_new_value = $context[ $key_for_new_val ];
828
- if ( $post_old_value != $post_new_value ) {
829
-
830
  // Different diffs for different keys.
831
- if ( 'post_title' == $key_to_diff ) {
832
-
833
  $has_diff_values = true;
834
 
835
  $diff_table_output .= sprintf(
836
  '<tr><td>%1$s</td><td>%2$s</td></tr>',
837
- __( 'Title', 'simple-history' ),
838
- simple_history_text_diff( $post_old_value, $post_new_value )
 
 
 
839
  );
840
-
841
- } elseif ( 'post_content' == $key_to_diff ) {
842
-
843
  // Problem: to much text/content.
844
  // Risks to fill the visual output.
845
  // Maybe solution: use own diff function, that uses none or few context lines.
846
  $has_diff_values = true;
847
- $key_text_diff = simple_history_text_diff( $post_old_value, $post_new_value );
 
 
 
848
 
849
- if ( $key_text_diff ) {
850
  $diff_table_output .= sprintf(
851
  '<tr><td>%1$s</td><td>%2$s</td></tr>',
852
- __( 'Content', 'simple-history' ),
853
  $key_text_diff
854
  );
855
  }
856
-
857
- } elseif ( 'post_status' == $key_to_diff ) {
858
-
859
  $has_diff_values = true;
860
  $diff_table_output .= sprintf(
861
  '<tr>
862
  <td>%1$s</td>
863
  <td>Changed from %2$s to %3$s</td>
864
  </tr>',
865
- __( 'Status', 'simple-history' ),
866
- esc_html( $post_old_value ),
867
- esc_html( $post_new_value )
868
  );
869
-
870
- } elseif ( 'post_date' == $key_to_diff ) {
871
-
872
  $has_diff_values = true;
873
 
874
  // $diff = new FineDiff($post_old_value, $post_new_value, FineDiff::$wordGranularity);
@@ -877,13 +1275,11 @@ class SimplePostLogger extends SimpleLogger {
877
  <td>%1$s</td>
878
  <td>Changed from %2$s to %3$s</td>
879
  </tr>',
880
- __( 'Publish date', 'simple-history' ),
881
- esc_html( $post_old_value ),
882
- esc_html( $post_new_value )
883
  );
884
-
885
- } elseif ( 'post_name' == $key_to_diff ) {
886
-
887
  $has_diff_values = true;
888
 
889
  // $diff = new FineDiff($post_old_value, $post_new_value, FineDiff::$wordGranularity);
@@ -892,12 +1288,13 @@ class SimplePostLogger extends SimpleLogger {
892
  <td>%1$s</td>
893
  <td>%2$s</td>
894
  </tr>',
895
- __( 'Permalink', 'simple-history' ),
896
- simple_history_text_diff( $post_old_value, $post_new_value )
 
 
 
897
  );
898
-
899
- } elseif ( 'comment_status' == $key_to_diff ) {
900
-
901
  $has_diff_values = true;
902
 
903
  // $diff = new FineDiff($post_old_value, $post_new_value, FineDiff::$wordGranularity);
@@ -906,65 +1303,119 @@ class SimplePostLogger extends SimpleLogger {
906
  <td>%1$s</td>
907
  <td>Changed from %2$s to %3$s</td>
908
  </tr>',
909
- __( 'Comment status', 'simple-history' ),
910
- esc_html( $post_old_value ),
911
- esc_html( $post_new_value )
912
  );
913
-
914
- } elseif ( 'post_author' == $key_to_diff ) {
915
-
916
  $has_diff_values = true;
917
 
918
  // wp post edit screen uses display_name so we should use it too.
919
- if ( isset( $context['post_prev_post_author/display_name'] ) && isset( $context['post_new_post_author/display_name'] ) ) {
920
-
921
- $prev_user_display_name = $context['post_prev_post_author/display_name'];
922
- $new_user_display_name = $context['post_new_post_author/display_name'];
923
-
924
- $prev_user_user_email = $context['post_prev_post_author/user_email'];
925
- $new_user_user_email = $context['post_new_post_author/user_email'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
926
 
927
  $diff_table_output .= sprintf(
928
  '<tr>
929
  <td>%1$s</td>
930
  <td>%2$s</td>
931
  </tr>',
932
- __( 'Author', 'simple-history' ),
933
  $this->interpolate(
934
- __( 'Changed from {prev_user_display_name} ({prev_user_email}) to {new_user_display_name} ({new_user_email})', 'simple-history' ),
 
 
 
935
  array(
936
- 'prev_user_display_name' => esc_html( $prev_user_display_name ),
937
- 'prev_user_email' => esc_html( $prev_user_user_email ),
938
- 'new_user_display_name' => esc_html( $new_user_display_name ),
939
- 'new_user_email' => esc_html( $new_user_user_email ),
 
 
 
 
 
 
 
 
940
  )
941
  )
942
  );
943
-
944
  }
945
- } elseif ( 'page_template' == $key_to_diff ) {
946
-
947
  // page template filename.
948
- $prev_page_template = $context['post_prev_page_template'];
949
- $new_page_template = $context['post_new_page_template'];
 
 
950
 
951
  // page template name, should exist, but I guess someone could have deleted a template
952
  // and after that change the template for a post.
953
- $prev_page_template_name = isset( $context['post_prev_page_template_name'] ) ? $context['post_prev_page_template_name'] : '';
954
- $new_page_template_name = isset( $context['post_new_page_template_name'] ) ? $context['post_new_page_template_name'] : '';
 
 
 
 
 
 
 
 
955
 
956
  // If prev och new template is "default" then use that as name.
957
- if ( 'default' == $prev_page_template && ! $prev_page_template_name ) {
 
 
 
958
  $prev_page_template_name = $prev_page_template;
959
- } elseif ( 'default' == $new_page_template && ! $new_page_template_name ) {
 
 
 
960
  $new_page_template_name = $new_page_template;
961
  }
962
 
963
- // @TODO: translate template names
964
- // $value = translate( $value, $this->get('TextDomain') );
965
- $message = __( 'Changed from {prev_page_template} to {new_page_template}', 'simple-history' );
966
- if ( $prev_page_template_name && $new_page_template_name ) {
967
- $message = __( 'Changed from "{prev_page_template_name}" to "{new_page_template_name}"', 'simple-history' );
 
 
 
 
 
 
 
 
 
968
  }
969
 
970
  $diff_table_output .= sprintf(
@@ -972,39 +1423,57 @@ class SimplePostLogger extends SimpleLogger {
972
  <td>%1$s</td>
973
  <td>%2$s</td>
974
  </tr>',
975
- __( 'Template', 'simple-history' ),
976
- $this->interpolate(
977
- $message,
978
- array(
979
- 'prev_page_template' => '<code>' . esc_html( $prev_page_template ) . '</code>',
980
- 'new_page_template' => '<code>' . esc_html( $new_page_template ) . '</code>',
981
- 'prev_page_template_name' => esc_html( $prev_page_template_name ),
982
- 'new_page_template_name' => esc_html( $new_page_template_name ),
 
 
 
 
 
 
 
983
  )
984
- )
985
  );
986
-
987
- }// End if().
988
- }// End if().
989
- }// End if().
990
- }// End if().
991
  } // End foreach().
992
 
993
- if ( isset( $context['post_meta_added'] ) || isset( $context['post_meta_removed'] ) || isset( $context['post_meta_changed'] ) ) {
994
-
 
 
 
995
  $meta_changed_out = '';
996
  $has_diff_values = true;
997
 
998
- if ( isset( $context['post_meta_added'] ) ) {
999
- $meta_changed_out .= "<span class='SimpleHistoryLogitem__inlineDivided'>" . (int) $context['post_meta_added'] . ' added</span> ';
 
 
 
1000
  }
1001
 
1002
- if ( isset( $context['post_meta_removed'] ) ) {
1003
- $meta_changed_out .= "<span class='SimpleHistoryLogitem__inlineDivided'>" . (int) $context['post_meta_removed'] . ' removed</span> ';
 
 
 
1004
  }
1005
 
1006
- if ( isset( $context['post_meta_changed'] ) ) {
1007
- $meta_changed_out .= "<span class='SimpleHistoryLogitem__inlineDivided'>" . (int) $context['post_meta_changed'] . ' changed</span> ';
 
 
 
1008
  }
1009
 
1010
  $diff_table_output .= sprintf(
@@ -1012,10 +1481,9 @@ class SimplePostLogger extends SimpleLogger {
1012
  <td>%1$s</td>
1013
  <td>%2$s</td>
1014
  </tr>',
1015
- esc_html( __( 'Custom fields', 'simple-history' ) ),
1016
  $meta_changed_out
1017
  );
1018
-
1019
  }
1020
 
1021
  /*
@@ -1034,7 +1502,9 @@ class SimplePostLogger extends SimpleLogger {
1034
  // Changed post thumb/featued image.
1035
  // post_prev_thumb, int of prev thumb, empty if not prev thumb.
1036
  // post_new_thumb, int of new thumb, empty if no new thumb.
1037
- $diff_table_output .= $this->getLogRowDetailsOutputForPostThumb( $context );
 
 
1038
 
1039
  /**
1040
  * Modify the formatted diff output of a saved/modified post
@@ -1043,23 +1513,25 @@ class SimplePostLogger extends SimpleLogger {
1043
  * @param array $context
1044
  * @return string
1045
  */
1046
- $diff_table_output = apply_filters( 'simple_history/post_logger/post_updated/diff_table_output', $diff_table_output, $context );
1047
-
1048
- if ( $has_diff_values || $diff_table_output ) {
1049
-
1050
- $diff_table_output = '<table class="SimpleHistoryLogitem__keyValueTable">' . $diff_table_output . '</table>';
1051
 
 
 
 
 
 
1052
  }
1053
 
1054
  $out .= $diff_table_output;
1055
-
1056
- }// End if().
1057
 
1058
  return $out;
1059
-
1060
  }
1061
 
1062
-
1063
  /**
1064
  * Modify RSS links to they go directly to the correct post in wp admin
1065
  *
@@ -1067,26 +1539,27 @@ class SimplePostLogger extends SimpleLogger {
1067
  * @param string $link Link.
1068
  * @param array $row Row.
1069
  */
1070
- public function filter_rss_item_link( $link, $row ) {
1071
-
1072
- if ( $row->logger != $this->slug ) {
1073
  return $link;
1074
  }
1075
 
1076
- if ( isset( $row->context['post_id'] ) ) {
1077
-
1078
- $permalink = add_query_arg( array(
1079
- 'action' => 'edit',
1080
- 'post' => $row->context['post_id'],
1081
- ), admin_url( 'post.php' ) );
 
 
1082
 
1083
- if ( $permalink ) {
1084
  $link = $permalink;
1085
  }
1086
  }
1087
 
1088
  return $link;
1089
-
1090
  }
1091
 
1092
  /**
@@ -1097,35 +1570,45 @@ class SimplePostLogger extends SimpleLogger {
1097
  * @param array $new_meta New meta.
1098
  * @return array Maybe modifed context.
1099
  */
1100
- public function add_post_thumb_diff( $context, $old_meta, $new_meta ) {
 
1101
  $post_thumb_modified = false;
1102
  $prev_post_thumb_id = null;
1103
  $new_post_thumb_id = null;
1104
 
1105
  // If it was changed from one image to another.
1106
- if ( isset( $old_meta['_thumbnail_id'][0] ) && isset( $new_meta['_thumbnail_id'][0] ) ) {
1107
- if ( $old_meta['_thumbnail_id'][0] !== $new_meta['_thumbnail_id'][0] ) {
 
 
 
 
 
1108
  $post_thumb_modified = true;
1109
  $prev_post_thumb_id = $old_meta['_thumbnail_id'][0];
1110
  $new_post_thumb_id = $new_meta['_thumbnail_id'][0];
1111
  }
1112
  } else {
1113
  // Featured image id did not exist on both new and old data. But on any?
1114
- if ( isset( $old_meta['_thumbnail_id'][0] ) ) {
1115
  $prev_post_thumb_id = $old_meta['_thumbnail_id'][0];
1116
- } elseif ( isset( $new_meta['_thumbnail_id'][0] ) ) {
1117
  $new_post_thumb_id = $new_meta['_thumbnail_id'][0];
1118
  }
1119
  }
1120
 
1121
- if ( $prev_post_thumb_id ) {
1122
  $context['post_prev_thumb_id'] = $prev_post_thumb_id;
1123
- $context['post_prev_thumb_title'] = get_the_title( $prev_post_thumb_id );
 
 
1124
  }
1125
 
1126
- if ( $new_post_thumb_id ) {
1127
  $context['post_new_thumb_id'] = $new_post_thumb_id;
1128
- $context['post_new_thumb_title'] = get_the_title( $new_post_thumb_id );
 
 
1129
  }
1130
 
1131
  return $context;
@@ -1137,25 +1620,42 @@ class SimplePostLogger extends SimpleLogger {
1137
  * @param array $context Context that may contains prev- and new thumb ids.
1138
  * @return string HTML to be used in keyvale table.
1139
  */
1140
- private function getLogRowDetailsOutputForPostThumb( $context = null ) {
 
1141
  $out = '';
1142
 
1143
- if ( ! empty( $context['post_prev_thumb_id'] ) || ! empty( $context['post_new_thumb_id'] ) ) {
1144
-
 
 
1145
  // Check if images still exists and if so get their thumbnails.
1146
- $prev_thumb_id = empty( $context['post_prev_thumb_id'] ) ? null : $context['post_prev_thumb_id'];
1147
- $new_thumb_id = empty( $context['post_new_thumb_id'] ) ? null : $context['post_new_thumb_id'];
1148
- $post_new_thumb_title = empty( $context['post_new_thumb_title'] ) ? null : $context['post_new_thumb_title'];
1149
- $post_prev_thumb_title = empty( $context['post_prev_thumb_title'] ) ? null : $context['post_prev_thumb_title'];
1150
-
1151
- $prev_attached_file = get_attached_file( $prev_thumb_id );
1152
- $prev_thumb_src = wp_get_attachment_image_src( $prev_thumb_id, 'small' );
 
 
 
 
 
 
 
 
 
 
 
1153
 
1154
- $new_attached_file = get_attached_file( $new_thumb_id );
1155
- $new_thumb_src = wp_get_attachment_image_src( $new_thumb_id, 'small' );
 
 
 
1156
 
1157
  $prev_thumb_html = '';
1158
- if ( file_exists( $prev_attached_file ) && $prev_thumb_src ) {
1159
  $prev_thumb_html = sprintf(
1160
  '
1161
  <div>%2$s</div>
@@ -1164,18 +1664,18 @@ class SimplePostLogger extends SimpleLogger {
1164
  </div>
1165
  ',
1166
  $prev_thumb_src[0],
1167
- esc_html( $post_prev_thumb_title )
1168
  );
1169
  } else {
1170
  // Fallback if image does not exist.
1171
  $prev_thumb_html = sprintf(
1172
  '<div>%1$s</div>',
1173
- esc_html( $post_prev_thumb_title )
1174
  );
1175
  }
1176
 
1177
  $new_thumb_html = '';
1178
- if ( file_exists( $new_attached_file ) && $new_thumb_src ) {
1179
  $new_thumb_html = sprintf(
1180
  '
1181
  <div>%2$s</div>
@@ -1184,13 +1684,13 @@ class SimplePostLogger extends SimpleLogger {
1184
  </div>
1185
  ',
1186
  $new_thumb_src[0],
1187
- esc_html( $post_new_thumb_title )
1188
  );
1189
  } else {
1190
  // Fallback if image does not exist.
1191
  $prev_thumb_html = sprintf(
1192
  '<div>%1$s</div>',
1193
- esc_html( $post_new_thumb_title )
1194
  );
1195
  }
1196
 
@@ -1217,7 +1717,7 @@ class SimplePostLogger extends SimpleLogger {
1217
 
1218
  </td>
1219
  </tr>',
1220
- esc_html( __( 'Featured image', 'simple-history' ) ), // 1
1221
  $prev_thumb_html, // 2
1222
  $new_thumb_html // 3
1223
  );
@@ -1229,7 +1729,8 @@ class SimplePostLogger extends SimpleLogger {
1229
  /**
1230
  * Output CSS for diff output
1231
  */
1232
- public function adminCSS() {
 
1233
  ?>
1234
  <style>
1235
  .SimpleHistory__diff.SimpleHistory__diff {
@@ -1249,5 +1750,4 @@ class SimplePostLogger extends SimpleLogger {
1249
  </style>
1250
  <?php
1251
  }
1252
-
1253
  }
1
  <?php
2
 
3
+ defined('ABSPATH') || die();
4
 
5
  /**
6
+ * Todo/@HERE
7
+ * - [ ] install and test with ACF again
8
+ * - Install 5.7.13 and then each save or preview results in 2 or 3 adds to the log.
9
+ * - The second save saves all the post meta. So it's technically two saves but not for the user.
10
+ * Both requests have the same HTTP_X_WP_NONCE
11
+ * - [ ] test REST API update from curl or similar
12
+ * - [ ] test REST API from Android/Ios-apps
13
+ * - [ ] Save auto-saves? Not done by user but still done...
14
  */
 
15
 
16
+ /**
17
+ * Logs changes to posts and pages, including custom post types
18
+ */
19
+ class SimplePostLogger extends SimpleLogger
20
+ {
21
+ // The logger slug. Defaulting to the class name is nice and logical I think.
22
  public $slug = __CLASS__;
23
 
24
+ // Array that will contain previous post data, before data is updated.
25
+ // Array format is
26
+ // [post_id] => [post_data, post_meta].
27
+ // post_data = WP_Post object, post_meta = post meta array.
28
  private $old_post_data = array();
29
 
30
+ public function loaded()
31
+ {
32
+ add_action('admin_action_editpost', array(
33
+ $this,
34
+ 'on_admin_action_editpost'
35
+ ));
36
+ add_action(
37
+ 'transition_post_status',
38
+ array($this, 'on_transition_post_status'),
39
+ 10,
40
+ 3
41
+ );
42
+ add_action('delete_post', array($this, 'on_delete_post'));
43
+ add_action('untrash_post', array($this, 'on_untrash_post'));
44
 
45
  $this->add_xml_rpc_hooks();
46
+ $this->add_rest_hooks();
47
+
48
+ add_filter(
49
+ 'simple_history/rss_item_link',
50
+ array($this, 'filter_rss_item_link'),
51
+ 10,
52
+ 2
53
+ );
54
+ }
55
 
56
+ /**
57
+ * Add hooks to catch updates via REST API, i.e. the new Gutenberg editor.
58
+ */
59
+ function add_rest_hooks()
60
+ {
61
+ // Get all post types.
62
+ $post_types = get_post_types(array(), 'objects');
63
+
64
+ // Add actions for each post type.
65
+ foreach ($post_types as $post_type) {
66
+ // class-wp-rest-posts-controller.php fires two actions in
67
+ // the update_item() method: pre_insert and after_insert.
68
+
69
+ // Rest pre insert is fired before an updated post is inserted into db.
70
+ add_action(
71
+ "rest_pre_insert_{$post_type->name}",
72
+ array($this, 'on_rest_pre_insert'),
73
+ 10,
74
+ 2
75
+ );
76
 
77
+ // Rest insert happens after the post has been updated: "Fires after a single post is completely created or updated via the REST API."
78
+ // add_action( "rest_after_insert_{$post_type->name}", array( $this, 'on_rest_after_insert' ), 10, 3 );
79
+ }
80
  }
81
 
82
  /**
83
+ * Filter "rest_pre_insert_{$this->post_type}" filters a post before it is inserted via the REST API.
84
+ * Fired from class-wp-rest-posts-controller.php.
85
+ *
86
+ * Here we can get the old post object.
87
+ *
88
+ * @param stdClass $prepared_post An object representing a single post prepared
89
+ * for inserting or updating the database, i.e. the new updated post.
90
+ * @param WP_REST_Request $request Request object.
91
+ * @return stdClass $prepared_post
92
  */
93
+ function on_rest_pre_insert($prepared_post, $request)
94
+ {
95
+ // $prepared_post = stdClass Object with new and modified content.
96
+ // changes are not saved to post in db yet, so get_post( $prepared_post->ID ) will get old contents.
97
+ /*
98
+ stdClass Object
99
+ (
100
+ [ID] => 889
101
+ [post_title] => gutenberg 1
102
+ [post_content] => <!-- wp:paragraph -->
103
+ <p>hejsan</p>
104
+ <!-- /wp:paragraph -->
105
+ [post_excerpt] =>
106
+ [post_type] => post
107
+ [page_template] =>
108
+ )
109
+ */
110
+
111
+ // $old_post = post with old content and old meta
112
+ $old_post = get_post($prepared_post->ID);
113
 
114
+ $this->old_post_data[$old_post->ID] = array(
115
+ 'post_data' => $old_post,
116
+ 'post_meta' => get_post_custom($old_post->ID)
117
+ );
118
+
119
+ return $prepared_post;
120
+ }
121
+
122
+ /**
123
+ * Fires after a single post is completely created or updated via the REST API.
124
+ *
125
+ * Here we can get the updated post, after it's updated in the db.
126
+ *
127
+ * @param WP_Post $post Inserted or updated post object.
128
+ * @param WP_REST_Request $request Request object.
129
+ * @param bool $creating True when creating a post, false when updating.
130
+ */
131
+ function on_rest_after_insert($post, $request, $creating)
132
+ {
133
+ $post = get_post($post->ID);
134
+ $post_meta = get_post_custom($post->ID);
135
+
136
+ $old_post = $this->old_post_data[$post->ID]['post_data'];
137
+ $old_post_meta = $this->old_post_data[$post->ID]['post_meta'];
138
+
139
+ // @HERE
140
+ $args = array(
141
+ 'new_post' => $post,
142
+ 'new_post_meta' => $post_meta,
143
+ 'old_post' => $old_post,
144
+ 'old_post_meta' => $old_post_meta,
145
+ 'old_status' => $old_post->post_status,
146
+ '_debug_caller_method' => __METHOD__
147
+ );
148
+
149
+ $this->maybe_log_post_change($args);
150
+ }
151
+
152
+ /**
153
+ * Filters to XML RPC calls needs to be added early, admin_init is to late.
154
+ */
155
+ function add_xml_rpc_hooks()
156
+ {
157
  // Debug: log all XML-RPC requests
158
  /*
159
  add_action("xmlrpc_call", function($method) {
161
  }, 10, 1);
162
  */
163
 
164
+ add_action(
165
+ 'xmlrpc_call_success_blogger_newPost',
166
+ array($this, 'on_xmlrpc_newPost'),
167
+ 10,
168
+ 2
169
+ );
170
+ add_action(
171
+ 'xmlrpc_call_success_mw_newPost',
172
+ array($this, 'on_xmlrpc_newPost'),
173
+ 10,
174
+ 2
175
+ );
176
 
177
+ add_action(
178
+ 'xmlrpc_call_success_blogger_editPost',
179
+ array($this, 'on_xmlrpc_editPost'),
180
+ 10,
181
+ 2
182
+ );
183
+ add_action(
184
+ 'xmlrpc_call_success_mw_editPost',
185
+ array($this, 'on_xmlrpc_editPost'),
186
+ 10,
187
+ 2
188
+ );
189
 
190
+ add_action(
191
+ 'xmlrpc_call_success_blogger_deletePost',
192
+ array($this, 'on_xmlrpc_deletePost'),
193
+ 10,
194
+ 2
195
+ );
196
+ add_action(
197
+ 'xmlrpc_call_success_wp_deletePage',
198
+ array($this, 'on_xmlrpc_deletePost'),
199
+ 10,
200
+ 2
201
+ );
202
 
203
+ add_action('xmlrpc_call', array($this, 'on_xmlrpc_call'), 10, 1);
204
  }
205
 
206
+ function on_xmlrpc_call($method)
207
+ {
208
+ $arr_methods_to_act_on = array('wp.deletePost');
 
 
209
 
210
  $raw_post_data = null;
211
  $message = null;
212
  $context = array();
213
 
214
+ if (in_array($method, $arr_methods_to_act_on)) {
 
215
  // Setup common stuff
216
+ $raw_post_data = file_get_contents('php://input');
217
+ $context[
218
+ 'wp.deletePost.xmldata'
219
+ ] = $this->simpleHistory->json_encode($raw_post_data);
220
+ $message = new IXR_Message($raw_post_data);
221
 
222
+ if (!$message->parse()) {
223
  return;
224
  }
225
 
226
+ $context[
227
+ 'wp.deletePost.xmlrpc_message'
228
+ ] = $this->simpleHistory->json_encode($message);
229
+ $context[
230
+ 'wp.deletePost.xmlrpc_message.messageType'
231
+ ] = $this->simpleHistory->json_encode($message->messageType);
232
+ $context[
233
+ 'wp.deletePost.xmlrpc_message.methodName'
234
+ ] = $this->simpleHistory->json_encode($message->methodName);
235
+ $context[
236
+ 'wp.deletePost.xmlrpc_message.messageParams'
237
+ ] = $this->simpleHistory->json_encode($message->params);
238
 
239
  // Actions for delete post
240
+ if ('wp.deletePost' == $method) {
 
241
  // 4 params, where the last is the post id
242
+ if (!isset($message->params[3])) {
243
  return;
244
  }
245
 
246
  $post_ID = $message->params[3];
247
 
248
+ $post = get_post($post_ID);
249
 
250
  $context = array(
251
  'post_id' => $post->ID,
252
+ 'post_type' => get_post_type($post),
253
+ 'post_title' => get_the_title($post)
254
  );
255
 
256
+ $this->infoMessage('post_trashed', $context);
 
257
  }
258
+ } // End if().
 
259
  }
260
 
 
261
  /**
262
  * Get array with information about this logger
263
  *
264
  * @return array
265
  */
266
+ function getInfo()
267
+ {
268
  $arr_info = array(
269
  'name' => 'Post Logger',
270
+ 'description' =>
271
+ 'Logs the creation and modification of posts and pages',
272
  'capability' => 'edit_pages',
273
  'messages' => array(
274
+ 'post_created' => __(
275
+ 'Created {post_type} "{post_title}"',
276
+ 'simple-history'
277
+ ),
278
+ 'post_updated' => __(
279
+ 'Updated {post_type} "{post_title}"',
280
+ 'simple-history'
281
+ ),
282
+ 'post_restored' => __(
283
+ 'Restored {post_type} "{post_title}" from trash',
284
+ 'simple-history'
285
+ ),
286
+ 'post_deleted' => __(
287
+ 'Deleted {post_type} "{post_title}"',
288
+ 'simple-history'
289
+ ),
290
+ 'post_trashed' => __(
291
+ 'Moved {post_type} "{post_title}" to the trash',
292
+ 'simple-history'
293
+ )
294
  ),
295
  'labels' => array(
296
  'search' => array(
297
+ 'label' => _x(
298
+ 'Posts & Pages',
299
+ 'Post logger: search',
300
+ 'simple-history'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
  ),
302
+ 'label_all' => _x(
303
+ 'All posts & pages activity',
304
+ 'Post logger: search',
305
+ 'simple-history'
306
+ ),
307
+ 'options' => array(
308
+ _x(
309
+ 'Posts created',
310
+ 'Post logger: search',
311
+ 'simple-history'
312
+ ) => array('post_created'),
313
+ _x(
314
+ 'Posts updated',
315
+ 'Post logger: search',
316
+ 'simple-history'
317
+ ) => array('post_updated'),
318
+ _x(
319
+ 'Posts trashed',
320
+ 'Post logger: search',
321
+ 'simple-history'
322
+ ) => array('post_trashed'),
323
+ _x(
324
+ 'Posts deleted',
325
+ 'Post logger: search',
326
+ 'simple-history'
327
+ ) => array('post_deleted'),
328
+ _x(
329
+ 'Posts restored',
330
+ 'Post logger: search',
331
+ 'simple-history'
332
+ ) => array('post_restored')
333
+ )
334
+ ) // end search array
335
+ ) // end labels
336
  );
337
 
338
  return $arr_info;
 
339
  }
340
 
341
  /**
342
  * Get and store old info about a post that is being edited.
343
  * Needed to later compare old data with new data, to detect differences.
344
+ * This function is called on edit screen but before post edits are saved.
345
  *
346
  * Can't use the regular filters like "pre_post_update" because custom fields are already written by then.
347
  *
348
  * @since 2.0.29
349
  */
350
+ function on_admin_action_editpost()
351
+ {
352
+ $post_ID = isset($_POST['post_ID']) ? (int) $_POST['post_ID'] : 0;
353
 
354
+ if (!$post_ID) {
 
 
355
  return;
356
  }
357
 
358
+ if (!current_user_can('edit_post', $post_ID)) {
359
  return;
360
+ }
361
 
362
+ $prev_post_data = get_post($post_ID);
363
 
364
  if (is_wp_error($prev_post_data)) {
365
  return;
366
  }
367
 
368
  $this->old_post_data[$post_ID] = array(
369
+ 'post_data' => $prev_post_data,
370
+ 'post_meta' => get_post_custom($post_ID)
371
  );
 
372
  }
373
 
374
  /**
379
  * @param int $post_ID ID of the deleted post.
380
  * @param array $args An array of arguments to delete the post.
381
  */
382
+ function on_xmlrpc_deletePost($post_ID, $args)
383
+ {
384
+ $post = get_post($post_ID);
385
 
386
  $context = array(
387
  'post_id' => $post->ID,
388
+ 'post_type' => get_post_type($post),
389
+ 'post_title' => get_the_title($post)
390
  );
391
 
392
+ $this->infoMessage('post_deleted', $context);
 
393
  }
394
 
395
  /**
400
  * @param int $post_ID ID of the updated post.
401
  * @param array $args An array of arguments for the post to edit.
402
  */
403
+ function on_xmlrpc_editPost($post_ID, $args)
404
+ {
405
+ $post = get_post($post_ID);
406
 
407
  $context = array(
408
  'post_id' => $post->ID,
409
+ 'post_type' => get_post_type($post),
410
+ 'post_title' => get_the_title($post)
411
  );
412
 
413
+ $this->infoMessage('post_updated', $context);
 
414
  }
415
 
416
  /**
421
  * @param int $post_ID ID of the new post.
422
  * @param array $args An array of new post arguments.
423
  */
424
+ function on_xmlrpc_newPost($post_ID, $args)
425
+ {
426
+ $post = get_post($post_ID);
427
 
428
  $context = array(
429
  'post_id' => $post->ID,
430
+ 'post_type' => get_post_type($post),
431
+ 'post_title' => get_the_title($post)
432
  );
433
 
434
+ $this->infoMessage('post_created', $context);
 
435
  }
436
 
437
  /**
438
  * Called when a post is restored from the trash
439
+ * @param int $post_id
440
  */
441
+ function on_untrash_post($post_id)
442
+ {
443
+ $post = get_post($post_id);
444
 
445
+ if (!$this->ok_to_log_post_posttype($post)) {
446
  return;
447
  }
448
 
449
+ $this->infoMessage('post_restored', array(
450
+ 'post_id' => $post_id,
451
+ 'post_type' => get_post_type($post),
452
+ 'post_title' => get_the_title($post)
453
+ ));
 
 
 
 
454
  }
455
 
456
  /**
458
  *
459
  * @param int $postid Post ID.
460
  */
461
+ function on_delete_post($post_id)
462
+ {
463
+ $post = get_post($post_id);
464
 
465
+ if (wp_is_post_revision($post_id)) {
466
  return;
467
  }
468
 
469
+ if (
470
+ $post->post_status === 'auto-draft' ||
471
+ $post->post_status === 'inherit'
472
+ ) {
473
  return;
474
  }
475
 
476
  $ok_to_log = true;
477
 
478
+ if (!$this->ok_to_log_post_posttype($post)) {
479
  $ok_to_log = false;
480
  }
481
 
489
  *
490
  * @since 2.21
491
  */
492
+ $ok_to_log = apply_filters(
493
+ 'simple_history/post_logger/post_deleted/ok_to_log',
494
+ $ok_to_log,
495
+ $post_id
496
+ );
497
 
498
+ if (!$ok_to_log) {
499
  return;
500
  }
501
 
512
  ]
513
  */
514
  global $wp_current_filter;
515
+ if (isset($wp_current_filter) && is_array($wp_current_filter)) {
516
+ if (in_array('wp_scheduled_delete', $wp_current_filter, true)) {
517
  return;
518
  }
519
  }
520
 
521
+ $this->infoMessage('post_deleted', array(
522
+ 'post_id' => $post_id,
523
+ 'post_type' => get_post_type($post),
524
+ 'post_title' => get_the_title($post)
525
+ ));
 
 
 
 
526
  }
527
 
528
  /**
529
  * Get an array of post types that should not be logged by this logger.
530
+ *
531
+ * @return Array with post type slugs to skip.
532
  */
533
+ public function get_skip_posttypes()
534
+ {
535
  $skip_posttypes = array(
536
  // Don't log nav_menu_updates.
537
  'nav_menu_item',
540
  'jetpack_migration',
541
  'jp_sitemap',
542
  'jp_img_sitemap',
543
+ 'jp_sitemap_master'
544
  );
545
 
546
  /**
548
  *
549
  * @since 2.18
550
  */
551
+ $skip_posttypes = apply_filters(
552
+ 'simple_history/post_logger/skip_posttypes',
553
+ $skip_posttypes
554
+ );
555
 
556
  return $skip_posttypes;
557
  }
563
  *
564
  * @return bool
565
  */
566
+ public function ok_to_log_post_posttype($post)
567
+ {
568
  $ok_to_log = true;
569
  $skip_posttypes = $this->get_skip_posttypes();
570
 
571
+ if (in_array(get_post_type($post), $skip_posttypes, true)) {
572
  $ok_to_log = false;
573
  }
574
 
576
  }
577
 
578
  /**
579
+ * Maybe log a post creation, modification or deletion.
580
+ *
581
+ * Todo:
582
+ * - support password protect.
583
+ * - post_password is set
584
+ *
585
+ * @param array $args Array with old and new post data.
586
+ */
587
+ public function maybe_log_post_change($args)
588
+ {
589
+ $default_args = array(
590
+ 'new_post',
591
+ 'new_post_meta',
592
+ 'old_post',
593
+ 'old_post_meta',
594
+ // Old status is included because that's the value we get in filter
595
+ // "transation_post_status", when a previous post may not exist.
596
+ 'old_status'
597
+ );
598
+
599
+ $args = wp_parse_args($args, $default_args);
600
+
601
+ // Bail if needed args not set.
602
+ if (!isset($args['new_post']) || !isset($args['new_post_meta'])) {
603
+ return;
604
+ }
605
 
606
+ $new_status = isset($args['new_post']->post_status)
607
+ ? $args['new_post']->post_status
608
+ : null;
609
+ $post = $args['new_post'];
610
+ $new_post_data = array(
611
+ 'post_data' => $post,
612
+ 'post_meta' => $args['new_post_meta']
613
+ );
614
+
615
+ // Set old status to status from old post with fallback to old_status variable.
616
+ $old_status = isset($args['old_post']->post_status)
617
+ ? $args['old_post']->post_status
618
+ : null;
619
+ $old_status =
620
+ !isset($old_status) && isset($args['old_status'])
621
+ ? $args['old_status']
622
+ : $old_status;
623
+
624
+ $old_post = isset($args['old_post']) ? $args['old_post'] : null;
625
+ $old_post_meta = isset($args['old_post_meta'])
626
+ ? $args['old_post_meta']
627
+ : null;
628
+ $old_post_data = array(
629
+ 'post_data' => $old_post,
630
+ 'post_meta' => $old_post_meta
631
+ );
632
+
633
+ // Default to log.
634
  $ok_to_log = true;
635
 
636
+ // Calls from the WordPress ios app/jetpack comes from non-admin-area
637
  // i.e. is_admin() is false
638
+ // so don't log when outside admin area.
639
+ if (!is_admin()) {
640
  $ok_to_log = false;
641
  }
642
 
643
+ // Except when calls are from/for Jetpack/WordPress apps.
644
+ // seems to be jetpack/app request when $_GET["for"] == "jetpack.
645
+ $isXmlRpcRequest = defined('XMLRPC_REQUEST') && XMLRPC_REQUEST;
646
+ if (
647
+ $isXmlRpcRequest &&
648
+ isset($_GET['for']) &&
649
+ 'jetpack' === $_GET['for']
650
+ ) {
651
+ $ok_to_log = true;
652
+ }
653
+
654
+ // Also accept calls from REST API
655
+ $isRestApiRequest =
656
+ (defined('REST_API_REQUEST') && REST_API_REQUEST) ||
657
+ (defined('REST_REQUEST') && REST_REQUEST);
658
+ if ($isRestApiRequest) {
659
  $ok_to_log = true;
660
  }
661
 
662
  // Don't log revisions.
663
+ if (wp_is_post_revision($post)) {
664
  $ok_to_log = false;
665
  }
666
 
667
+ // Don't log Gutenberg saving meta boxes.
668
+ if (isset($_GET['meta-box-loader']) && $_GET['meta-box-loader']) {
669
+ $ok_to_log = false;
670
+ }
671
+
672
+ if (!$this->ok_to_log_post_posttype($post)) {
673
  $ok_to_log = false;
674
  }
675
 
685
  *
686
  * @since 2.21
687
  */
688
+ $ok_to_log = apply_filters(
689
+ 'simple_history/post_logger/post_updated/ok_to_log',
690
+ $ok_to_log,
691
+ $new_status,
692
+ $old_status,
693
+ $post
694
+ );
695
 
696
+ if (!$ok_to_log) {
697
  return;
698
  }
699
 
711
  */
712
  $context = array(
713
  'post_id' => $post->ID,
714
+ 'post_type' => get_post_type($post),
715
+ 'post_title' => get_the_title($post)
716
  );
717
 
718
+ if (
719
+ 'auto-draft' === $old_status &&
720
+ ('auto-draft' !== $new_status && 'inherit' !== $new_status)
721
+ ) {
722
  // Post created
723
+ $this->infoMessage('post_created', $context);
724
+ } elseif (
725
+ 'auto-draft' === $new_status ||
726
+ ('new' === $old_status && 'inherit' === $new_status)
727
+ ) {
728
  // Post was automagically saved by WordPress
729
  return;
730
+ } elseif ('trash' === $new_status) {
 
 
731
  // Post trashed
732
+ $this->infoMessage('post_trashed', $context);
 
733
  } else {
734
+ // Existing post was updated.
735
 
736
+ // Also add diff between previous saved data and new data.
737
+ if (isset($old_post_data) && isset($new_post_data)) {
 
 
 
 
 
 
 
 
 
738
  // Now we have both old and new post data, including custom fields, in the same format
739
  // So let's compare!
740
+ $context = $this->add_post_data_diff_to_context(
741
+ $context,
742
+ $old_post_data,
743
+ $new_post_data
744
+ );
745
  }
746
 
747
+ $context['_occasionsID'] =
748
+ __CLASS__ . '/' . __FUNCTION__ . "/post_updated/{$post->ID}";
749
 
750
  /**
751
  * Modify the context saved.
753
  * @param array $context
754
  * @param WP_Post $post
755
  */
756
+ $context = apply_filters(
757
+ 'simple_history/post_logger/post_updated/context',
758
+ $context,
759
+ $post
760
+ );
761
+
762
+ $this->infoMessage('post_updated', $context);
763
+ } // End if().
764
+ }
765
+
766
+ /**
767
+ * Fired when a post has changed status in the classical editor.
768
+ * Only run in certain cases,
769
+ * because when always enabled it catches a lots of edits made by plugins during cron jobs etc,
770
+ * which by definition is not wrong, but perhaps not wanted/annoying.
771
+ *
772
+ * @param string $new_status One of auto-draft, inherit, draft, pending, publish, future.
773
+ * @param string $old_status Same as above.
774
+ * @param WP_Post $post New updated post.
775
+ */
776
+ function on_transition_post_status($new_status, $old_status, $post)
777
+ {
778
+ // $isRestApiRequest = ( defined( 'REST_API_REQUEST' ) && REST_API_REQUEST ) || ( defined( 'REST_REQUEST' ) && REST_REQUEST );
779
+ // $is_admin = is_admin();
780
+ // False if not a revision, ID of revision's parent otherwise.
781
+ // $post_is_revision = wp_is_post_revision( $post );
782
+ // sh_error_log('on_transition_post_status', '$new_status', $new_status, '$old_status', $old_status, '$isRestApiRequest', $isRestApiRequest, '$is_admin', $is_admin, '$post_is_revision', $post_is_revision);
783
+ // Bail if post is not a post.
784
+ if (!is_a($post, 'WP_Post')) {
785
+ return;
786
+ }
787
 
788
+ // $old_post_data_exists = ! empty( $this->old_post_data[ $post->ID ] );
789
 
790
+ $old_post = null;
791
+ $old_post_meta = null;
792
 
793
+ if (!empty($this->old_post_data[$post->ID])) {
794
+ $old_post = $this->old_post_data[$post->ID]['post_data'];
795
+ $old_post_meta = $this->old_post_data[$post->ID]['post_meta'];
796
+ }
797
+
798
+ $args = array(
799
+ 'new_post' => $post,
800
+ 'new_post_meta' => get_post_custom($post->ID),
801
+ 'old_post' => $old_post,
802
+ 'old_post_meta' => $old_post_meta,
803
+ 'old_status' => $old_status,
804
+ '_debug_caller_method' => __METHOD__
805
+ );
806
+
807
+ $this->maybe_log_post_change($args);
808
  }
809
 
810
  /**
813
  * Since 2.0.29
814
  *
815
  * To detect
816
+ * - categories
817
+ * - tags
818
  *
819
  * @param array $context Array with context.
820
  * @param array $old_post_data Old/prev post data.
821
  * @param array $new_post_data New post data.
822
  * @return array $context with diff data added.
823
  */
824
+ function add_post_data_diff_to_context(
825
+ $context,
826
+ $old_post_data,
827
+ $new_post_data
828
+ ) {
829
  $old_data = $old_post_data['post_data'];
830
  $new_data = $new_post_data['post_data'];
831
 
844
  'comment_status',
845
  'ping_status',
846
  'post_parent', // only id, need to get context for that, like name of parent at least?
847
+ 'post_author' // only id, need to get more info for user.
848
  );
849
 
850
+ foreach ($arr_keys_to_diff as $key) {
851
+ if (isset($old_data->$key) && isset($new_data->$key)) {
852
+ $post_data_diff = $this->add_diff(
853
+ $post_data_diff,
854
+ $key,
855
+ $old_data->$key,
856
+ $new_data->$key
857
+ );
858
  }
859
  }
860
 
861
  // If changes where detected.
862
+ if ($post_data_diff) {
 
863
  // Save at least 2 values for each detected value change, i.e. the old value and the new value.
864
+ foreach ($post_data_diff as $diff_key => $diff_values) {
865
+ $context["post_prev_{$diff_key}"] = $diff_values['old'];
866
+ $context["post_new_{$diff_key}"] = $diff_values['new'];
 
867
 
868
  // If post_author then get more author info,
869
  // because just a user ID does not get us far.
870
+ if ('post_author' == $diff_key) {
871
+ $old_author_user = get_userdata((int) $diff_values['old']);
872
+ $new_author_user = get_userdata((int) $diff_values['new']);
873
+
874
+ if (
875
+ is_a($old_author_user, 'WP_User') &&
876
+ is_a($new_author_user, 'WP_User')
877
+ ) {
878
+ $context["post_prev_{$diff_key}/user_login"] =
879
+ $old_author_user->user_login;
880
+ $context["post_prev_{$diff_key}/user_email"] =
881
+ $old_author_user->user_email;
882
+ $context["post_prev_{$diff_key}/display_name"] =
883
+ $old_author_user->display_name;
884
+
885
+ $context["post_new_{$diff_key}/user_login"] =
886
+ $new_author_user->user_login;
887
+ $context["post_new_{$diff_key}/user_email"] =
888
+ $new_author_user->user_email;
889
+ $context["post_new_{$diff_key}/display_name"] =
890
+ $new_author_user->display_name;
891
  }
892
  }
893
  }
900
  '_edit_last',
901
  '_post_restored_from',
902
  '_wp_page_template',
903
+ '_thumbnail_id'
904
  );
905
 
906
  $meta_changes = array(
907
  'added' => array(),
908
  'removed' => array(),
909
+ 'changed' => array()
910
  );
911
 
912
+ $old_meta = isset($old_post_data['post_meta'])
913
+ ? (array) $old_post_data['post_meta']
914
+ : array();
915
+ $new_meta = isset($new_post_data['post_meta'])
916
+ ? (array) $new_post_data['post_meta']
917
+ : array();
918
 
919
  // Add post featured thumb data.
920
+ $context = $this->add_post_thumb_diff($context, $old_meta, $new_meta);
921
 
922
  // Page template is stored in _wp_page_template.
923
+ if (
924
+ isset($old_meta['_wp_page_template'][0]) &&
925
+ isset($new_meta['_wp_page_template'][0])
926
+ ) {
927
  /*
928
  Var is string with length 7: default
929
  Var is string with length 20: template-builder.php
930
  */
931
 
932
+ if (
933
+ $old_meta['_wp_page_template'][0] !==
934
+ $new_meta['_wp_page_template'][0]
935
+ ) {
936
  // Prev page template is different from new page template,
937
  // store template php file name.
938
+ $context['post_prev_page_template'] =
939
+ $old_meta['_wp_page_template'][0];
940
+ $context['post_new_page_template'] =
941
+ $new_meta['_wp_page_template'][0];
942
 
943
  $theme_templates = (array) $this->get_theme_templates();
944
 
945
+ if (
946
+ isset($theme_templates[$context['post_prev_page_template']])
947
+ ) {
948
+ $context['post_prev_page_template_name'] =
949
+ $theme_templates[$context['post_prev_page_template']];
950
  }
951
 
952
+ if (
953
+ isset($theme_templates[$context['post_new_page_template']])
954
+ ) {
955
+ $context['post_new_page_template_name'] =
956
+ $theme_templates[$context['post_new_page_template']];
957
  }
958
  }
959
  }
960
 
961
  // Remove fields that we have checked already and other that should be ignored.
962
+ foreach ($arr_meta_keys_to_ignore as $key_to_ignore) {
963
+ unset($old_meta[$key_to_ignore]);
964
+ unset($new_meta[$key_to_ignore]);
965
  }
966
 
967
  // Look for added custom fields.
968
+ foreach ($new_meta as $meta_key => $meta_value) {
969
+ if (!isset($old_meta[$meta_key])) {
970
+ $meta_changes['added'][$meta_key] = true;
 
971
  }
972
  }
973
 
974
+ // Look for removed meta.
975
+ // Does not work, if user clicks "delete" in edit screen then meta is removed using ajax.
976
  /*
977
  foreach ( $old_meta as $meta_key => $meta_value ) {
978
 
984
  */
985
 
986
  // Look for changed meta.
987
+ foreach ($old_meta as $meta_key => $meta_value) {
988
+ if (isset($new_meta[$meta_key])) {
989
+ if (
990
+ json_encode($old_meta[$meta_key]) !=
991
+ json_encode($new_meta[$meta_key])
992
+ ) {
993
+ $meta_changes['changed'][$meta_key] = true;
994
  }
995
  }
996
  }
997
 
998
+ if ($meta_changes['added']) {
999
+ $context['post_meta_added'] = count($meta_changes['added']);
1000
  }
1001
 
1002
+ if ($meta_changes['removed']) {
1003
+ $context['post_meta_removed'] = count($meta_changes['removed']);
1004
  }
1005
 
1006
+ if ($meta_changes['changed']) {
1007
+ $context['post_meta_changed'] = count($meta_changes['changed']);
1008
  }
1009
 
1010
+ // Check for changes in post visbility and post password usage and store in context.
1011
+ // publish = public
1012
+ // publish + post_password = password protected
1013
+ // private = post private
1014
+ $old_post_has_password = !empty($old_data->post_password);
1015
+ $old_post_password = $old_post_has_password
1016
+ ? $old_data->post_password
1017
+ : null;
1018
+ $old_post_status = isset($old_data->post_status)
1019
+ ? $old_data->post_status
1020
+ : null;
1021
+
1022
+ $new_post_has_password = !empty($new_data->post_password);
1023
+ $new_post_password = $new_post_has_password
1024
+ ? $new_data->post_password
1025
+ : null;
1026
+ $new_post_status = isset($new_data->post_status)
1027
+ ? $new_data->post_status
1028
+ : null;
1029
+
1030
+ if (
1031
+ false === $old_post_has_password &&
1032
+ 'publish' === $new_post_status &&
1033
+ $new_post_has_password
1034
+ ) {
1035
+ // If updated post is published and password is set and old post did not have password set
1036
+ // = post changed to be password protected.
1037
+ $context['post_password_protected'] = true;
1038
+ } elseif (
1039
+ $old_post_has_password &&
1040
+ 'publish' === $old_post_status &&
1041
+ false === $new_post_has_password &&
1042
+ 'publish' === $new_post_status
1043
+ ) {
1044
+ // Old post is publish and had password protection and new post is publish but no password
1045
+ // = post changed to be un-password protected
1046
+ $context['post_password_unprotected'] = true;
1047
+ } elseif (
1048
+ $old_post_has_password &&
1049
+ $new_post_has_password &&
1050
+ $old_post_password !== $new_post_password
1051
+ ) {
1052
+ // If old post had password and new post has password, but passwords are note same
1053
+ // = post has changed password.
1054
+ $context['post_password_changed'] = true;
1055
+ } elseif (
1056
+ 'private' === $new_post_status &&
1057
+ 'private' !== $old_post_status
1058
+ ) {
1059
+ // If new status is private and old is not
1060
+ // = post is changed to be private.
1061
+ $context['post_private'] = true;
1062
+ // Also check if password was set before.
1063
+ if ($old_post_has_password) {
1064
+ $context['post_password_unprotected'] = true;
1065
+ }
1066
+ }
1067
+
1068
+ // Todo: detect sticky.
1069
+ // Sticky is stored in option:
1070
+ // $sticky_posts = get_option('sticky_posts');
1071
 
1072
+ return $context;
1073
  }
1074
 
1075
  /**
1079
  *
1080
  * @since 2.0.29
1081
  */
1082
+ public function get_theme_templates()
1083
+ {
1084
  $theme = wp_get_theme();
1085
  $page_templates = array();
1086
 
1087
+ $files = (array) $theme->get_files('php', 1);
1088
 
1089
+ foreach ($files as $file => $full_path) {
1090
+ if (
1091
+ !preg_match(
1092
+ '|Template Name:(.*)$|mi',
1093
+ file_get_contents($full_path),
1094
+ $header
1095
+ )
1096
+ ) {
1097
  continue;
1098
  }
1099
+ $page_templates[$file] = _cleanup_header_comment($header[1]);
1100
  }
1101
 
1102
  return $page_templates;
 
1103
  }
1104
 
1105
  /**
1113
  * @param mixed $new_value New value.
1114
  * @return array
1115
  */
1116
+ public function add_diff($post_data_diff, $key, $old_value, $new_value)
1117
+ {
1118
+ if ($old_value != $new_value) {
1119
+ $post_data_diff[$key] = array(
 
1120
  'old' => $old_value,
1121
+ 'new' => $new_value
1122
  );
 
1123
  }
1124
 
1125
  return $post_data_diff;
 
1126
  }
1127
 
1128
  /**
1130
  *
1131
  * @param array $row Row data.
1132
  */
1133
+ public function getLogRowPlainTextOutput($row)
1134
+ {
1135
  $context = $row->context;
1136
+ $post_id = isset($context['post_id']) ? $context['post_id'] : 0;
1137
 
1138
  // Default to original log message.
1139
  $message = $row->message;
1141
  // Check if post still is available.
1142
  // It will return a WP_Post Object if post still is in system.
1143
  // If post is deleted from trash (not just moved there), then null is returned.
1144
+ $post = get_post($post_id);
1145
+ $post_is_available = is_a($post, 'WP_Post');
1146
 
1147
+ $message_key = isset($context['_message_key'])
1148
+ ? $context['_message_key']
1149
+ : null;
1150
 
1151
  // Try to get singular name.
1152
+ $post_type = isset($context['post_type']) ? $context['post_type'] : '';
1153
+ $post_type_obj = get_post_type_object($post_type);
1154
+ if (!is_null($post_type_obj)) {
1155
+ if (!empty($post_type_obj->labels->singular_name)) {
1156
+ $context['post_type'] = strtolower(
1157
+ $post_type_obj->labels->singular_name
1158
+ );
1159
  }
1160
  }
1161
 
1162
+ $context['edit_link'] = get_edit_post_link($post_id);
1163
 
1164
  // If post is not available any longer then we can't link to it, so keep plain message then.
1165
  // Also keep plain format if user is not allowed to edit post (edit link is empty).
1166
+ if ($post_is_available && $context['edit_link']) {
1167
+ if ('post_updated' == $message_key) {
1168
+ $message = __(
1169
+ 'Updated {post_type} <a href="{edit_link}">"{post_title}"</a>',
1170
+ 'simple-history'
1171
+ );
1172
+ } elseif ('post_deleted' == $message_key) {
1173
+ $message = __(
1174
+ 'Deleted {post_type} "{post_title}"',
1175
+ 'simple-history'
1176
+ );
1177
+ } elseif ('post_created' == $message_key) {
1178
+ $message = __(
1179
+ 'Created {post_type} <a href="{edit_link}">"{post_title}"</a>',
1180
+ 'simple-history'
1181
+ );
1182
+ } elseif ('post_trashed' == $message_key) {
1183
  // While in trash we can still get actions to delete or restore if we follow the edit link.
1184
+ $message = __(
1185
+ 'Moved {post_type} <a href="{edit_link}">"{post_title}"</a> to the trash',
1186
+ 'simple-history'
1187
+ );
1188
  }
1189
  } // End if().
1190
 
1191
+ $context['post_type'] = isset($context['post_type'])
1192
+ ? esc_html($context['post_type'])
1193
+ : '';
1194
+ $context['post_title'] = isset($context['post_title'])
1195
+ ? esc_html($context['post_title'])
1196
+ : '';
1197
 
1198
+ return $this->interpolate($message, $context, $row);
1199
  }
1200
 
1201
  /**
1203
  *
1204
  * @param array $row Row data.
1205
  */
1206
+ public function getLogRowDetailsOutput($row)
1207
+ {
1208
  $context = $row->context;
1209
  $message_key = $context['_message_key'];
 
1210
 
1211
  $out = '';
1212
 
1213
+ if ('post_updated' == $message_key) {
 
1214
  // Check for keys like "post_prev_post_title" and "post_new_post_title".
1215
  $diff_table_output = '';
1216
  $has_diff_values = false;
1217
 
1218
+ foreach ($context as $key => $val) {
1219
+ if (strpos($key, 'post_prev_') !== false) {
 
 
1220
  // Old value exists, new value must also exist for diff to be calculates.
1221
+ $key_to_diff = substr($key, strlen('post_prev_'));
1222
 
1223
  $key_for_new_val = "post_new_{$key_to_diff}";
1224
 
1225
+ if (isset($context[$key_for_new_val])) {
1226
+ $post_old_value = $context[$key];
1227
+ $post_new_value = $context[$key_for_new_val];
1228
+ if ($post_old_value != $post_new_value) {
 
 
1229
  // Different diffs for different keys.
1230
+ if ('post_title' == $key_to_diff) {
 
1231
  $has_diff_values = true;
1232
 
1233
  $diff_table_output .= sprintf(
1234
  '<tr><td>%1$s</td><td>%2$s</td></tr>',
1235
+ __('Title', 'simple-history'),
1236
+ simple_history_text_diff(
1237
+ $post_old_value,
1238
+ $post_new_value
1239
+ )
1240
  );
1241
+ } elseif ('post_content' == $key_to_diff) {
 
 
1242
  // Problem: to much text/content.
1243
  // Risks to fill the visual output.
1244
  // Maybe solution: use own diff function, that uses none or few context lines.
1245
  $has_diff_values = true;
1246
+ $key_text_diff = simple_history_text_diff(
1247
+ $post_old_value,
1248
+ $post_new_value
1249
+ );
1250
 
1251
+ if ($key_text_diff) {
1252
  $diff_table_output .= sprintf(
1253
  '<tr><td>%1$s</td><td>%2$s</td></tr>',
1254
+ __('Content', 'simple-history'),
1255
  $key_text_diff
1256
  );
1257
  }
1258
+ } elseif ('post_status' == $key_to_diff) {
 
 
1259
  $has_diff_values = true;
1260
  $diff_table_output .= sprintf(
1261
  '<tr>
1262
  <td>%1$s</td>
1263
  <td>Changed from %2$s to %3$s</td>
1264
  </tr>',
1265
+ __('Status', 'simple-history'),
1266
+ esc_html($post_old_value),
1267
+ esc_html($post_new_value)
1268
  );
1269
+ } elseif ('post_date' == $key_to_diff) {
 
 
1270
  $has_diff_values = true;
1271
 
1272
  // $diff = new FineDiff($post_old_value, $post_new_value, FineDiff::$wordGranularity);
1275
  <td>%1$s</td>
1276
  <td>Changed from %2$s to %3$s</td>
1277
  </tr>',
1278
+ __('Publish date', 'simple-history'),
1279
+ esc_html($post_old_value),
1280
+ esc_html($post_new_value)
1281
  );
1282
+ } elseif ('post_name' == $key_to_diff) {
 
 
1283
  $has_diff_values = true;
1284
 
1285
  // $diff = new FineDiff($post_old_value, $post_new_value, FineDiff::$wordGranularity);
1288
  <td>%1$s</td>
1289
  <td>%2$s</td>
1290
  </tr>',
1291
+ __('Permalink', 'simple-history'),
1292
+ simple_history_text_diff(
1293
+ $post_old_value,
1294
+ $post_new_value
1295
+ )
1296
  );
1297
+ } elseif ('comment_status' == $key_to_diff) {
 
 
1298
  $has_diff_values = true;
1299
 
1300
  // $diff = new FineDiff($post_old_value, $post_new_value, FineDiff::$wordGranularity);
1303
  <td>%1$s</td>
1304
  <td>Changed from %2$s to %3$s</td>
1305
  </tr>',
1306
+ __('Comment status', 'simple-history'),
1307
+ esc_html($post_old_value),
1308
+ esc_html($post_new_value)
1309
  );
1310
+ } elseif ('post_author' == $key_to_diff) {
 
 
1311
  $has_diff_values = true;
1312
 
1313
  // wp post edit screen uses display_name so we should use it too.
1314
+ if (
1315
+ isset(
1316
+ $context[
1317
+ 'post_prev_post_author/display_name'
1318
+ ]
1319
+ ) &&
1320
+ isset(
1321
+ $context[
1322
+ 'post_new_post_author/display_name'
1323
+ ]
1324
+ )
1325
+ ) {
1326
+ $prev_user_display_name =
1327
+ $context[
1328
+ 'post_prev_post_author/display_name'
1329
+ ];
1330
+ $new_user_display_name =
1331
+ $context[
1332
+ 'post_new_post_author/display_name'
1333
+ ];
1334
+
1335
+ $prev_user_user_email =
1336
+ $context[
1337
+ 'post_prev_post_author/user_email'
1338
+ ];
1339
+ $new_user_user_email =
1340
+ $context[
1341
+ 'post_new_post_author/user_email'
1342
+ ];
1343
 
1344
  $diff_table_output .= sprintf(
1345
  '<tr>
1346
  <td>%1$s</td>
1347
  <td>%2$s</td>
1348
  </tr>',
1349
+ __('Author', 'simple-history'),
1350
  $this->interpolate(
1351
+ __(
1352
+ 'Changed from {prev_user_display_name} ({prev_user_email}) to {new_user_display_name} ({new_user_email})',
1353
+ 'simple-history'
1354
+ ),
1355
  array(
1356
+ 'prev_user_display_name' => esc_html(
1357
+ $prev_user_display_name
1358
+ ),
1359
+ 'prev_user_email' => esc_html(
1360
+ $prev_user_user_email
1361
+ ),
1362
+ 'new_user_display_name' => esc_html(
1363
+ $new_user_display_name
1364
+ ),
1365
+ 'new_user_email' => esc_html(
1366
+ $new_user_user_email
1367
+ )
1368
  )
1369
  )
1370
  );
 
1371
  }
1372
+ } elseif ('page_template' == $key_to_diff) {
 
1373
  // page template filename.
1374
+ $prev_page_template =
1375
+ $context['post_prev_page_template'];
1376
+ $new_page_template =
1377
+ $context['post_new_page_template'];
1378
 
1379
  // page template name, should exist, but I guess someone could have deleted a template
1380
  // and after that change the template for a post.
1381
+ $prev_page_template_name = isset(
1382
+ $context['post_prev_page_template_name']
1383
+ )
1384
+ ? $context['post_prev_page_template_name']
1385
+ : '';
1386
+ $new_page_template_name = isset(
1387
+ $context['post_new_page_template_name']
1388
+ )
1389
+ ? $context['post_new_page_template_name']
1390
+ : '';
1391
 
1392
  // If prev och new template is "default" then use that as name.
1393
+ if (
1394
+ 'default' == $prev_page_template &&
1395
+ !$prev_page_template_name
1396
+ ) {
1397
  $prev_page_template_name = $prev_page_template;
1398
+ } elseif (
1399
+ 'default' == $new_page_template &&
1400
+ !$new_page_template_name
1401
+ ) {
1402
  $new_page_template_name = $new_page_template;
1403
  }
1404
 
1405
+ // @TODO: translate template names
1406
+ // $value = translate( $value, $this->get('TextDomain') );
1407
+ $message = __(
1408
+ 'Changed from {prev_page_template} to {new_page_template}',
1409
+ 'simple-history'
1410
+ );
1411
+ if (
1412
+ $prev_page_template_name &&
1413
+ $new_page_template_name
1414
+ ) {
1415
+ $message = __(
1416
+ 'Changed from "{prev_page_template_name}" to "{new_page_template_name}"',
1417
+ 'simple-history'
1418
+ );
1419
  }
1420
 
1421
  $diff_table_output .= sprintf(
1423
  <td>%1$s</td>
1424
  <td>%2$s</td>
1425
  </tr>',
1426
+ __('Template', 'simple-history'),
1427
+ $this->interpolate($message, array(
1428
+ 'prev_page_template' =>
1429
+ '<code>' .
1430
+ esc_html($prev_page_template) .
1431
+ '</code>',
1432
+ 'new_page_template' =>
1433
+ '<code>' .
1434
+ esc_html($new_page_template) .
1435
+ '</code>',
1436
+ 'prev_page_template_name' => esc_html(
1437
+ $prev_page_template_name
1438
+ ),
1439
+ 'new_page_template_name' => esc_html(
1440
+ $new_page_template_name
1441
  )
1442
+ ))
1443
  );
1444
+ } // End if().
1445
+ } // End if().
1446
+ } // End if().
1447
+ } // End if().
 
1448
  } // End foreach().
1449
 
1450
+ if (
1451
+ isset($context['post_meta_added']) ||
1452
+ isset($context['post_meta_removed']) ||
1453
+ isset($context['post_meta_changed'])
1454
+ ) {
1455
  $meta_changed_out = '';
1456
  $has_diff_values = true;
1457
 
1458
+ if (isset($context['post_meta_added'])) {
1459
+ $meta_changed_out .=
1460
+ "<span class='SimpleHistoryLogitem__inlineDivided'>" .
1461
+ (int) $context['post_meta_added'] .
1462
+ ' added</span> ';
1463
  }
1464
 
1465
+ if (isset($context['post_meta_removed'])) {
1466
+ $meta_changed_out .=
1467
+ "<span class='SimpleHistoryLogitem__inlineDivided'>" .
1468
+ (int) $context['post_meta_removed'] .
1469
+ ' removed</span> ';
1470
  }
1471
 
1472
+ if (isset($context['post_meta_changed'])) {
1473
+ $meta_changed_out .=
1474
+ "<span class='SimpleHistoryLogitem__inlineDivided'>" .
1475
+ (int) $context['post_meta_changed'] .
1476
+ ' changed</span> ';
1477
  }
1478
 
1479
  $diff_table_output .= sprintf(
1481
  <td>%1$s</td>
1482
  <td>%2$s</td>
1483
  </tr>',
1484
+ esc_html(__('Custom fields', 'simple-history')),
1485
  $meta_changed_out
1486
  );
 
1487
  }
1488
 
1489
  /*
1502
  // Changed post thumb/featued image.
1503
  // post_prev_thumb, int of prev thumb, empty if not prev thumb.
1504
  // post_new_thumb, int of new thumb, empty if no new thumb.
1505
+ $diff_table_output .= $this->getLogRowDetailsOutputForPostThumb(
1506
+ $context
1507
+ );
1508
 
1509
  /**
1510
  * Modify the formatted diff output of a saved/modified post
1513
  * @param array $context
1514
  * @return string
1515
  */
1516
+ $diff_table_output = apply_filters(
1517
+ 'simple_history/post_logger/post_updated/diff_table_output',
1518
+ $diff_table_output,
1519
+ $context
1520
+ );
1521
 
1522
+ if ($has_diff_values || $diff_table_output) {
1523
+ $diff_table_output =
1524
+ '<table class="SimpleHistoryLogitem__keyValueTable">' .
1525
+ $diff_table_output .
1526
+ '</table>';
1527
  }
1528
 
1529
  $out .= $diff_table_output;
1530
+ } // End if().
 
1531
 
1532
  return $out;
 
1533
  }
1534
 
 
1535
  /**
1536
  * Modify RSS links to they go directly to the correct post in wp admin
1537
  *
1539
  * @param string $link Link.
1540
  * @param array $row Row.
1541
  */
1542
+ public function filter_rss_item_link($link, $row)
1543
+ {
1544
+ if ($row->logger != $this->slug) {
1545
  return $link;
1546
  }
1547
 
1548
+ if (isset($row->context['post_id'])) {
1549
+ $permalink = add_query_arg(
1550
+ array(
1551
+ 'action' => 'edit',
1552
+ 'post' => $row->context['post_id']
1553
+ ),
1554
+ admin_url('post.php')
1555
+ );
1556
 
1557
+ if ($permalink) {
1558
  $link = $permalink;
1559
  }
1560
  }
1561
 
1562
  return $link;
 
1563
  }
1564
 
1565
  /**
1570
  * @param array $new_meta New meta.
1571
  * @return array Maybe modifed context.
1572
  */
1573
+ public function add_post_thumb_diff($context, $old_meta, $new_meta)
1574
+ {
1575
  $post_thumb_modified = false;
1576
  $prev_post_thumb_id = null;
1577
  $new_post_thumb_id = null;
1578
 
1579
  // If it was changed from one image to another.
1580
+ if (
1581
+ isset($old_meta['_thumbnail_id'][0]) &&
1582
+ isset($new_meta['_thumbnail_id'][0])
1583
+ ) {
1584
+ if (
1585
+ $old_meta['_thumbnail_id'][0] !== $new_meta['_thumbnail_id'][0]
1586
+ ) {
1587
  $post_thumb_modified = true;
1588
  $prev_post_thumb_id = $old_meta['_thumbnail_id'][0];
1589
  $new_post_thumb_id = $new_meta['_thumbnail_id'][0];
1590
  }
1591
  } else {
1592
  // Featured image id did not exist on both new and old data. But on any?
1593
+ if (isset($old_meta['_thumbnail_id'][0])) {
1594
  $prev_post_thumb_id = $old_meta['_thumbnail_id'][0];
1595
+ } elseif (isset($new_meta['_thumbnail_id'][0])) {
1596
  $new_post_thumb_id = $new_meta['_thumbnail_id'][0];
1597
  }
1598
  }
1599
 
1600
+ if ($prev_post_thumb_id) {
1601
  $context['post_prev_thumb_id'] = $prev_post_thumb_id;
1602
+ $context['post_prev_thumb_title'] = get_the_title(
1603
+ $prev_post_thumb_id
1604
+ );
1605
  }
1606
 
1607
+ if ($new_post_thumb_id) {
1608
  $context['post_new_thumb_id'] = $new_post_thumb_id;
1609
+ $context['post_new_thumb_title'] = get_the_title(
1610
+ $new_post_thumb_id
1611
+ );
1612
  }
1613
 
1614
  return $context;
1620
  * @param array $context Context that may contains prev- and new thumb ids.
1621
  * @return string HTML to be used in keyvale table.
1622
  */
1623
+ private function getLogRowDetailsOutputForPostThumb($context = null)
1624
+ {
1625
  $out = '';
1626
 
1627
+ if (
1628
+ !empty($context['post_prev_thumb_id']) ||
1629
+ !empty($context['post_new_thumb_id'])
1630
+ ) {
1631
  // Check if images still exists and if so get their thumbnails.
1632
+ $prev_thumb_id = empty($context['post_prev_thumb_id'])
1633
+ ? null
1634
+ : $context['post_prev_thumb_id'];
1635
+ $new_thumb_id = empty($context['post_new_thumb_id'])
1636
+ ? null
1637
+ : $context['post_new_thumb_id'];
1638
+ $post_new_thumb_title = empty($context['post_new_thumb_title'])
1639
+ ? null
1640
+ : $context['post_new_thumb_title'];
1641
+ $post_prev_thumb_title = empty($context['post_prev_thumb_title'])
1642
+ ? null
1643
+ : $context['post_prev_thumb_title'];
1644
+
1645
+ $prev_attached_file = get_attached_file($prev_thumb_id);
1646
+ $prev_thumb_src = wp_get_attachment_image_src(
1647
+ $prev_thumb_id,
1648
+ 'small'
1649
+ );
1650
 
1651
+ $new_attached_file = get_attached_file($new_thumb_id);
1652
+ $new_thumb_src = wp_get_attachment_image_src(
1653
+ $new_thumb_id,
1654
+ 'small'
1655
+ );
1656
 
1657
  $prev_thumb_html = '';
1658
+ if (file_exists($prev_attached_file) && $prev_thumb_src) {
1659
  $prev_thumb_html = sprintf(
1660
  '
1661
  <div>%2$s</div>
1664
  </div>
1665
  ',
1666
  $prev_thumb_src[0],
1667
+ esc_html($post_prev_thumb_title)
1668
  );
1669
  } else {
1670
  // Fallback if image does not exist.
1671
  $prev_thumb_html = sprintf(
1672
  '<div>%1$s</div>',
1673
+ esc_html($post_prev_thumb_title)
1674
  );
1675
  }
1676
 
1677
  $new_thumb_html = '';
1678
+ if (file_exists($new_attached_file) && $new_thumb_src) {
1679
  $new_thumb_html = sprintf(
1680
  '
1681
  <div>%2$s</div>
1684
  </div>
1685
  ',
1686
  $new_thumb_src[0],
1687
+ esc_html($post_new_thumb_title)
1688
  );
1689
  } else {
1690
  // Fallback if image does not exist.
1691
  $prev_thumb_html = sprintf(
1692
  '<div>%1$s</div>',
1693
+ esc_html($post_new_thumb_title)
1694
  );
1695
  }
1696
 
1717
 
1718
  </td>
1719
  </tr>',
1720
+ esc_html(__('Featured image', 'simple-history')), // 1
1721
  $prev_thumb_html, // 2
1722
  $new_thumb_html // 3
1723
  );
1729
  /**
1730
  * Output CSS for diff output
1731
  */
1732
+ public function adminCSS()
1733
+ {
1734
  ?>
1735
  <style>
1736
  .SimpleHistory__diff.SimpleHistory__diff {
1750
  </style>
1751
  <?php
1752
  }
 
1753
  }
package-lock.json ADDED
@@ -0,0 +1,1303 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "simplehistory",
3
+ "version": "0.0.1",
4
+ "lockfileVersion": 1,
5
+ "requires": true,
6
+ "dependencies": {
7
+ "@prettier/plugin-php": {
8
+ "version": "0.10.2",
9
+ "resolved": "https://registry.npmjs.org/@prettier/plugin-php/-/plugin-php-0.10.2.tgz",
10
+ "integrity": "sha512-FCzNR2kqlS9YV81JguX4vYnpwFn6cOlLwUZaEB0jIjPcrEgqqBwk6KSERTA5cE+lX5Ynip5rkV1hydGufwyJ7A==",
11
+ "requires": {
12
+ "linguist-languages": "^6.3.0",
13
+ "mem": "^4.0.0",
14
+ "php-parser": "github:glayzzle/php-parser#71485979b688d12fb130d3e853fdc00348671e00"
15
+ }
16
+ },
17
+ "@types/normalize-package-data": {
18
+ "version": "2.4.0",
19
+ "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
20
+ "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA=="
21
+ },
22
+ "abbrev": {
23
+ "version": "1.1.1",
24
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
25
+ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
26
+ "dev": true
27
+ },
28
+ "ansi-regex": {
29
+ "version": "2.1.1",
30
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
31
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
32
+ "dev": true
33
+ },
34
+ "ansi-styles": {
35
+ "version": "2.2.1",
36
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
37
+ "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
38
+ "dev": true
39
+ },
40
+ "argparse": {
41
+ "version": "0.1.16",
42
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz",
43
+ "integrity": "sha1-z9AeD7uj1srtBJ+9dY1A9lGW9Xw=",
44
+ "dev": true,
45
+ "requires": {
46
+ "underscore": "~1.7.0",
47
+ "underscore.string": "~2.4.0"
48
+ },
49
+ "dependencies": {
50
+ "underscore.string": {
51
+ "version": "2.4.0",
52
+ "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz",
53
+ "integrity": "sha1-jN2PusTi0uoefi6Al8QvRCKA+Fs=",
54
+ "dev": true
55
+ }
56
+ }
57
+ },
58
+ "array-differ": {
59
+ "version": "1.0.0",
60
+ "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz",
61
+ "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=",
62
+ "dev": true
63
+ },
64
+ "array-union": {
65
+ "version": "1.0.2",
66
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
67
+ "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
68
+ "requires": {
69
+ "array-uniq": "^1.0.1"
70
+ }
71
+ },
72
+ "array-uniq": {
73
+ "version": "1.0.3",
74
+ "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
75
+ "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY="
76
+ },
77
+ "arrify": {
78
+ "version": "1.0.1",
79
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
80
+ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0="
81
+ },
82
+ "async": {
83
+ "version": "0.1.22",
84
+ "resolved": "https://registry.npmjs.org/async/-/async-0.1.22.tgz",
85
+ "integrity": "sha1-D8GqoIig4+8Ovi2IMbqw3PiEUGE=",
86
+ "dev": true
87
+ },
88
+ "balanced-match": {
89
+ "version": "1.0.0",
90
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
91
+ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
92
+ },
93
+ "brace-expansion": {
94
+ "version": "1.1.11",
95
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
96
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
97
+ "requires": {
98
+ "balanced-match": "^1.0.0",
99
+ "concat-map": "0.0.1"
100
+ }
101
+ },
102
+ "caller-callsite": {
103
+ "version": "2.0.0",
104
+ "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
105
+ "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=",
106
+ "requires": {
107
+ "callsites": "^2.0.0"
108
+ }
109
+ },
110
+ "caller-path": {
111
+ "version": "2.0.0",
112
+ "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz",
113
+ "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=",
114
+ "requires": {
115
+ "caller-callsite": "^2.0.0"
116
+ }
117
+ },
118
+ "callsites": {
119
+ "version": "2.0.0",
120
+ "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
121
+ "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA="
122
+ },
123
+ "chalk": {
124
+ "version": "1.1.3",
125
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
126
+ "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
127
+ "dev": true,
128
+ "requires": {
129
+ "ansi-styles": "^2.2.1",
130
+ "escape-string-regexp": "^1.0.2",
131
+ "has-ansi": "^2.0.0",
132
+ "strip-ansi": "^3.0.0",
133
+ "supports-color": "^2.0.0"
134
+ }
135
+ },
136
+ "ci-info": {
137
+ "version": "2.0.0",
138
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
139
+ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="
140
+ },
141
+ "coffee-script": {
142
+ "version": "1.3.3",
143
+ "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.3.3.tgz",
144
+ "integrity": "sha1-FQ1rTLUiiUNp7+1qIQHCC8f0pPQ=",
145
+ "dev": true
146
+ },
147
+ "color-convert": {
148
+ "version": "1.9.3",
149
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
150
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
151
+ "requires": {
152
+ "color-name": "1.1.3"
153
+ }
154
+ },
155
+ "color-name": {
156
+ "version": "1.1.3",
157
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
158
+ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
159
+ },
160
+ "colors": {
161
+ "version": "0.6.2",
162
+ "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz",
163
+ "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=",
164
+ "dev": true
165
+ },
166
+ "concat-map": {
167
+ "version": "0.0.1",
168
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
169
+ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
170
+ },
171
+ "cosmiconfig": {
172
+ "version": "5.2.0",
173
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.0.tgz",
174
+ "integrity": "sha512-nxt+Nfc3JAqf4WIWd0jXLjTJZmsPLrA9DDc4nRw2KFJQJK7DNooqSXrNI7tzLG50CF8axczly5UV929tBmh/7g==",
175
+ "requires": {
176
+ "import-fresh": "^2.0.0",
177
+ "is-directory": "^0.3.1",
178
+ "js-yaml": "^3.13.0",
179
+ "parse-json": "^4.0.0"
180
+ },
181
+ "dependencies": {
182
+ "argparse": {
183
+ "version": "1.0.10",
184
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
185
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
186
+ "requires": {
187
+ "sprintf-js": "~1.0.2"
188
+ }
189
+ },
190
+ "esprima": {
191
+ "version": "4.0.1",
192
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
193
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
194
+ },
195
+ "js-yaml": {
196
+ "version": "3.13.1",
197
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
198
+ "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
199
+ "requires": {
200
+ "argparse": "^1.0.7",
201
+ "esprima": "^4.0.0"
202
+ }
203
+ }
204
+ }
205
+ },
206
+ "cross-spawn": {
207
+ "version": "6.0.5",
208
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
209
+ "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
210
+ "requires": {
211
+ "nice-try": "^1.0.4",
212
+ "path-key": "^2.0.1",
213
+ "semver": "^5.5.0",
214
+ "shebang-command": "^1.2.0",
215
+ "which": "^1.2.9"
216
+ },
217
+ "dependencies": {
218
+ "which": {
219
+ "version": "1.3.1",
220
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
221
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
222
+ "requires": {
223
+ "isexe": "^2.0.0"
224
+ }
225
+ }
226
+ }
227
+ },
228
+ "date-time": {
229
+ "version": "1.1.0",
230
+ "resolved": "https://registry.npmjs.org/date-time/-/date-time-1.1.0.tgz",
231
+ "integrity": "sha1-GIdtC9pMGf5w3Tv0sDTygbEqQLY=",
232
+ "dev": true,
233
+ "requires": {
234
+ "time-zone": "^0.1.0"
235
+ }
236
+ },
237
+ "dateformat": {
238
+ "version": "1.0.2-1.2.3",
239
+ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.2-1.2.3.tgz",
240
+ "integrity": "sha1-sCIMAt6YYXQztyhRz0fePfLNvuk=",
241
+ "dev": true
242
+ },
243
+ "encoding": {
244
+ "version": "0.1.12",
245
+ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
246
+ "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=",
247
+ "dev": true,
248
+ "requires": {
249
+ "iconv-lite": "~0.4.13"
250
+ },
251
+ "dependencies": {
252
+ "iconv-lite": {
253
+ "version": "0.4.24",
254
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
255
+ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
256
+ "dev": true,
257
+ "requires": {
258
+ "safer-buffer": ">= 2.1.2 < 3"
259
+ }
260
+ }
261
+ }
262
+ },
263
+ "end-of-stream": {
264
+ "version": "1.4.1",
265
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
266
+ "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
267
+ "requires": {
268
+ "once": "^1.4.0"
269
+ }
270
+ },
271
+ "error-ex": {
272
+ "version": "1.3.2",
273
+ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
274
+ "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
275
+ "requires": {
276
+ "is-arrayish": "^0.2.1"
277
+ }
278
+ },
279
+ "escape-string-regexp": {
280
+ "version": "1.0.5",
281
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
282
+ "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
283
+ },
284
+ "esprima": {
285
+ "version": "1.0.4",
286
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz",
287
+ "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=",
288
+ "dev": true
289
+ },
290
+ "eventemitter2": {
291
+ "version": "0.4.14",
292
+ "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz",
293
+ "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=",
294
+ "dev": true
295
+ },
296
+ "execa": {
297
+ "version": "1.0.0",
298
+ "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
299
+ "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
300
+ "requires": {
301
+ "cross-spawn": "^6.0.0",
302
+ "get-stream": "^4.0.0",
303
+ "is-stream": "^1.1.0",
304
+ "npm-run-path": "^2.0.0",
305
+ "p-finally": "^1.0.0",
306
+ "signal-exit": "^3.0.0",
307
+ "strip-eof": "^1.0.0"
308
+ }
309
+ },
310
+ "exit": {
311
+ "version": "0.1.2",
312
+ "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
313
+ "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
314
+ "dev": true
315
+ },
316
+ "figures": {
317
+ "version": "1.7.0",
318
+ "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
319
+ "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
320
+ "dev": true,
321
+ "requires": {
322
+ "escape-string-regexp": "^1.0.5",
323
+ "object-assign": "^4.1.0"
324
+ }
325
+ },
326
+ "find-up": {
327
+ "version": "3.0.0",
328
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
329
+ "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
330
+ "requires": {
331
+ "locate-path": "^3.0.0"
332
+ }
333
+ },
334
+ "findup-sync": {
335
+ "version": "0.1.3",
336
+ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.1.3.tgz",
337
+ "integrity": "sha1-fz56l7gjksZTvwZYm9hRkOk8NoM=",
338
+ "dev": true,
339
+ "requires": {
340
+ "glob": "~3.2.9",
341
+ "lodash": "~2.4.1"
342
+ },
343
+ "dependencies": {
344
+ "glob": {
345
+ "version": "3.2.11",
346
+ "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz",
347
+ "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=",
348
+ "dev": true,
349
+ "requires": {
350
+ "inherits": "2",
351
+ "minimatch": "0.3"
352
+ }
353
+ },
354
+ "lodash": {
355
+ "version": "2.4.2",
356
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz",
357
+ "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=",
358
+ "dev": true
359
+ },
360
+ "minimatch": {
361
+ "version": "0.3.0",
362
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz",
363
+ "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=",
364
+ "dev": true,
365
+ "requires": {
366
+ "lru-cache": "2",
367
+ "sigmund": "~1.0.0"
368
+ }
369
+ }
370
+ }
371
+ },
372
+ "get-stdin": {
373
+ "version": "7.0.0",
374
+ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz",
375
+ "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ=="
376
+ },
377
+ "get-stream": {
378
+ "version": "4.1.0",
379
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
380
+ "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
381
+ "requires": {
382
+ "pump": "^3.0.0"
383
+ }
384
+ },
385
+ "getobject": {
386
+ "version": "0.1.0",
387
+ "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz",
388
+ "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=",
389
+ "dev": true
390
+ },
391
+ "gettext-parser": {
392
+ "version": "0.2.0",
393
+ "resolved": "https://registry.npmjs.org/gettext-parser/-/gettext-parser-0.2.0.tgz",
394
+ "integrity": "sha1-VBuZ4nIORgFjBVxk6ZsUIuPplfU=",
395
+ "dev": true,
396
+ "requires": {
397
+ "encoding": "~0.1"
398
+ }
399
+ },
400
+ "glob": {
401
+ "version": "3.1.21",
402
+ "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz",
403
+ "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=",
404
+ "dev": true,
405
+ "requires": {
406
+ "graceful-fs": "~1.2.0",
407
+ "inherits": "1",
408
+ "minimatch": "~0.2.11"
409
+ },
410
+ "dependencies": {
411
+ "inherits": {
412
+ "version": "1.0.2",
413
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz",
414
+ "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=",
415
+ "dev": true
416
+ }
417
+ }
418
+ },
419
+ "graceful-fs": {
420
+ "version": "1.2.3",
421
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz",
422
+ "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=",
423
+ "dev": true
424
+ },
425
+ "grunt": {
426
+ "version": "0.4.5",
427
+ "resolved": "https://registry.npmjs.org/grunt/-/grunt-0.4.5.tgz",
428
+ "integrity": "sha1-VpN81RlDJK3/bSB2MYMqnWuk5/A=",
429
+ "dev": true,
430
+ "requires": {
431
+ "async": "~0.1.22",
432
+ "coffee-script": "~1.3.3",
433
+ "colors": "~0.6.2",
434
+ "dateformat": "1.0.2-1.2.3",
435
+ "eventemitter2": "~0.4.13",
436
+ "exit": "~0.1.1",
437
+ "findup-sync": "~0.1.2",
438
+ "getobject": "~0.1.0",
439
+ "glob": "~3.1.21",
440
+ "grunt-legacy-log": "~0.1.0",
441
+ "grunt-legacy-util": "~0.2.0",
442
+ "hooker": "~0.2.3",
443
+ "iconv-lite": "~0.2.11",
444
+ "js-yaml": "~2.0.5",
445
+ "lodash": "~0.9.2",
446
+ "minimatch": "~0.2.12",
447
+ "nopt": "~1.0.10",
448
+ "rimraf": "~2.2.8",
449
+ "underscore.string": "~2.2.1",
450
+ "which": "~1.0.5"
451
+ }
452
+ },
453
+ "grunt-legacy-log": {
454
+ "version": "0.1.3",
455
+ "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-0.1.3.tgz",
456
+ "integrity": "sha1-7ClCboAwIa9ZAp+H0vnNczWgVTE=",
457
+ "dev": true,
458
+ "requires": {
459
+ "colors": "~0.6.2",
460
+ "grunt-legacy-log-utils": "~0.1.1",
461
+ "hooker": "~0.2.3",
462
+ "lodash": "~2.4.1",
463
+ "underscore.string": "~2.3.3"
464
+ },
465
+ "dependencies": {
466
+ "lodash": {
467
+ "version": "2.4.2",
468
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz",
469
+ "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=",
470
+ "dev": true
471
+ },
472
+ "underscore.string": {
473
+ "version": "2.3.3",
474
+ "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz",
475
+ "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=",
476
+ "dev": true
477
+ }
478
+ }
479
+ },
480
+ "grunt-legacy-log-utils": {
481
+ "version": "0.1.1",
482
+ "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-0.1.1.tgz",
483
+ "integrity": "sha1-wHBrndkGThFvNvI/5OawSGcsD34=",
484
+ "dev": true,
485
+ "requires": {
486
+ "colors": "~0.6.2",
487
+ "lodash": "~2.4.1",
488
+ "underscore.string": "~2.3.3"
489
+ },
490
+ "dependencies": {
491
+ "lodash": {
492
+ "version": "2.4.2",
493
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz",
494
+ "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=",
495
+ "dev": true
496
+ },
497
+ "underscore.string": {
498
+ "version": "2.3.3",
499
+ "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz",
500
+ "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=",
501
+ "dev": true
502
+ }
503
+ }
504
+ },
505
+ "grunt-legacy-util": {
506
+ "version": "0.2.0",
507
+ "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-0.2.0.tgz",
508
+ "integrity": "sha1-kzJIhNv343qf98Am3/RR2UqeVUs=",
509
+ "dev": true,
510
+ "requires": {
511
+ "async": "~0.1.22",
512
+ "exit": "~0.1.1",
513
+ "getobject": "~0.1.0",
514
+ "hooker": "~0.2.3",
515
+ "lodash": "~0.9.2",
516
+ "underscore.string": "~2.2.1",
517
+ "which": "~1.0.5"
518
+ }
519
+ },
520
+ "grunt-pot": {
521
+ "version": "0.2.1",
522
+ "resolved": "https://registry.npmjs.org/grunt-pot/-/grunt-pot-0.2.1.tgz",
523
+ "integrity": "sha1-eCFIGpkTxY11K22N9XV7ZRz6Ous=",
524
+ "dev": true
525
+ },
526
+ "grunt-wp-i18n": {
527
+ "version": "0.4.9",
528
+ "resolved": "https://registry.npmjs.org/grunt-wp-i18n/-/grunt-wp-i18n-0.4.9.tgz",
529
+ "integrity": "sha1-6j7kmnp4hrk2kEhprffZZ/YWbsE=",
530
+ "dev": true,
531
+ "requires": {
532
+ "async": "~0.2.10",
533
+ "gettext-parser": "~0.2.0",
534
+ "grunt": "~0.4.2",
535
+ "underscore": "~1.5.2",
536
+ "underscore.string": "~2.3.3"
537
+ },
538
+ "dependencies": {
539
+ "async": {
540
+ "version": "0.2.10",
541
+ "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
542
+ "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=",
543
+ "dev": true
544
+ },
545
+ "underscore": {
546
+ "version": "1.5.2",
547
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.5.2.tgz",
548
+ "integrity": "sha1-EzXF5PXm0zu7SwBrqMhqAPVW3gg=",
549
+ "dev": true
550
+ },
551
+ "underscore.string": {
552
+ "version": "2.3.3",
553
+ "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz",
554
+ "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=",
555
+ "dev": true
556
+ }
557
+ }
558
+ },
559
+ "has-ansi": {
560
+ "version": "2.0.0",
561
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
562
+ "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
563
+ "dev": true,
564
+ "requires": {
565
+ "ansi-regex": "^2.0.0"
566
+ }
567
+ },
568
+ "has-flag": {
569
+ "version": "3.0.0",
570
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
571
+ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
572
+ },
573
+ "hooker": {
574
+ "version": "0.2.3",
575
+ "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz",
576
+ "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=",
577
+ "dev": true
578
+ },
579
+ "hosted-git-info": {
580
+ "version": "2.7.1",
581
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz",
582
+ "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w=="
583
+ },
584
+ "husky": {
585
+ "version": "2.1.0",
586
+ "resolved": "https://registry.npmjs.org/husky/-/husky-2.1.0.tgz",
587
+ "integrity": "sha512-FHsqdIJPmQX/89Xg/761RMFCPSNNG2eiQMxChGP081NTohHexEuu/4nYh5m4TcFKq4xm+DqaGp8J/EUnkzL1Aw==",
588
+ "requires": {
589
+ "cosmiconfig": "^5.2.0",
590
+ "execa": "^1.0.0",
591
+ "find-up": "^3.0.0",
592
+ "get-stdin": "^7.0.0",
593
+ "is-ci": "^2.0.0",
594
+ "pkg-dir": "^4.1.0",
595
+ "please-upgrade-node": "^3.1.1",
596
+ "read-pkg": "^5.0.0",
597
+ "run-node": "^1.0.0",
598
+ "slash": "^2.0.0"
599
+ }
600
+ },
601
+ "iconv-lite": {
602
+ "version": "0.2.11",
603
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz",
604
+ "integrity": "sha1-HOYKOleGSiktEyH/RgnKS7llrcg=",
605
+ "dev": true
606
+ },
607
+ "ignore": {
608
+ "version": "3.3.10",
609
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz",
610
+ "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug=="
611
+ },
612
+ "import-fresh": {
613
+ "version": "2.0.0",
614
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
615
+ "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=",
616
+ "requires": {
617
+ "caller-path": "^2.0.0",
618
+ "resolve-from": "^3.0.0"
619
+ }
620
+ },
621
+ "inherits": {
622
+ "version": "2.0.3",
623
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
624
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
625
+ "dev": true
626
+ },
627
+ "is-arrayish": {
628
+ "version": "0.2.1",
629
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
630
+ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
631
+ },
632
+ "is-ci": {
633
+ "version": "2.0.0",
634
+ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz",
635
+ "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==",
636
+ "requires": {
637
+ "ci-info": "^2.0.0"
638
+ }
639
+ },
640
+ "is-directory": {
641
+ "version": "0.3.1",
642
+ "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
643
+ "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE="
644
+ },
645
+ "is-finite": {
646
+ "version": "1.0.2",
647
+ "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
648
+ "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
649
+ "dev": true,
650
+ "requires": {
651
+ "number-is-nan": "^1.0.0"
652
+ }
653
+ },
654
+ "is-stream": {
655
+ "version": "1.1.0",
656
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
657
+ "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
658
+ },
659
+ "isexe": {
660
+ "version": "2.0.0",
661
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
662
+ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
663
+ },
664
+ "js-yaml": {
665
+ "version": "2.0.5",
666
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-2.0.5.tgz",
667
+ "integrity": "sha1-olrmUJmZ6X3yeMZxnaEb0Gh3Q6g=",
668
+ "dev": true,
669
+ "requires": {
670
+ "argparse": "~ 0.1.11",
671
+ "esprima": "~ 1.0.2"
672
+ }
673
+ },
674
+ "json-parse-better-errors": {
675
+ "version": "1.0.2",
676
+ "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
677
+ "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="
678
+ },
679
+ "linguist-languages": {
680
+ "version": "6.3.0",
681
+ "resolved": "https://registry.npmjs.org/linguist-languages/-/linguist-languages-6.3.0.tgz",
682
+ "integrity": "sha512-d86fIQM00SqmBmAErxRpBEBe2Nw/WK4Se999wavaXc+lqarOLnoenGP3V/wgBclxKsRXEYWTd6mvv8373vPSKg=="
683
+ },
684
+ "load-grunt-tasks": {
685
+ "version": "1.0.0",
686
+ "resolved": "https://registry.npmjs.org/load-grunt-tasks/-/load-grunt-tasks-1.0.0.tgz",
687
+ "integrity": "sha1-NKxnBIWb1q4by9fjwh96D8bqx9c=",
688
+ "dev": true,
689
+ "requires": {
690
+ "findup-sync": "^0.1.2",
691
+ "multimatch": "^1.0.0"
692
+ }
693
+ },
694
+ "locate-path": {
695
+ "version": "3.0.0",
696
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
697
+ "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
698
+ "requires": {
699
+ "p-locate": "^3.0.0",
700
+ "path-exists": "^3.0.0"
701
+ }
702
+ },
703
+ "lodash": {
704
+ "version": "0.9.2",
705
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-0.9.2.tgz",
706
+ "integrity": "sha1-jzSZxSRdNG1oLlsNO0B2fgnxqSw=",
707
+ "dev": true
708
+ },
709
+ "lru-cache": {
710
+ "version": "2.7.3",
711
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz",
712
+ "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=",
713
+ "dev": true
714
+ },
715
+ "map-age-cleaner": {
716
+ "version": "0.1.3",
717
+ "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
718
+ "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
719
+ "requires": {
720
+ "p-defer": "^1.0.0"
721
+ }
722
+ },
723
+ "mem": {
724
+ "version": "4.3.0",
725
+ "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz",
726
+ "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==",
727
+ "requires": {
728
+ "map-age-cleaner": "^0.1.1",
729
+ "mimic-fn": "^2.0.0",
730
+ "p-is-promise": "^2.0.0"
731
+ }
732
+ },
733
+ "mimic-fn": {
734
+ "version": "2.1.0",
735
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
736
+ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
737
+ },
738
+ "minimatch": {
739
+ "version": "0.2.14",
740
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz",
741
+ "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=",
742
+ "dev": true,
743
+ "requires": {
744
+ "lru-cache": "2",
745
+ "sigmund": "~1.0.0"
746
+ }
747
+ },
748
+ "mri": {
749
+ "version": "1.1.4",
750
+ "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.4.tgz",
751
+ "integrity": "sha512-6y7IjGPm8AzlvoUrwAaw1tLnUBudaS3752vcd8JtrpGGQn+rXIe63LFVHm/YMwtqAuh+LJPCFdlLYPWM1nYn6w=="
752
+ },
753
+ "multimatch": {
754
+ "version": "1.0.1",
755
+ "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-1.0.1.tgz",
756
+ "integrity": "sha1-GFR8/iWNAf0zJDWVONv68QRqfI8=",
757
+ "dev": true,
758
+ "requires": {
759
+ "array-differ": "^1.0.0",
760
+ "array-union": "^1.0.1",
761
+ "minimatch": "^1.0.0"
762
+ },
763
+ "dependencies": {
764
+ "minimatch": {
765
+ "version": "1.0.0",
766
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-1.0.0.tgz",
767
+ "integrity": "sha1-4N0hILSeG3JM6NcUxSCCKpQ4V20=",
768
+ "dev": true,
769
+ "requires": {
770
+ "lru-cache": "2",
771
+ "sigmund": "~1.0.0"
772
+ }
773
+ }
774
+ }
775
+ },
776
+ "nice-try": {
777
+ "version": "1.0.5",
778
+ "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
779
+ "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
780
+ },
781
+ "nopt": {
782
+ "version": "1.0.10",
783
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
784
+ "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=",
785
+ "dev": true,
786
+ "requires": {
787
+ "abbrev": "1"
788
+ }
789
+ },
790
+ "normalize-package-data": {
791
+ "version": "2.5.0",
792
+ "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
793
+ "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
794
+ "requires": {
795
+ "hosted-git-info": "^2.1.4",
796
+ "resolve": "^1.10.0",
797
+ "semver": "2 || 3 || 4 || 5",
798
+ "validate-npm-package-license": "^3.0.1"
799
+ }
800
+ },
801
+ "npm-run-path": {
802
+ "version": "2.0.2",
803
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
804
+ "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
805
+ "requires": {
806
+ "path-key": "^2.0.0"
807
+ }
808
+ },
809
+ "number-is-nan": {
810
+ "version": "1.0.1",
811
+ "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
812
+ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
813
+ "dev": true
814
+ },
815
+ "object-assign": {
816
+ "version": "4.1.1",
817
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
818
+ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
819
+ "dev": true
820
+ },
821
+ "once": {
822
+ "version": "1.4.0",
823
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
824
+ "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
825
+ "requires": {
826
+ "wrappy": "1"
827
+ }
828
+ },
829
+ "p-defer": {
830
+ "version": "1.0.0",
831
+ "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
832
+ "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww="
833
+ },
834
+ "p-finally": {
835
+ "version": "1.0.0",
836
+ "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
837
+ "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
838
+ },
839
+ "p-is-promise": {
840
+ "version": "2.1.0",
841
+ "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz",
842
+ "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg=="
843
+ },
844
+ "p-limit": {
845
+ "version": "2.2.0",
846
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz",
847
+ "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==",
848
+ "requires": {
849
+ "p-try": "^2.0.0"
850
+ }
851
+ },
852
+ "p-locate": {
853
+ "version": "3.0.0",
854
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
855
+ "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
856
+ "requires": {
857
+ "p-limit": "^2.0.0"
858
+ }
859
+ },
860
+ "p-try": {
861
+ "version": "2.2.0",
862
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
863
+ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
864
+ },
865
+ "parse-json": {
866
+ "version": "4.0.0",
867
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
868
+ "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
869
+ "requires": {
870
+ "error-ex": "^1.3.1",
871
+ "json-parse-better-errors": "^1.0.1"
872
+ }
873
+ },
874
+ "parse-ms": {
875
+ "version": "1.0.1",
876
+ "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-1.0.1.tgz",
877
+ "integrity": "sha1-VjRtR0nXjyNDDKDHE4UK75GqNh0=",
878
+ "dev": true
879
+ },
880
+ "path-exists": {
881
+ "version": "3.0.0",
882
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
883
+ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
884
+ },
885
+ "path-key": {
886
+ "version": "2.0.1",
887
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
888
+ "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
889
+ },
890
+ "path-parse": {
891
+ "version": "1.0.6",
892
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
893
+ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
894
+ },
895
+ "php-parser": {
896
+ "version": "github:glayzzle/php-parser#71485979b688d12fb130d3e853fdc00348671e00",
897
+ "from": "github:glayzzle/php-parser#71485979b688d12fb130d3e853fdc00348671e00"
898
+ },
899
+ "pkg-dir": {
900
+ "version": "4.1.0",
901
+ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.1.0.tgz",
902
+ "integrity": "sha512-55k9QN4saZ8q518lE6EFgYiu95u3BWkSajCifhdQjvLvmr8IpnRbhI+UGpWJQfa0KzDguHeeWT1ccO1PmkOi3A==",
903
+ "requires": {
904
+ "find-up": "^3.0.0"
905
+ }
906
+ },
907
+ "please-upgrade-node": {
908
+ "version": "3.1.1",
909
+ "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.1.1.tgz",
910
+ "integrity": "sha512-KY1uHnQ2NlQHqIJQpnh/i54rKkuxCEBx+voJIS/Mvb+L2iYd2NMotwduhKTMjfC1uKoX3VXOxLjIYG66dfJTVQ==",
911
+ "requires": {
912
+ "semver-compare": "^1.0.0"
913
+ }
914
+ },
915
+ "plur": {
916
+ "version": "1.0.0",
917
+ "resolved": "https://registry.npmjs.org/plur/-/plur-1.0.0.tgz",
918
+ "integrity": "sha1-24XGgU9eXlo7Se/CjWBP7GKXUVY=",
919
+ "dev": true
920
+ },
921
+ "prettier": {
922
+ "version": "1.17.0",
923
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.17.0.tgz",
924
+ "integrity": "sha512-sXe5lSt2WQlCbydGETgfm1YBShgOX4HxQkFPvbxkcwgDvGDeqVau8h+12+lmSVlP3rHPz0oavfddSZg/q+Szjw=="
925
+ },
926
+ "pretty-ms": {
927
+ "version": "2.1.0",
928
+ "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-2.1.0.tgz",
929
+ "integrity": "sha1-QlfCVt8/sLRR1q/6qwIYhBJpgdw=",
930
+ "dev": true,
931
+ "requires": {
932
+ "is-finite": "^1.0.1",
933
+ "parse-ms": "^1.0.0",
934
+ "plur": "^1.0.0"
935
+ }
936
+ },
937
+ "pretty-quick": {
938
+ "version": "1.10.0",
939
+ "resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-1.10.0.tgz",
940
+ "integrity": "sha512-uNvm2N3UWmnZRZrClyQI45hIbV20f5BpSyZY51Spbvn4APp9+XLyX4bCjWRGT3fGyVyQ/2/iw7dbQq1UUaq7SQ==",
941
+ "requires": {
942
+ "chalk": "^2.3.0",
943
+ "execa": "^0.8.0",
944
+ "find-up": "^2.1.0",
945
+ "ignore": "^3.3.7",
946
+ "mri": "^1.1.0",
947
+ "multimatch": "^3.0.0"
948
+ },
949
+ "dependencies": {
950
+ "ansi-styles": {
951
+ "version": "3.2.1",
952
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
953
+ "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
954
+ "requires": {
955
+ "color-convert": "^1.9.0"
956
+ }
957
+ },
958
+ "array-differ": {
959
+ "version": "2.1.0",
960
+ "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-2.1.0.tgz",
961
+ "integrity": "sha512-KbUpJgx909ZscOc/7CLATBFam7P1Z1QRQInvgT0UztM9Q72aGKCunKASAl7WNW0tnPmPyEMeMhdsfWhfmW037w=="
962
+ },
963
+ "chalk": {
964
+ "version": "2.4.2",
965
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
966
+ "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
967
+ "requires": {
968
+ "ansi-styles": "^3.2.1",
969
+ "escape-string-regexp": "^1.0.5",
970
+ "supports-color": "^5.3.0"
971
+ }
972
+ },
973
+ "cross-spawn": {
974
+ "version": "5.1.0",
975
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
976
+ "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
977
+ "requires": {
978
+ "lru-cache": "^4.0.1",
979
+ "shebang-command": "^1.2.0",
980
+ "which": "^1.2.9"
981
+ }
982
+ },
983
+ "execa": {
984
+ "version": "0.8.0",
985
+ "resolved": "https://registry.npmjs.org/execa/-/execa-0.8.0.tgz",
986
+ "integrity": "sha1-2NdrvBtVIX7RkP1t1J08d07PyNo=",
987
+ "requires": {
988
+ "cross-spawn": "^5.0.1",
989
+ "get-stream": "^3.0.0",
990
+ "is-stream": "^1.1.0",
991
+ "npm-run-path": "^2.0.0",
992
+ "p-finally": "^1.0.0",
993
+ "signal-exit": "^3.0.0",
994
+ "strip-eof": "^1.0.0"
995
+ }
996
+ },
997
+ "find-up": {
998
+ "version": "2.1.0",
999
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz",
1000
+ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=",
1001
+ "requires": {
1002
+ "locate-path": "^2.0.0"
1003
+ }
1004
+ },
1005
+ "get-stream": {
1006
+ "version": "3.0.0",
1007
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
1008
+ "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
1009
+ },
1010
+ "locate-path": {
1011
+ "version": "2.0.0",
1012
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz",
1013
+ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=",
1014
+ "requires": {
1015
+ "p-locate": "^2.0.0",
1016
+ "path-exists": "^3.0.0"
1017
+ }
1018
+ },
1019
+ "lru-cache": {
1020
+ "version": "4.1.5",
1021
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
1022
+ "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
1023
+ "requires": {
1024
+ "pseudomap": "^1.0.2",
1025
+ "yallist": "^2.1.2"
1026
+ }
1027
+ },
1028
+ "minimatch": {
1029
+ "version": "3.0.4",
1030
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
1031
+ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
1032
+ "requires": {
1033
+ "brace-expansion": "^1.1.7"
1034
+ }
1035
+ },
1036
+ "multimatch": {
1037
+ "version": "3.0.0",
1038
+ "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-3.0.0.tgz",
1039
+ "integrity": "sha512-22foS/gqQfANZ3o+W7ST2x25ueHDVNWl/b9OlGcLpy/iKxjCpvcNCM51YCenUi7Mt/jAjjqv8JwZRs8YP5sRjA==",
1040
+ "requires": {
1041
+ "array-differ": "^2.0.3",
1042
+ "array-union": "^1.0.2",
1043
+ "arrify": "^1.0.1",
1044
+ "minimatch": "^3.0.4"
1045
+ }
1046
+ },
1047
+ "p-limit": {
1048
+ "version": "1.3.0",
1049
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
1050
+ "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==",
1051
+ "requires": {
1052
+ "p-try": "^1.0.0"
1053
+ }
1054
+ },
1055
+ "p-locate": {
1056
+ "version": "2.0.0",
1057
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz",
1058
+ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=",
1059
+ "requires": {
1060
+ "p-limit": "^1.1.0"
1061
+ }
1062
+ },
1063
+ "p-try": {
1064
+ "version": "1.0.0",
1065
+ "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz",
1066
+ "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M="
1067
+ },
1068
+ "supports-color": {
1069
+ "version": "5.5.0",
1070
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
1071
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
1072
+ "requires": {
1073
+ "has-flag": "^3.0.0"
1074
+ }
1075
+ },
1076
+ "which": {
1077
+ "version": "1.3.1",
1078
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
1079
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
1080
+ "requires": {
1081
+ "isexe": "^2.0.0"
1082
+ }
1083
+ }
1084
+ }
1085
+ },
1086
+ "pseudomap": {
1087
+ "version": "1.0.2",
1088
+ "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
1089
+ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
1090
+ },
1091
+ "pump": {
1092
+ "version": "3.0.0",
1093
+ "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
1094
+ "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
1095
+ "requires": {
1096
+ "end-of-stream": "^1.1.0",
1097
+ "once": "^1.3.1"
1098
+ }
1099
+ },
1100
+ "read-pkg": {
1101
+ "version": "5.1.1",
1102
+ "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.1.1.tgz",
1103
+ "integrity": "sha512-dFcTLQi6BZ+aFUaICg7er+/usEoqFdQxiEBsEMNGoipenihtxxtdrQuBXvyANCEI8VuUIVYFgeHGx9sLLvim4w==",
1104
+ "requires": {
1105
+ "@types/normalize-package-data": "^2.4.0",
1106
+ "normalize-package-data": "^2.5.0",
1107
+ "parse-json": "^4.0.0",
1108
+ "type-fest": "^0.4.1"
1109
+ }
1110
+ },
1111
+ "resolve": {
1112
+ "version": "1.10.1",
1113
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.1.tgz",
1114
+ "integrity": "sha512-KuIe4mf++td/eFb6wkaPbMDnP6kObCaEtIDuHOUED6MNUo4K670KZUHuuvYPZDxNF0WVLw49n06M2m2dXphEzA==",
1115
+ "requires": {
1116
+ "path-parse": "^1.0.6"
1117
+ }
1118
+ },
1119
+ "resolve-from": {
1120
+ "version": "3.0.0",
1121
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
1122
+ "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g="
1123
+ },
1124
+ "rimraf": {
1125
+ "version": "2.2.8",
1126
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz",
1127
+ "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=",
1128
+ "dev": true
1129
+ },
1130
+ "run-node": {
1131
+ "version": "1.0.0",
1132
+ "resolved": "https://registry.npmjs.org/run-node/-/run-node-1.0.0.tgz",
1133
+ "integrity": "sha512-kc120TBlQ3mih1LSzdAJXo4xn/GWS2ec0l3S+syHDXP9uRr0JAT8Qd3mdMuyjqCzeZktgP3try92cEgf9Nks8A=="
1134
+ },
1135
+ "safer-buffer": {
1136
+ "version": "2.1.2",
1137
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1138
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
1139
+ "dev": true
1140
+ },
1141
+ "semver": {
1142
+ "version": "5.7.0",
1143
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
1144
+ "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA=="
1145
+ },
1146
+ "semver-compare": {
1147
+ "version": "1.0.0",
1148
+ "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
1149
+ "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w="
1150
+ },
1151
+ "shebang-command": {
1152
+ "version": "1.2.0",
1153
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
1154
+ "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
1155
+ "requires": {
1156
+ "shebang-regex": "^1.0.0"
1157
+ }
1158
+ },
1159
+ "shebang-regex": {
1160
+ "version": "1.0.0",
1161
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
1162
+ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
1163
+ },
1164
+ "sigmund": {
1165
+ "version": "1.0.1",
1166
+ "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
1167
+ "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=",
1168
+ "dev": true
1169
+ },
1170
+ "signal-exit": {
1171
+ "version": "3.0.2",
1172
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
1173
+ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
1174
+ },
1175
+ "slash": {
1176
+ "version": "2.0.0",
1177
+ "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
1178
+ "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A=="
1179
+ },
1180
+ "spdx-correct": {
1181
+ "version": "3.1.0",
1182
+ "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
1183
+ "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
1184
+ "requires": {
1185
+ "spdx-expression-parse": "^3.0.0",
1186
+ "spdx-license-ids": "^3.0.0"
1187
+ }
1188
+ },
1189
+ "spdx-exceptions": {
1190
+ "version": "2.2.0",
1191
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
1192
+ "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA=="
1193
+ },
1194
+ "spdx-expression-parse": {
1195
+ "version": "3.0.0",
1196
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
1197
+ "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
1198
+ "requires": {
1199
+ "spdx-exceptions": "^2.1.0",
1200
+ "spdx-license-ids": "^3.0.0"
1201
+ }
1202
+ },
1203
+ "spdx-license-ids": {
1204
+ "version": "3.0.4",
1205
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.4.tgz",
1206
+ "integrity": "sha512-7j8LYJLeY/Yb6ACbQ7F76qy5jHkp0U6jgBfJsk97bwWlVUnUWsAgpyaCvo17h0/RQGnQ036tVDomiwoI4pDkQA=="
1207
+ },
1208
+ "sprintf-js": {
1209
+ "version": "1.0.3",
1210
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
1211
+ "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
1212
+ },
1213
+ "strip-ansi": {
1214
+ "version": "3.0.1",
1215
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
1216
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
1217
+ "dev": true,
1218
+ "requires": {
1219
+ "ansi-regex": "^2.0.0"
1220
+ }
1221
+ },
1222
+ "strip-eof": {
1223
+ "version": "1.0.0",
1224
+ "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
1225
+ "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
1226
+ },
1227
+ "supports-color": {
1228
+ "version": "2.0.0",
1229
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
1230
+ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
1231
+ "dev": true
1232
+ },
1233
+ "text-table": {
1234
+ "version": "0.2.0",
1235
+ "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
1236
+ "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
1237
+ "dev": true
1238
+ },
1239
+ "time-grunt": {
1240
+ "version": "1.4.0",
1241
+ "resolved": "https://registry.npmjs.org/time-grunt/-/time-grunt-1.4.0.tgz",
1242
+ "integrity": "sha1-BiIT5mDJB+hvRAVWwB6mWXtxJCA=",
1243
+ "dev": true,
1244
+ "requires": {
1245
+ "chalk": "^1.0.0",
1246
+ "date-time": "^1.1.0",
1247
+ "figures": "^1.0.0",
1248
+ "hooker": "^0.2.3",
1249
+ "number-is-nan": "^1.0.0",
1250
+ "pretty-ms": "^2.1.0",
1251
+ "text-table": "^0.2.0"
1252
+ }
1253
+ },
1254
+ "time-zone": {
1255
+ "version": "0.1.0",
1256
+ "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-0.1.0.tgz",
1257
+ "integrity": "sha1-Sncotqwo2w4Aj1FAQ/1VW9VXO0Y=",
1258
+ "dev": true
1259
+ },
1260
+ "type-fest": {
1261
+ "version": "0.4.1",
1262
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.4.1.tgz",
1263
+ "integrity": "sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw=="
1264
+ },
1265
+ "underscore": {
1266
+ "version": "1.7.0",
1267
+ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz",
1268
+ "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=",
1269
+ "dev": true
1270
+ },
1271
+ "underscore.string": {
1272
+ "version": "2.2.1",
1273
+ "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.2.1.tgz",
1274
+ "integrity": "sha1-18D6KvXVoaZ/QlPa7pgTLnM/Dxk=",
1275
+ "dev": true
1276
+ },
1277
+ "validate-npm-package-license": {
1278
+ "version": "3.0.4",
1279
+ "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
1280
+ "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
1281
+ "requires": {
1282
+ "spdx-correct": "^3.0.0",
1283
+ "spdx-expression-parse": "^3.0.0"
1284
+ }
1285
+ },
1286
+ "which": {
1287
+ "version": "1.0.9",
1288
+ "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz",
1289
+ "integrity": "sha1-RgwdoPgQED0DIam2M6+eV15kSG8=",
1290
+ "dev": true
1291
+ },
1292
+ "wrappy": {
1293
+ "version": "1.0.2",
1294
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1295
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
1296
+ },
1297
+ "yallist": {
1298
+ "version": "2.1.2",
1299
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
1300
+ "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
1301
+ }
1302
+ }
1303
+ }
package.json CHANGED
@@ -1,14 +1,25 @@
1
  {
2
- "name": "SimpleHistory",
3
  "version": "0.0.1",
4
  "description": "WordPress log plugin",
5
  "author": "Pär Thernström",
6
  "license": "GPL",
7
  "devDependencies": {
8
- "grunt": "~0.4.5",
9
- "grunt-pot": "^0.2.0",
10
  "grunt-wp-i18n": "^0.4.9",
11
- "load-grunt-tasks": "~1.0.0",
12
- "time-grunt": "^1.0.0"
 
 
 
 
 
 
 
 
 
 
 
13
  }
14
  }
1
  {
2
+ "name": "simplehistory",
3
  "version": "0.0.1",
4
  "description": "WordPress log plugin",
5
  "author": "Pär Thernström",
6
  "license": "GPL",
7
  "devDependencies": {
8
+ "grunt": "^0.4.5",
9
+ "grunt-pot": "^0.2.1",
10
  "grunt-wp-i18n": "^0.4.9",
11
+ "load-grunt-tasks": "^1.0.0",
12
+ "time-grunt": "^1.4.0"
13
+ },
14
+ "dependencies": {
15
+ "@prettier/plugin-php": "^0.10.2",
16
+ "husky": "^2.1.0",
17
+ "prettier": "^1.17.0",
18
+ "pretty-quick": "^1.10.0"
19
+ },
20
+ "husky": {
21
+ "hooks": {
22
+ "pre-commit": "pretty-quick --staged"
23
+ }
24
  }
25
  }
readme.txt CHANGED
@@ -3,9 +3,9 @@ Contributors: eskapism
3
  Donate link: http://eskapism.se/sida/donate/
4
  Tags: history, log, changes, changelog, audit, audit log, event log, user tracking, trail, pages, attachments, users, dashboard, admin, syslog, feed, activity, stream, audit trail, brute-force
5
  Requires at least: 4.5.1
6
- Tested up to: 4.9
7
- Requires PHP: 5.3
8
- Stable tag: 2.29.2
9
 
10
  View changes made by users within WordPress. See who created a page, uploaded an attachment or approved an comment, and more.
11
 
@@ -17,34 +17,33 @@ The plugin works as a log/history/audit log/version history of the most importan
17
 
18
  Out of the box Simple History has support for:
19
 
20
- * **Posts and pages**<br>
21
- see who added, updated or deleted a post or page
22
- * **Attachments**<br>
23
- see who added, updated or deleted an attachment
24
- * **Taxonomies (Custom taxonomies, categories, tags)**<br>
25
- see who added, updated or deleted an taxonomy
26
- * **Comments**<br>
27
- see who edited, approved or removed a comment
28
- * **Widgets**<br>
29
- get info when someone adds, updates or removes a widget in a sidebar
30
- * **Plugins**<br>
31
- activation and deactivation
32
- * **User profiles**<br>
33
- info about added, updated or removed users
34
- * **User logins**<br>
35
- see when a user login & logout. Also see when a user fails to login (good way to catch brute-force login attempts).
36
- * **Failed user logins**<br>
37
- see when someone has tried to log in, but failed. The log will then include ip address of the possible hacker.
38
- * **Menu edits**
39
- * **Option screens**<br>
40
- view details about changes made in the differnt settings sections of WordPress. Things like changes to the site title and the permalink structure will be logged.
41
- * **Privacy page**<br>
42
- when a privacy page is created or set to a new page.
43
- * **Data Export**<br>
44
- see when a privacy data export request is added and when this request is approved by the user, downloaded by an admin, or emailed to the user.
45
- * **User Data Erasure Requests**<br>
46
- see when a user privacy data export request is added and when this request is approved by the user and when the user data is removed.
47
-
48
 
49
  #### Support for third party plugins
50
 
@@ -81,6 +80,10 @@ The plugin [Duplicate Post](https://wordpress.org/plugins/duplicate-post/) allow
81
  clone posts of any type.
82
  Simple History will log when a clone of a post or page is done.
83
 
 
 
 
 
84
  #### RSS feed with changes
85
 
86
  There is also a **RSS feed of changes** available, so you can keep track of the changes made via your favorite RSS reader on your phone, on your iPad, or on your computer.
@@ -105,6 +108,7 @@ that must be it."_
105
  If you are a theme or plugin developer and would like to add your own things/events to Simple History you can do that by using the function `SimpleLogger()` like this:
106
 
107
  `
 
108
  <?php
109
 
110
  if ( function_exists("SimpleLogger") ) {
@@ -119,6 +123,7 @@ if ( function_exists("SimpleLogger") ) {
119
 
120
  }
121
  ?>
 
122
  `
123
 
124
  Check out the [examples-folder](https://github.com/bonny/WordPress-Simple-History/tree/master/examples) for more examples.
@@ -127,14 +132,14 @@ Check out the [examples-folder](https://github.com/bonny/WordPress-Simple-Histor
127
 
128
  So far Simple History is translated to:
129
 
130
- * Swedish
131
- * German
132
- * Polish
133
- * Danish
134
- * Dutch
135
- * Finnish
136
- * French
137
- * Russian
138
 
139
  I'm looking for translations of Simple History in more languages! If you want to translate Simple History
140
  to your language then read about how this is done over at the [Polyglots handbook](https://make.wordpress.org/polyglots/handbook/rosetta/theme-plugin-directories/#translating-themes-plugins).
@@ -146,7 +151,7 @@ https://github.com/bonny/WordPress-Simple-History
146
 
147
  #### Donation
148
 
149
- * If you like this plugin please consider [donating to support the development](https://www.paypal.me/eskapism).
150
 
151
  == Frequently Asked Questions ==
152
 
@@ -154,6 +159,11 @@ https://github.com/bonny/WordPress-Simple-History
154
 
155
  Yes. See the [examples file](https://github.com/bonny/WordPress-Simple-History/blob/master/examples/examples.php).
156
 
 
 
 
 
 
157
  = For how long are events stored? =
158
 
159
  Events in the log are stored for 60 days by default. Events older than this will be removed.
@@ -161,10 +171,10 @@ Events in the log are stored for 60 days by default. Events older than this will
161
  == Screenshots ==
162
 
163
  1. The log view + it also shows the filter function in use - the log only shows event that
164
- are of type post and pages and media (i.e. images & other uploads), and only events
165
- initiated by a specific user.
166
 
167
- 2. The __Post Quick Diff__ feature will make it quick and easy for a user of a site to see what updates other users have done to posts and pages.
168
 
169
  3. When users are created or changed you can see details on what have changed.
170
 
@@ -175,12 +185,26 @@ initiated by a specific user.
175
  6. See even more details about a logged event (by clicking on the date and time of the event).
176
 
177
  7. A chart with some quick statistics is available, so you can see the number of events that has been logged each day.
178
- A simple way to see any uncommon activity, for example an increased number of logins or similar.
179
 
180
  == Changelog ==
181
 
182
  ## Changelog
183
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
184
  = 2.29.2 (January 2019) =
185
 
186
  - Fix for (the still great) plugin [Advanced Custom Fields](http://advancedcustomfields.com) 5.7.10 that removed the function `_acf_get_field_by_id` that this plugin used. Fixes https://wordpress.org/support/topic/uncaught-error-call-to-undefined-function-_acf_get_field_by_id/.
@@ -192,18 +216,16 @@ A simple way to see any uncommon activity, for example an increased number of lo
192
  = 2.29 (December 2018) =
193
 
194
  - Make log welcome message translateable.
195
- - Add two filters to make it more ease to control via filters if a logger and the combination logger + message should be logged.
196
- - `"simple_history/log/do_log/{$this->slug}"` controls if any messages for a specific logger should be logged. Simply return false to this filter to disable all logging to that logger.
197
- - `"simple_history/log/do_log/{$this->slug}/{$message_key}"` controls if a specific message for a specific logger should be logged. Simply return false to this filter to disable all logging to that logger.
198
- - Code examples for the two filters above:
199
- ```
200
- // Disable logging of any user message, i.e. any message from the logger SimpleUserLogger.
201
- add_filter( 'simple_history/log/do_log/SimpleUserLogger', '__return_false' );
202
-
203
- // Disable logging of updated posts, i.e. the message "post_updated" from the logger SimplePostLogger.
204
- add_filter( 'simple_history/log/do_log/SimplePostLogger/post_updated', '__return_false' );
205
- ```
206
- - add_filter('simple_history/log/do_log/SimpleUserLogger', '__return_false');
207
  - Fix notice in Redirection plugin logger due because redirection plugin can have multiple target types. Props @MaximVanhove.
208
  - Fix warning because of missing logging messages in the categories/tags logger. Props @JeroenSormani.
209
  - Fix warning in the next version of PHP, PHP 7.3.
@@ -236,7 +258,7 @@ A simple way to see any uncommon activity, for example an increased number of lo
236
  - Add support for the [Jetpack plugin](https://wordpress.org/plugins/jetpack/). To begin with, activation and deactivation of Jetpack modules is logged.
237
  - Add logging of translation updates, so now you can see when a plugin or a theme has gotten new translations. Fixes https://github.com/bonny/WordPress-Simple-History/issues/147.
238
  - Fix notice in Advanced Custom Fields logger when saving an ACF options page.
239
- Fixes https://wordpress.org/support/topic/problem-with-acf-options-pages/, https://wordpress.org/support/topic/problem-with-recent-version-and-acf/, https://github.com/bonny/WordPress-Simple-History/issues/145.
240
 
241
  = 2.25 (July 2018) =
242
 
@@ -259,10 +281,7 @@ Fixes https://wordpress.org/support/topic/problem-with-acf-options-pages/, https
259
 
260
  = 2.23 (May 2018) =
261
 
262
- - Add logging of privacy and GDPR related functions in WordPress. Some of the new [privacy related features in WordPress 4.9.6](https://wordpress.org/news/2018/05/wordpress-4-9-6-privacy-and-maintenance-release/) that are logged:
263
- - Privacy policy page is created or changed to a new page.
264
- - Privacy data export is requested for a user and when this request is confirmed by the user and when the data for the request is downloaded by an admin or emailed to the user.
265
- - Erase Personal Data: Request is added for user to have their personal data erased, user confirms the data removal and when the deletion of user data is done.
266
  - Fix error when categories changes was shown in the log. Fixes https://wordpress.org/support/topic/php-notice-undefined-variable-term_object/.
267
  - Fix error when a ACF Field Group was saved.
268
  - Fix error when the IP address anonymization function tried to anonymize an empty IP adress. Could happen when for example running wp cron locally on your server.
@@ -278,9 +297,9 @@ Fixes https://wordpress.org/support/topic/problem-with-acf-options-pages/, https
278
  = 2.22 (May 2018) =
279
 
280
  - IP addresses are now anonymized by default. This is mainly done because of the [General Data Protection Regulation](https://en.wikipedia.org/wiki/General_Data_Protection_Regulation) (GDPR)
281
- Both IPv4 and IPv6 addresses will be anonymized and the IP addresses are anonymized to their network ID.
282
- So for example the IPv4 address `192.168.123.124` is anonymized to `192.168.123.0` and
283
- the IPv6 address `2a03:2880:2110:df07:face:b00c::1` is anonymized by default to `2610:28:3090:3001::`.
284
 
285
  - Added filter `simple_history/privacy/anonymize_ip_address` than can be used to disable ip address anonymization.
286
 
@@ -288,12 +307,10 @@ the IPv6 address `2a03:2880:2110:df07:face:b00c::1` is anonymized by default to
288
 
289
  - Fixed logging for [plugin Redirection](https://wordpress.org/plugins/redirection/). The logging of URL redirects and so on stopped working some while back because the Redirection plugin started using the WP REST API. But now it's working again!
290
 
291
-
292
  = 2.21.1 (May 2018) =
293
 
294
  - Make sure support for Advanced Custom Fields is activated for all users – and not only for the developer of the plugin ;)
295
 
296
-
297
  = 2.21 (May 2018) =
298
 
299
  - Added support for Advanced Custom Fields (ACF): when a ACF Field or ACF Field Group is created or modified or deleted you will now get more details in the activity feed.
@@ -354,14 +371,14 @@ the IPv6 address `2a03:2880:2110:df07:face:b00c::1` is anonymized by default to
354
 
355
  - Added [WP-CLI](https://wp-cli.org) command for Simple History. Now you can write `wp simple-history list` to see the latest entries from the history log. For now `list` is the only available command. Let me know if you need more commands!
356
  - Added support for logging edits to theme files and plugin files. When a file is edited you will also get a quick diff on the changes,
357
- so you can see what CSS styles a client changed or what PHP changes they made in a plugin file.
358
  - Removed the edit file logger from the plugin logger, because it did not always work (checked wrong wp path). Intead the new Theme and plugins logger mentioned above will take care of this.
359
 
360
  = 2.15 (May 2017) =
361
 
362
  - Use thumbnail version of PDF preview instead of full size image.
363
  - Remove Google Maps image when clicking IP address of failed login and similar, because Google Maps must be used with API key.
364
- Hostname, Network, City, Region and Country is still shown.
365
  - Fix notice in available updates logger.
366
  - Fix notice in redirection logger.
367
 
@@ -372,7 +389,7 @@ so you can see what CSS styles a client changed or what PHP changes they made in
372
  = 2.14 (April 2017) =
373
 
374
  - Added support for plugin [Duplicate Post](https://wordpress.org/plugins/duplicate-post/).
375
- Now when a user clones a post or page you will se this in the history log, with links to both the original post and the new copy.
376
  - Removed log level info from title in RSS feed
377
  - Make date dropdown less "jumpy" when loading page (due to select element switching to Select2)
378
  - Only add filters for plugin Limit Login Attempts if plugin is active. This fixes problem with Limit Login Attempts Reloaded and possibly other forks of the plugin.
@@ -394,20 +411,20 @@ so you can see what CSS styles a client changed or what PHP changes they made in
394
  = 2.11 (September 2016) =
395
 
396
  - Added support for plugin [Redirection](https://wordpress.org/plugins/redirection/).
397
- Redirects and groups that are created, changed, enabled and disabled will be logged. Also when the plugin global settings are changed that will be logged.
398
  - Fix possible notice error from User logger.
399
  - "View changelog" link now works on multisite.
400
 
401
  = 2.10 (September 2016) =
402
 
403
  - Available updates to plugins, themes, and WordPress itself is now logged.
404
- Pretty great if you subscribe to the RSS feed to get the changes on a site. No need to manually check the updates-page to see if there are any updates.
405
  - Changed to logic used to determine if a post edit should be logged or not. Version 2.9 used a version that started to log a bit to much for some plugins. This should fix the problems with the Nextgen Gallery, All-In-One Events Calendar, and Membership 2 plugins. If you still have problems with a plugin that is causing to many events to be logged, please let me know!
406
 
407
  = 2.9.1 (August 2016) =
408
 
409
  - Fixed an issue where the logged time was off by some hours, due to timezone being manually set elsewhere.
410
- Should fix https://wordpress.org/support/topic/logged-time-off-by-2-hours and https://wordpress.org/support/topic/different-time-between-dashboard-and-logger.
411
  - Fixed Nextgen Gallery and Nextgen Gallery Plus logging lots and lots of event when viewing posts with galleries. The posts was actually updated, so this plugin did nothing wrong. But it was indeed a bit annoying and most likely something you didn't want in your log. Fixes https://wordpress.org/support/topic/non-stop-logging-nextgen-gallery-items.
412
 
413
  = 2.9 (August 2016) =
@@ -424,7 +441,7 @@ so you can see what CSS styles a client changed or what PHP changes they made in
424
  - ...and so are theme updates
425
  - ...and theme deletions. Awesome!
426
  - Support for plugin [Limit Login Attempts](https://wordpress.org/plugins/limit-login-attempts/).
427
- Failed login attempts, lockouts and configuration changes will be logged.
428
  - Correct message is now used when a plugin update fails, i.e. the message for key `plugin_update_failed`.
429
  - The original untranslated strings for plugin name and so on are stored when storing info for plugin installs and updates and similar.
430
  - Default number of events to show is now 10 instead of 5.
@@ -433,7 +450,7 @@ so you can see what CSS styles a client changed or what PHP changes they made in
433
 
434
  - User logins using e-mail are now logged correctly. Previously the user would be logged in successfully but the log said that they failed.
435
  - Security fix: only users with [`list_users`](https://codex.wordpress.org/Roles_and_Capabilities#list_users) capability can view the users filter and use the autocomplete api for users.
436
- Previously the autocomplete function could be used by all logged in users.
437
  - Add labels to search filters. (I do really hate label-less forms so it's kinda very strange that this was not in place before.)
438
  - Misc other internal fixes
439
 
@@ -446,7 +463,7 @@ so you can see what CSS styles a client changed or what PHP changes they made in
446
 
447
  = 2.7.3 (June 2016) =
448
 
449
- - Removed the usage of the mb_* functions and mbstring is no longer a requirement.
450
  - Added a new debug tab to the settings page. On the debug page you can see stuff like how large your database is and how many rows that are stored in the database. Also, a list of all loggers are listed there together with some useful (for developers anyway) information.
451
 
452
  = 2.7.2 (June 2016) =
3
  Donate link: http://eskapism.se/sida/donate/
4
  Tags: history, log, changes, changelog, audit, audit log, event log, user tracking, trail, pages, attachments, users, dashboard, admin, syslog, feed, activity, stream, audit trail, brute-force
5
  Requires at least: 4.5.1
6
+ Tested up to: 5.2
7
+ Requires PHP: 5.4
8
+ Stable tag: 2.31
9
 
10
  View changes made by users within WordPress. See who created a page, uploaded an attachment or approved an comment, and more.
11
 
17
 
18
  Out of the box Simple History has support for:
19
 
20
+ - **Posts and pages**<br>
21
+ see who added, updated or deleted a post or page
22
+ - **Attachments**<br>
23
+ see who added, updated or deleted an attachment
24
+ - **Taxonomies (Custom taxonomies, categories, tags)**<br>
25
+ see who added, updated or deleted an taxonomy
26
+ - **Comments**<br>
27
+ see who edited, approved or removed a comment
28
+ - **Widgets**<br>
29
+ get info when someone adds, updates or removes a widget in a sidebar
30
+ - **Plugins**<br>
31
+ activation and deactivation
32
+ - **User profiles**<br>
33
+ info about added, updated or removed users
34
+ - **User logins**<br>
35
+ see when a user login & logout. Also see when a user fails to login (good way to catch brute-force login attempts).
36
+ - **Failed user logins**<br>
37
+ see when someone has tried to log in, but failed. The log will then include ip address of the possible hacker.
38
+ - **Menu edits**
39
+ - **Option screens**<br>
40
+ view details about changes made in the differnt settings sections of WordPress. Things like changes to the site title and the permalink structure will be logged.
41
+ - **Privacy page**<br>
42
+ when a privacy page is created or set to a new page.
43
+ - **Data Export**<br>
44
+ see when a privacy data export request is added and when this request is approved by the user, downloaded by an admin, or emailed to the user.
45
+ - **User Data Erasure Requests**<br>
46
+ see when a user privacy data export request is added and when this request is approved by the user and when the user data is removed.
 
47
 
48
  #### Support for third party plugins
49
 
80
  clone posts of any type.
81
  Simple History will log when a clone of a post or page is done.
82
 
83
+ **Beaver Builder**
84
+ The plugin [Beaver Build](https://wordpress.org/plugins/beaver-builder-lite-version/) is a page builder for WordPress that adds a flexible drag and drop page builder to the front end of your WordPress website.
85
+ Simple History will log when a Beaver Builder layout or template is saved or when the settings for the plugins are saved.
86
+
87
  #### RSS feed with changes
88
 
89
  There is also a **RSS feed of changes** available, so you can keep track of the changes made via your favorite RSS reader on your phone, on your iPad, or on your computer.
108
  If you are a theme or plugin developer and would like to add your own things/events to Simple History you can do that by using the function `SimpleLogger()` like this:
109
 
110
  `
111
+
112
  <?php
113
 
114
  if ( function_exists("SimpleLogger") ) {
123
 
124
  }
125
  ?>
126
+
127
  `
128
 
129
  Check out the [examples-folder](https://github.com/bonny/WordPress-Simple-History/tree/master/examples) for more examples.
132
 
133
  So far Simple History is translated to:
134
 
135
+ - Swedish
136
+ - German
137
+ - Polish
138
+ - Danish
139
+ - Dutch
140
+ - Finnish
141
+ - French
142
+ - Russian
143
 
144
  I'm looking for translations of Simple History in more languages! If you want to translate Simple History
145
  to your language then read about how this is done over at the [Polyglots handbook](https://make.wordpress.org/polyglots/handbook/rosetta/theme-plugin-directories/#translating-themes-plugins).
151
 
152
  #### Donation
153
 
154
+ - If you like this plugin please consider [donating to support the development](https://www.paypal.me/eskapism).
155
 
156
  == Frequently Asked Questions ==
157
 
159
 
160
  Yes. See the [examples file](https://github.com/bonny/WordPress-Simple-History/blob/master/examples/examples.php).
161
 
162
+ = Is it possible to exclude users from the log? =
163
+
164
+ Yes, you exclude users by role or email using the filter `simple_history/log/do_log`.
165
+ See the [examples file](https://github.com/bonny/WordPress-Simple-History/blob/master/examples/examples.php).
166
+
167
  = For how long are events stored? =
168
 
169
  Events in the log are stored for 60 days by default. Events older than this will be removed.
171
  == Screenshots ==
172
 
173
  1. The log view + it also shows the filter function in use - the log only shows event that
174
+ are of type post and pages and media (i.e. images & other uploads), and only events
175
+ initiated by a specific user.
176
 
177
+ 2. The **Post Quick Diff** feature will make it quick and easy for a user of a site to see what updates other users have done to posts and pages.
178
 
179
  3. When users are created or changed you can see details on what have changed.
180
 
185
  6. See even more details about a logged event (by clicking on the date and time of the event).
186
 
187
  7. A chart with some quick statistics is available, so you can see the number of events that has been logged each day.
188
+ A simple way to see any uncommon activity, for example an increased number of logins or similar.
189
 
190
  == Changelog ==
191
 
192
  ## Changelog
193
 
194
+ = 2.31 (May 2019) =
195
+
196
+ - Add support for plugin [Beaver Builder](https://wordpress.org/plugins/beaver-builder-lite-version/).
197
+
198
+ = 2.30 (April 2019) =
199
+
200
+ - Add better Gutenberg compatibility.
201
+ - Don't log WooCommerce scheduled actions. Fixes https://wordpress.org/support/topic/cant-use-flooded-with-deleted-scheduled-action-woocommerce-webhooks/.
202
+ - Store if post password has been set, unset, or changed.
203
+ - Store if a log entry comes from the REST API. Stored in the event context as `_rest_api_request`.
204
+ - Check that logger messages exists and is array before trying to use.
205
+ - Bump required version in readme to 5.4. It's just to difficult to keep the plugin compatible with PHP less than [PHP version 5.4](http://php.net/manual/en/migration54.new-features.php).
206
+ - Updates to some translation strings.
207
+
208
  = 2.29.2 (January 2019) =
209
 
210
  - Fix for (the still great) plugin [Advanced Custom Fields](http://advancedcustomfields.com) 5.7.10 that removed the function `_acf_get_field_by_id` that this plugin used. Fixes https://wordpress.org/support/topic/uncaught-error-call-to-undefined-function-_acf_get_field_by_id/.
216
  = 2.29 (December 2018) =
217
 
218
  - Make log welcome message translateable.
219
+ - Add two filters to make it more ease to control via filters if a logger and the combination logger + message should be logged. - `"simple_history/log/do_log/{$this->slug}"` controls if any messages for a specific logger should be logged. Simply return false to this filter to disable all logging to that logger. - `"simple_history/log/do_log/{$this->slug}/{$message_key}"` controls if a specific message for a specific logger should be logged. Simply return false to this filter to disable all logging to that logger. - Code examples for the two filters above:
220
+ ```
221
+ // Disable logging of any user message, i.e. any message from the logger SimpleUserLogger.
222
+ add_filter( 'simple_history/log/do_log/SimpleUserLogger', '\_\_return_false' );
223
+
224
+ // Disable logging of updated posts, i.e. the message "post_updated" from the logger SimplePostLogger.
225
+ add_filter( 'simple_history/log/do_log/SimplePostLogger/post_updated', '__return_false' );
226
+ ```
227
+
228
+ - add_filter('simple_history/log/do_log/SimpleUserLogger', '\_\_return_false');
 
 
229
  - Fix notice in Redirection plugin logger due because redirection plugin can have multiple target types. Props @MaximVanhove.
230
  - Fix warning because of missing logging messages in the categories/tags logger. Props @JeroenSormani.
231
  - Fix warning in the next version of PHP, PHP 7.3.
258
  - Add support for the [Jetpack plugin](https://wordpress.org/plugins/jetpack/). To begin with, activation and deactivation of Jetpack modules is logged.
259
  - Add logging of translation updates, so now you can see when a plugin or a theme has gotten new translations. Fixes https://github.com/bonny/WordPress-Simple-History/issues/147.
260
  - Fix notice in Advanced Custom Fields logger when saving an ACF options page.
261
+ Fixes https://wordpress.org/support/topic/problem-with-acf-options-pages/, https://wordpress.org/support/topic/problem-with-recent-version-and-acf/, https://github.com/bonny/WordPress-Simple-History/issues/145.
262
 
263
  = 2.25 (July 2018) =
264
 
281
 
282
  = 2.23 (May 2018) =
283
 
284
+ - Add logging of privacy and GDPR related functions in WordPress. Some of the new [privacy related features in WordPress 4.9.6](https://wordpress.org/news/2018/05/wordpress-4-9-6-privacy-and-maintenance-release/) that are logged: - Privacy policy page is created or changed to a new page. - Privacy data export is requested for a user and when this request is confirmed by the user and when the data for the request is downloaded by an admin or emailed to the user. - Erase Personal Data: Request is added for user to have their personal data erased, user confirms the data removal and when the deletion of user data is done.
 
 
 
285
  - Fix error when categories changes was shown in the log. Fixes https://wordpress.org/support/topic/php-notice-undefined-variable-term_object/.
286
  - Fix error when a ACF Field Group was saved.
287
  - Fix error when the IP address anonymization function tried to anonymize an empty IP adress. Could happen when for example running wp cron locally on your server.
297
  = 2.22 (May 2018) =
298
 
299
  - IP addresses are now anonymized by default. This is mainly done because of the [General Data Protection Regulation](https://en.wikipedia.org/wiki/General_Data_Protection_Regulation) (GDPR)
300
+ Both IPv4 and IPv6 addresses will be anonymized and the IP addresses are anonymized to their network ID.
301
+ So for example the IPv4 address `192.168.123.124` is anonymized to `192.168.123.0` and
302
+ the IPv6 address `2a03:2880:2110:df07:face:b00c::1` is anonymized by default to `2610:28:3090:3001::`.
303
 
304
  - Added filter `simple_history/privacy/anonymize_ip_address` than can be used to disable ip address anonymization.
305
 
307
 
308
  - Fixed logging for [plugin Redirection](https://wordpress.org/plugins/redirection/). The logging of URL redirects and so on stopped working some while back because the Redirection plugin started using the WP REST API. But now it's working again!
309
 
 
310
  = 2.21.1 (May 2018) =
311
 
312
  - Make sure support for Advanced Custom Fields is activated for all users – and not only for the developer of the plugin ;)
313
 
 
314
  = 2.21 (May 2018) =
315
 
316
  - Added support for Advanced Custom Fields (ACF): when a ACF Field or ACF Field Group is created or modified or deleted you will now get more details in the activity feed.
371
 
372
  - Added [WP-CLI](https://wp-cli.org) command for Simple History. Now you can write `wp simple-history list` to see the latest entries from the history log. For now `list` is the only available command. Let me know if you need more commands!
373
  - Added support for logging edits to theme files and plugin files. When a file is edited you will also get a quick diff on the changes,
374
+ so you can see what CSS styles a client changed or what PHP changes they made in a plugin file.
375
  - Removed the edit file logger from the plugin logger, because it did not always work (checked wrong wp path). Intead the new Theme and plugins logger mentioned above will take care of this.
376
 
377
  = 2.15 (May 2017) =
378
 
379
  - Use thumbnail version of PDF preview instead of full size image.
380
  - Remove Google Maps image when clicking IP address of failed login and similar, because Google Maps must be used with API key.
381
+ Hostname, Network, City, Region and Country is still shown.
382
  - Fix notice in available updates logger.
383
  - Fix notice in redirection logger.
384
 
389
  = 2.14 (April 2017) =
390
 
391
  - Added support for plugin [Duplicate Post](https://wordpress.org/plugins/duplicate-post/).
392
+ Now when a user clones a post or page you will se this in the history log, with links to both the original post and the new copy.
393
  - Removed log level info from title in RSS feed
394
  - Make date dropdown less "jumpy" when loading page (due to select element switching to Select2)
395
  - Only add filters for plugin Limit Login Attempts if plugin is active. This fixes problem with Limit Login Attempts Reloaded and possibly other forks of the plugin.
411
  = 2.11 (September 2016) =
412
 
413
  - Added support for plugin [Redirection](https://wordpress.org/plugins/redirection/).
414
+ Redirects and groups that are created, changed, enabled and disabled will be logged. Also when the plugin global settings are changed that will be logged.
415
  - Fix possible notice error from User logger.
416
  - "View changelog" link now works on multisite.
417
 
418
  = 2.10 (September 2016) =
419
 
420
  - Available updates to plugins, themes, and WordPress itself is now logged.
421
+ Pretty great if you subscribe to the RSS feed to get the changes on a site. No need to manually check the updates-page to see if there are any updates.
422
  - Changed to logic used to determine if a post edit should be logged or not. Version 2.9 used a version that started to log a bit to much for some plugins. This should fix the problems with the Nextgen Gallery, All-In-One Events Calendar, and Membership 2 plugins. If you still have problems with a plugin that is causing to many events to be logged, please let me know!
423
 
424
  = 2.9.1 (August 2016) =
425
 
426
  - Fixed an issue where the logged time was off by some hours, due to timezone being manually set elsewhere.
427
+ Should fix https://wordpress.org/support/topic/logged-time-off-by-2-hours and https://wordpress.org/support/topic/different-time-between-dashboard-and-logger.
428
  - Fixed Nextgen Gallery and Nextgen Gallery Plus logging lots and lots of event when viewing posts with galleries. The posts was actually updated, so this plugin did nothing wrong. But it was indeed a bit annoying and most likely something you didn't want in your log. Fixes https://wordpress.org/support/topic/non-stop-logging-nextgen-gallery-items.
429
 
430
  = 2.9 (August 2016) =
441
  - ...and so are theme updates
442
  - ...and theme deletions. Awesome!
443
  - Support for plugin [Limit Login Attempts](https://wordpress.org/plugins/limit-login-attempts/).
444
+ Failed login attempts, lockouts and configuration changes will be logged.
445
  - Correct message is now used when a plugin update fails, i.e. the message for key `plugin_update_failed`.
446
  - The original untranslated strings for plugin name and so on are stored when storing info for plugin installs and updates and similar.
447
  - Default number of events to show is now 10 instead of 5.
450
 
451
  - User logins using e-mail are now logged correctly. Previously the user would be logged in successfully but the log said that they failed.
452
  - Security fix: only users with [`list_users`](https://codex.wordpress.org/Roles_and_Capabilities#list_users) capability can view the users filter and use the autocomplete api for users.
453
+ Previously the autocomplete function could be used by all logged in users.
454
  - Add labels to search filters. (I do really hate label-less forms so it's kinda very strange that this was not in place before.)
455
  - Misc other internal fixes
456
 
463
 
464
  = 2.7.3 (June 2016) =
465
 
466
+ - Removed the usage of the mb\_\* functions and mbstring is no longer a requirement.
467
  - Added a new debug tab to the settings page. On the debug page you can see stuff like how large your database is and how many rows that are stored in the database. Also, a list of all loggers are listed there together with some useful (for developers anyway) information.
468
 
469
  = 2.7.2 (June 2016) =
vendor/autoload.php CHANGED
@@ -4,4 +4,4 @@
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
- return ComposerAutoloaderInitc9523a152a88c1bbdc6b5f12b52cd556::getLoader();
4
 
5
  require_once __DIR__ . '/composer/autoload_real.php';
6
 
7
+ return ComposerAutoloaderInit3f19e1fe69ca77f96f946c9d4920fd62::getLoader();
vendor/composer/ClassLoader.php CHANGED
@@ -279,7 +279,7 @@ class ClassLoader
279
  */
280
  public function setApcuPrefix($apcuPrefix)
281
  {
282
- $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
283
  }
284
 
285
  /**
@@ -377,11 +377,11 @@ class ClassLoader
377
  $subPath = $class;
378
  while (false !== $lastPos = strrpos($subPath, '\\')) {
379
  $subPath = substr($subPath, 0, $lastPos);
380
- $search = $subPath.'\\';
381
  if (isset($this->prefixDirsPsr4[$search])) {
 
382
  foreach ($this->prefixDirsPsr4[$search] as $dir) {
383
- $length = $this->prefixLengthsPsr4[$first][$search];
384
- if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
385
  return $file;
386
  }
387
  }
279
  */
280
  public function setApcuPrefix($apcuPrefix)
281
  {
282
+ $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
283
  }
284
 
285
  /**
377
  $subPath = $class;
378
  while (false !== $lastPos = strrpos($subPath, '\\')) {
379
  $subPath = substr($subPath, 0, $lastPos);
380
+ $search = $subPath . '\\';
381
  if (isset($this->prefixDirsPsr4[$search])) {
382
+ $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
383
  foreach ($this->prefixDirsPsr4[$search] as $dir) {
384
+ if (file_exists($file = $dir . $pathEnd)) {
 
385
  return $file;
386
  }
387
  }
vendor/composer/autoload_real.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
- class ComposerAutoloaderInitc9523a152a88c1bbdc6b5f12b52cd556
6
  {
7
  private static $loader;
8
 
@@ -19,15 +19,15 @@ class ComposerAutoloaderInitc9523a152a88c1bbdc6b5f12b52cd556
19
  return self::$loader;
20
  }
21
 
22
- spl_autoload_register(array('ComposerAutoloaderInitc9523a152a88c1bbdc6b5f12b52cd556', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInitc9523a152a88c1bbdc6b5f12b52cd556', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
- call_user_func(\Composer\Autoload\ComposerStaticInitc9523a152a88c1bbdc6b5f12b52cd556::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
2
 
3
  // autoload_real.php @generated by Composer
4
 
5
+ class ComposerAutoloaderInit3f19e1fe69ca77f96f946c9d4920fd62
6
  {
7
  private static $loader;
8
 
19
  return self::$loader;
20
  }
21
 
22
+ spl_autoload_register(array('ComposerAutoloaderInit3f19e1fe69ca77f96f946c9d4920fd62', 'loadClassLoader'), true, true);
23
  self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
+ spl_autoload_unregister(array('ComposerAutoloaderInit3f19e1fe69ca77f96f946c9d4920fd62', 'loadClassLoader'));
25
 
26
  $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
  if ($useStaticLoader) {
28
  require_once __DIR__ . '/autoload_static.php';
29
 
30
+ call_user_func(\Composer\Autoload\ComposerStaticInit3f19e1fe69ca77f96f946c9d4920fd62::getInitializer($loader));
31
  } else {
32
  $map = require __DIR__ . '/autoload_namespaces.php';
33
  foreach ($map as $namespace => $path) {
vendor/composer/autoload_static.php CHANGED
@@ -4,7 +4,7 @@
4
 
5
  namespace Composer\Autoload;
6
 
7
- class ComposerStaticInitc9523a152a88c1bbdc6b5f12b52cd556
8
  {
9
  public static function getInitializer(ClassLoader $loader)
10
  {
4
 
5
  namespace Composer\Autoload;
6
 
7
+ class ComposerStaticInit3f19e1fe69ca77f96f946c9d4920fd62
8
  {
9
  public static function getInitializer(ClassLoader $loader)
10
  {