Simple History - Version 2.22

Version Description

(May 2018) =

  • IP addresses are now anonymized by default. This is mainly done because of the General Data Protection Regulation (GDPR) Both IPv4 and IPv6 addresses will be anonymized and the IP addresses are anonymized to their network ID. So for example the IPv4 address 192.168.123.124 is anonymized to 192.168.123.0 and the IPv6 address 2a03:2880:2110:df07:face:b00c::1 is anonymized by default to 2610:28:3090:3001::.

  • Added filter simple_history/privacy/anonymize_ip_address than can be used to disable ip address anonymization.

  • Added function sh_error_log() to easily log variables to the error log. Probably only of interest to developers.

  • Fixed logging for plugin 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!

Download this release

Release Info

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

Code changes from version 2.21.1 to 2.22

dropins/SimpleHistoryRSSDropin.php CHANGED
@@ -288,43 +288,6 @@ class SimpleHistoryRSSDropin {
288
  <link><![CDATA[<?php echo $item_link ?>]]></link>
289
  </item>
290
  <?php
291
- /*
292
- [0] =&gt; stdClass Object
293
- (
294
- [id] =&gt; 27324
295
- [logger] =&gt; SimplePluginLogger
296
- [level] =&gt; info
297
- [date] =&gt; 2014-10-15 06:50:01
298
- [message] =&gt; Updated plugin &quot;{plugin_name}&quot; from {plugin_prev_version} to {plugin_version}
299
- [type] =&gt;
300
- [initiator] =&gt; wp_user
301
- [occasionsID] =&gt; 75e8aeab3e43b37f8a458f3744c4995f
302
- [subsequentOccasions] =&gt; 1
303
- [rep] =&gt; 1
304
- [repeated] =&gt; 1
305
- [occasionsIDType] =&gt; 75e8aeab3e43b37f8a458f3744c4995f
306
- [context] =&gt; Array
307
- (
308
- [plugin_slug] =&gt; google-analytics-for-wordpress
309
- [plugin_name] =&gt; Google Analytics by Yoast
310
- [plugin_title] =&gt; &lt;a href=&quot;https://yoast.com/wordpress/plugins/google-analytics/#utm_source=wordpress&amp;#038;utm_medium=plugin&amp;#038;utm_campaign=wpgaplugin&amp;#038;utm_content=v504&quot;&gt;Google Analytics by Yoast&lt;/a&gt;
311
- [plugin_description] =&gt; This plugin makes it simple to add Google Analytics to your WordPress blog, adding lots of features, eg. error page, search result and automatic clickout and download tracking. &lt;cite&gt;By &lt;a href=&quot;https://yoast.com/&quot;&gt;Team Yoast&lt;/a&gt;.&lt;/cite&gt;
312
- [plugin_author] =&gt; &lt;a href=&quot;https://yoast.com/&quot;&gt;Team Yoast&lt;/a&gt;
313
- [plugin_version] =&gt; 5.0.7
314
- [plugin_url] =&gt; https://yoast.com/wordpress/plugins/google-analytics/#utm_source=wordpress&amp;#038;utm_medium=plugin&amp;#038;utm_campaign=wpgaplugin&amp;#038;utm_content=v504
315
- [plugin_update_info_plugin] =&gt; google-analytics-for-wordpress/googleanalytics.php
316
- [plugin_update_info_package] =&gt; https://downloads.wordpress.org/plugin/google-analytics-for-wordpress.5.0.7.zip
317
- [plugin_prev_version] =&gt; 5.0.6
318
- [_message_key] =&gt; plugin_bulk_updated
319
- [_user_id] =&gt; 1
320
- [_user_login] =&gt; admin
321
- [_user_email] =&gt; par.thernstrom@gmail.com
322
- [_server_remote_addr] =&gt; ::1
323
- [_server_http_referer] =&gt; http://playground-root.ep/wp-admin/update-core.php?action=do-plugin-upgrade
324
- )
325
-
326
- )
327
- */
328
  } // End foreach().
329
 
330
  ?>
288
  <link><![CDATA[<?php echo $item_link ?>]]></link>
289
  </item>
290
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
291
  } // End foreach().
292
 
293
  ?>
dropins/SimpleHistoryWPCLIDropin.php CHANGED
@@ -150,36 +150,6 @@ class SimpleHistoryWPCLIDropin {
150
  );
151
  }
152
 
153
- // print_r($events);
154
- // print_r($eventsCleaned);
155
- /*
156
- [9] => stdClass Object
157
- (
158
- [id] => 735
159
- [logger] => AvailableUpdatesLogger
160
- [level] => notice
161
- [date] => 2017-05-19 12:45:13
162
- [message] => Found an update to plugin "{plugin_name}"
163
- [initiator] => wp
164
- [occasionsID] => 9a2d42eebea5c3cd2b16db0c38258016
165
- [subsequentOccasions] => 1
166
- [rep] => 1
167
- [repeated] => 10
168
- [occasionsIDType] => 9a2d42eebea5c3cd2b16db0c38258016
169
- [context_message_key] => plugin_update_available
170
- [context] => Array
171
- (
172
- [plugin_name] => WooCommerce
173
- [plugin_current_version] => 3.0.6
174
- [plugin_new_version] => 3.0.7
175
- [_message_key] => plugin_update_available
176
- [_server_remote_addr] => ::1
177
- [_server_http_referer] => http://wp-playground.dev/wp/wp-cron.php?doing_wp_cron=1495197902.1593680381774902343750
178
- )
179
-
180
- )
181
- */
182
-
183
  $fields = array(
184
  'date',
185
  'initiator',
150
  );
151
  }
152
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  $fields = array(
154
  'date',
155
  'initiator',
inc/SimpleHistory.php CHANGED
@@ -2479,7 +2479,7 @@ Because Simple History was just recently installed, this feed does not contain m
2479
  * Works like json_encode, but adds JSON_PRETTY_PRINT if the current php version supports it
2480
  * i.e. PHP is 5.4.0 or greated
2481
  *
2482
- * @param $value array|object|string|whatever that is json_encode'able
2483
  */
2484
  public static function json_encode( $value ) {
2485
 
@@ -3575,3 +3575,29 @@ function simple_history_text_diff( $left_string, $right_string, $args = null ) {
3575
 
3576
  return $r;
3577
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2479
  * Works like json_encode, but adds JSON_PRETTY_PRINT if the current php version supports it
2480
  * i.e. PHP is 5.4.0 or greated
2481
  *
2482
+ * @param mixed $value array|object|string|whatever that is json_encode'able.
2483
  */
2484
  public static function json_encode( $value ) {
2485
 
3575
 
3576
  return $r;
3577
  }
3578
+
3579
+ /**
3580
+ * Log variable(s) to error log.
3581
+ * Any number of variables can be passed and each variable is print_r'ed to the error log.
3582
+ *
3583
+ * Example usage:
3584
+ * sh_error_log(
3585
+ * 'rest_request_after_callbacks:',
3586
+ * $handler,
3587
+ * $handler['callback'][0],
3588
+ * $handler['callback'][1]
3589
+ * );
3590
+ */
3591
+ function sh_error_log() {
3592
+ foreach ( func_get_args() as $var ) {
3593
+ if ( is_bool( $var ) ) {
3594
+ $bool_string = true === $var ? 'true' : 'false';
3595
+ error_log( "$bool_string (boolean value)" );
3596
+ } elseif ( is_null( $var ) ) {
3597
+ error_log( 'null (null value)' );
3598
+ } else {
3599
+ error_log( print_r( $var, true ) );
3600
+ }
3601
+ }
3602
+ }
3603
+
inc/SimpleHistoryIpAnonymizer.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * IpAnonymizer class from https://github.com/geertw/php-ip-anonymizer
4
+ *
5
+ * Modified by removing namespace to make it work on PHP < 5.3 and renaming it
6
+ * to minimize multiple classes with same name.
7
+ */
8
+
9
+ class SimpleHistoryIpAnonymizer {
10
+ /**
11
+ * @var string IPv4 netmask used to anonymize IPv4 address.
12
+ */
13
+ public $ipv4NetMask = "255.255.255.0";
14
+
15
+ /**
16
+ * @var string IPv6 netmask used to anonymize IPv6 address.
17
+ */
18
+ public $ipv6NetMask = "ffff:ffff:ffff:ffff:0000:0000:0000:0000";
19
+
20
+ /**
21
+ * Anonymize an IPv4 or IPv6 address.
22
+ *
23
+ * @param $address string IP address that must be anonymized
24
+ * @return string The anonymized IP address. Returns an empty string when the IP address is invalid.
25
+ */
26
+ public static function anonymizeIp($address) {
27
+ $anonymizer = new SimpleHistoryIpAnonymizer();
28
+ return $anonymizer->anonymize($address);
29
+ }
30
+
31
+ /**
32
+ * Anonymize an IPv4 or IPv6 address.
33
+ *
34
+ * @param $address string IP address that must be anonymized
35
+ * @return string The anonymized IP address. Returns an empty string when the IP address is invalid.
36
+ */
37
+ public function anonymize($address) {
38
+ $packedAddress = inet_pton($address);
39
+
40
+ if (strlen($packedAddress) == 4) {
41
+ return $this->anonymizeIPv4($address);
42
+ } elseif (strlen($packedAddress) == 16) {
43
+ return $this->anonymizeIPv6($address);
44
+ } else {
45
+ return "";
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Anonymize an IPv4 address
51
+ * @param $address string IPv4 address
52
+ * @return string Anonymized address
53
+ */
54
+ public function anonymizeIPv4($address) {
55
+ return inet_ntop(inet_pton($address) & inet_pton($this->ipv4NetMask));
56
+ }
57
+
58
+ /**
59
+ * Anonymize an IPv6 address
60
+ * @param $address string IPv6 address
61
+ * @return string Anonymized address
62
+ */
63
+ public function anonymizeIPv6($address) {
64
+ return inet_ntop(inet_pton($address) & inet_pton($this->ipv6NetMask));
65
+ }
66
+ }
index.php CHANGED
@@ -5,7 +5,7 @@
5
  * Text Domain: simple-history
6
  * Domain Path: /languages
7
  * Description: Plugin that logs various things that occur in WordPress and then presents those events in a very nice GUI.
8
- * Version: 2.21.1
9
  * Author: Pär Thernström
10
  * Author URI: http://simple-history.com/
11
  * License: GPL2
@@ -32,9 +32,8 @@ if ( ! defined( 'WPINC' ) ) {
32
  die;
33
  }
34
 
35
- // Plugin requires at least version "4.5.1", because usage of functions like wp_get_raw_referer
36
-
37
- // true if version ok, false if too old version
38
  $ok_wp_version = version_compare( $GLOBALS['wp_version'], "4.5.1", '>=' );
39
  $ok_php_version = version_compare( phpversion(), '5.3', '>=' );
40
 
@@ -48,7 +47,7 @@ if ( $ok_php_version && $ok_wp_version ) {
48
  */
49
 
50
  if ( ! defined( 'SIMPLE_HISTORY_VERSION' ) ) {
51
- define( 'SIMPLE_HISTORY_VERSION', '2.21.1' );
52
  }
53
 
54
  if ( ! defined( 'SIMPLE_HISTORY_PATH' ) ) {
@@ -70,6 +69,7 @@ if ( $ok_php_version && $ok_wp_version ) {
70
  /** Load required files */
71
  require_once( __DIR__ . '/inc/SimpleHistory.php' );
72
  require_once( __DIR__ . '/inc/SimpleHistoryLogQuery.php' );
 
73
 
74
  /**
75
  Constants will be like:
5
  * Text Domain: simple-history
6
  * Domain Path: /languages
7
  * Description: Plugin that logs various things that occur in WordPress and then presents those events in a very nice GUI.
8
+ * Version: 2.22
9
  * Author: Pär Thernström
10
  * Author URI: http://simple-history.com/
11
  * License: GPL2
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
 
47
  */
48
 
49
  if ( ! defined( 'SIMPLE_HISTORY_VERSION' ) ) {
50
+ define( 'SIMPLE_HISTORY_VERSION', '2.22' );
51
  }
52
 
53
  if ( ! defined( 'SIMPLE_HISTORY_PATH' ) ) {
69
  /** Load required files */
70
  require_once( __DIR__ . '/inc/SimpleHistory.php' );
71
  require_once( __DIR__ . '/inc/SimpleHistoryLogQuery.php' );
72
+ require_once( __DIR__ . '/inc/SimpleHistoryIpAnonymizer.php' );
73
 
74
  /**
75
  Constants will be like:
loggers/Plugin_Redirection.php CHANGED
@@ -1,18 +1,31 @@
1
  <?php
2
 
3
- defined( 'ABSPATH' ) or die();
4
 
5
  /**
6
  * Logger for the Redirection plugin
7
- * https://sv.wordpress.org/plugins/redirection/
8
  */
9
  if ( ! class_exists( 'Plugin_Redirection' ) ) {
10
 
 
 
 
11
  class Plugin_Redirection extends SimpleLogger {
12
 
 
 
 
 
 
13
  public $slug = __CLASS__;
14
 
15
- function getInfo() {
 
 
 
 
 
16
 
17
  $arr_info = array(
18
  'name' => 'Redirection',
@@ -21,15 +34,18 @@ if ( ! class_exists( 'Plugin_Redirection' ) ) {
21
  'capability' => 'manage_options',
22
  'messages' => array(
23
  'redirection_redirection_added' => _x( 'Added a redirection for URL "{source_url}"', 'Logger: Redirection', 'simple-history' ),
24
- 'redirection_redirection_edited' => _x( 'Edited the redirection for URL "{source_url}', 'Logger: Redirection', 'simple-history' ),
25
- 'redirection_redirection_enabled' => _x( 'Enabled the redirection for {items_count} URL(s)', 'Logger: Redirection', 'simple-history' ),
26
- 'redirection_redirection_disabled' => _x( 'Disabled the redirection for {items_count} URL(s)', 'Logger: Redirection', 'simple-history' ),
27
- 'redirection_redirection_removed' => _x( 'Removed redirection for {items_count} URL(s)', 'Logger: Redirection', 'simple-history' ),
28
- 'redirection_options_saved' => _x( 'Updated options', 'Logger: Redirection', 'simple-history' ),
29
- 'redirection_options_removed_all' => _x( 'Removed all options and deactivated plugin', 'Logger: Redirection', 'simple-history' ),
30
- 'redirection_group_added' => _x( 'Added group "{group_name}"', 'Logger: Redirection', 'simple-history' ),
31
- 'redirection_group_deleted' => _x( 'Deleted {items_count} group(s)', 'Logger: Redirection', 'simple-history' ),
 
 
32
  ),
 
33
  /*
34
  "labels" => array(
35
  "search" => array(
@@ -55,270 +71,130 @@ if ( ! class_exists( 'Plugin_Redirection' ) ) {
55
  ) // end search array
56
  ) // end labels
57
  */
58
-
59
  );
60
 
61
  return $arr_info;
62
 
63
  }
64
 
65
- function loaded() {
66
-
67
- // Catch redirection create, enable, disable
68
- add_action( 'admin_init', array( $this, 'on_admin_init' ) );
69
-
70
- // Catch edit existing redirect
71
- add_action( 'wp_ajax_red_redirect_save', array( $this, 'on_edit_save_redirect' ) );
72
-
73
- } // loaded
74
-
75
- function on_edit_save_redirect() {
76
-
77
- /*
78
- Edit and save redirection
79
- {
80
- "old": "\/my-edited-old-page-again\/",
81
- "title": "",
82
- "group_id": "1",
83
- "target": "\/my-edited-new-page-again\/",
84
- "action_code": "301",
85
- "action": "red_redirect_save",
86
- "id": "7",
87
- "_wpnonce": "732a2bb825",
88
- "_wp_http_referer": "\/wp-admin\/admin-ajax.php"
89
- }
90
- _wpnonce:abfaeae905
91
- _wp_http_referer:/wp-admin/admin-ajax.php
92
- */
93
- $this->log_redirection_edit( $_REQUEST );
94
-
95
  }
96
 
97
  /**
98
- * Check if request is an create or enable/disable redirection
 
 
 
 
 
 
99
  */
100
- function on_admin_init() {
101
-
102
- $referer = wp_get_raw_referer();
103
-
104
- // We only continue if referer contains page=redirection.php
105
- if ( false === strpos( $referer, 'page=redirection.php' ) ) {
106
- return;
107
- }
108
-
109
- $referer_parsed = parse_url( $referer );
110
-
111
- /*
112
- Create redirection
113
- {
114
- "source": "source yo",
115
- "match": "url",
116
- "red_action": "url",
117
- "target": "dest yo",
118
- "group_id": "1",
119
- "add": "Add Redirection",
120
- "group": "0",
121
- "action": "red_redirect_add",
122
- "_wpnonce": "cdadb5a4ca",
123
- "_wp_http_referer": "\/wp-admin\/tools.php?page=redirection.php"
124
- }
125
- */
126
- if ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'red_redirect_add' ) {
127
- $this->log_redirection_add( $_REQUEST );
128
- return;
129
- }
130
-
131
- /*
132
- Enable/disable single or multiple direction(s)
133
- {
134
- "page": "redirection.php",
135
- "_wpnonce": "290f261024",
136
- "_wp_http_referer": "\/wp-admin\/tools.php?page=redirection.php",
137
- "action": "enable", or "disable"
138
- "id": "0",
139
- "paged": "1",
140
- "item": [
141
- "3",
142
- "2",
143
- "1"
144
- ],
145
- "action2": "-1"
146
- }
147
- */
148
- if ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'enable' && empty( $_REQUEST['sub'] ) ) {
149
- $this->log_redirection_enable_or_disable( $_REQUEST );
150
- return;
151
- } elseif ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'disable' && empty( $_REQUEST['sub'] ) ) {
152
- $this->log_redirection_enable_or_disable( $_REQUEST );
153
- return;
154
- }
155
-
156
- /*
157
- Delete item(s)
158
- {
159
- "page": "redirection.php",
160
- "edit": "4",
161
- "_wpnonce": "290f261024",
162
- "_wp_http_referer": "\/wp-admin\/tools.php?page=redirection.php&edit=4",
163
- "action": "delete",
164
- "id": "0",
165
- "paged": "1",
166
- "item": [
167
- "6"
168
- ],
169
- "action2": "-1"
170
- }
171
- */
172
- if ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'delete' && empty( $_REQUEST['sub'] ) ) {
173
- $this->log_redirection_delete( $_REQUEST );
174
- return;
175
- }
176
-
177
- /*
178
- Options
179
- - delete all options and deactivate plugin
180
- {
181
- "page": "redirection.php",
182
- "sub": "options",
183
- "_wpnonce": "e2c008ca25",
184
- "_wp_http_referer": "\/wp-admin\/tools.php?page=redirection.php&sub=options",
185
- "delete": "Delete"
186
- }
187
- */
188
- if ( isset( $_REQUEST['sub'] ) && $_REQUEST['sub'] == 'options' && isset( $_REQUEST['delete'] ) && $_REQUEST['delete'] == 'Delete' ) {
189
- $this->log_options_delete_all( $_REQUEST );
190
- return;
191
- }
192
-
193
- /*
194
- Save options {
195
- "page": "redirection.php",
196
- "sub": "options",
197
- "_wpnonce": "8fe9b57662",
198
- "_wp_http_referer": "\/wp-admin\/tools.php?page=redirection.php&sub=options",
199
- "support": "on",
200
- "expire_redirect": "7",
201
- "expire_404": "7",
202
- "monitor_post": "0",
203
- "token": "acf88715b12038e3aca1ae1b3d82132a",
204
- "auto_target": "",
205
- "update": "Update"
206
- }
207
- */
208
- if (
209
- isset( $_REQUEST['sub'] ) && $_REQUEST['sub'] == 'options' &&
210
- isset( $_REQUEST['update'] ) && $_REQUEST['update'] == 'Update'
211
-
212
- ) {
213
- $this->log_options_save( $_REQUEST );
214
- return;
215
- }
216
-
217
- /*
218
- Add group
219
- {
220
- "page": "redirection.php",
221
- "sub": "groups",
222
- "_wpnonce": "4cac237744",
223
- "_wp_http_referer": "\/wp-admin\/tools.php?page=redirection.php&sub=groups",
224
- "name": "new group yo",
225
- "module_id": "1",
226
- "add": "Add"
227
- }
228
- */
229
- if (
230
- isset( $_REQUEST['sub'] ) && $_REQUEST['sub'] == 'groups' &&
231
- isset( $_REQUEST['add'] ) && $_REQUEST['add'] == 'Add'
232
- ) {
233
- $this->log_group_add( $_REQUEST );
234
- return;
235
- }
236
 
237
- /*
238
- Delete group(s)
239
- {
240
- "page": "redirection.php",
241
- "sub": "groups",
242
- "_wpnonce": "290f261024",
243
- "_wp_http_referer": "\/wp-admin\/tools.php?page=redirection.php&sub=groups",
244
- "action": "-1",
245
- "id": "0",
246
- "paged": "1",
247
- "item": [
248
- "3",
249
- "2"
250
- ],
251
- "action2": "delete"
252
- }
253
- */
254
- if (
255
- isset( $_REQUEST['sub'] ) && $_REQUEST['sub'] == 'groups' &&
256
- isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'delete'
257
- ) {
258
- $this->log_group_delete( $_REQUEST );
259
- return;
260
  }
261
 
262
- /*
263
- Disable group(s)
264
- {
265
- "path": "\/wp-admin\/tools.php",
266
- "query": "page=redirection.php&sub=groups"
267
- }
268
- {
269
- "page": "redirection.php",
270
- "sub": "groups",
271
- "_wpnonce": "290f261024",
272
- "_wp_http_referer": "\/wp-admin\/tools.php?page=redirection.php&sub=groups",
273
- "action": "disable",
274
- "id": "0",
275
- "paged": "1",
276
- "item": [
277
- "1"
278
- ],
279
- "action2": "-1"
280
- }
281
- */
282
- if (
283
- isset( $_REQUEST['sub'] ) && $_REQUEST['sub'] == 'groups' &&
284
- isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'enable'
285
- ) {
286
- $this->log_group_enable_or_disable( $_REQUEST );
287
- return;
288
- } elseif (
289
- isset( $_REQUEST['sub'] ) && $_REQUEST['sub'] == 'groups' &&
290
- isset( $_REQUEST['action'] ) && $_REQUEST['action'] == 'disable'
291
- ) {
292
- $this->log_group_enable_or_disable( $_REQUEST );
293
- return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
294
  }
295
 
296
- } // on admin init
297
-
298
-
299
- function log_group_enable_or_disable() {
300
- // @HERE
301
  }
302
 
303
- function log_group_delete( $req ) {
304
-
305
- $items = isset( $req['item'] ) ? (array) $req['item'] : array();
306
-
 
 
 
307
  $context = array(
308
- 'items' => $items,
309
- 'items_count' => count( $items ),
310
  );
311
 
312
  $this->infoMessage(
313
  'redirection_group_deleted',
314
  $context
315
  );
316
-
317
  }
318
 
319
- function log_group_add( $req ) {
320
-
321
- $group_name = isset( $req['name'] ) ? $req['name'] : null;
 
 
 
 
322
 
323
  if ( ! $group_name ) {
324
  return;
@@ -332,122 +208,185 @@ if ( ! class_exists( 'Plugin_Redirection' ) ) {
332
  'redirection_group_added',
333
  $context
334
  );
335
-
336
  }
337
 
338
- function log_options_save( $req ) {
339
-
340
- $this->infoMessage( 'redirection_options_saved' );
341
-
342
- }
343
-
344
- function log_options_delete_all( $req ) {
345
-
346
- $this->infoMessage( 'redirection_options_removed_all' );
347
-
348
- }
349
-
350
- function log_redirection_delete( $req ) {
351
 
352
- $items = isset( $req['item'] ) ? (array) $req['item'] : array();
353
 
354
  $context = array(
355
- 'items' => $items,
356
- 'items_count' => count( $items ),
357
  );
358
 
359
- $message_key = 'redirection_redirection_removed';
360
-
361
  $this->infoMessage(
362
  $message_key,
363
  $context
364
  );
365
-
366
  }
367
 
368
- function log_redirection_edit( $req ) {
369
-
370
- /*
371
- log_redirection_edit
372
- {
373
- "old": "ddd changedaa",
374
- "regex": "on",
375
- "title": "this is descriptionaa",
376
- "group_id": "12",
377
- "user_agent": "Firefoxaa",
378
- "url_from": "eee changedaa",
379
- "url_notfrom": "not matched straa",
380
- "action": "red_redirect_save",
381
- "id": "7",
382
- "_wpnonce": "f15cdcdaea",
383
- "_wp_http_referer": "\/wp-admin\/admin-ajax.php"
384
- }
385
- */
386
 
 
 
 
 
 
 
 
387
  $context = array(
388
- 'source_url' => isset( $req['old'] ) ? $req['old'] : null,
389
- 'target_url' => isset( $req['target'] ) ? $req['target'] : null,
390
- 'item_id' => isset( $req['id'] ) ? $req['id'] : null,
391
- 'title' => isset( $req['title'] ) ? $req['title'] : null,
392
- 'regex' => isset( $req['regex'] ) ? true : false,
393
- 'group_id' => isset( $req['group_id'] ) ? $req['group_id'] : null,
394
- 'user_agent' => isset( $req['user_agent'] ) ? $req['user_agent'] : null,
395
- 'url_from' => isset( $req['url_from'] ) ? $req['url_from'] : null,
396
- 'url_notfrom' => isset( $req['url_notfrom'] ) ? $req['url_notfrom'] : null,
397
- 'action_code' => isset( $req['action_code'] ) ? $req['action_code'] : null,
398
  );
399
 
400
- $message_key = 'redirection_redirection_edited';
401
 
402
  $this->infoMessage(
403
  $message_key,
404
  $context
405
  );
406
-
407
  }
408
 
409
- function log_redirection_enable_or_disable( $req ) {
410
-
411
- $message_key = $req['action'] == 'enable' ? 'redirection_redirection_enabled' : 'redirection_redirection_disabled';
 
 
 
 
 
412
 
413
- $items = isset( $req['item'] ) ? (array) $req['item'] : array();
414
 
415
  $context = array(
416
- 'items' => $items,
417
- 'items_count' => count( $items ),
418
  );
419
 
420
  $this->infoMessage(
421
  $message_key,
422
  $context
423
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
424
 
 
 
 
 
 
 
425
  }
426
 
427
- function log_redirection_add( $req ) {
 
 
 
 
 
 
428
 
429
- if ( ! isset( $req['group_id'] ) ) {
430
- return;
431
  }
432
 
433
- $source = isset( $req['source'] ) ? $req['source'] : null;
434
- $target = isset( $req['target'] ) ? $req['target'] : null;
435
- $match = isset( $req['match'] ) ? $req['match'] : null;
436
- $action = isset( $req['action'] ) ? $req['action'] : null;
437
- $group_id = isset( $req['group_id'] ) ? $req['group_id'] : null;
438
- $regex = isset( $req['regex'] ) ? true : false;
439
 
440
  $context = array(
441
- 'source_url' => $source,
442
- 'target_url' => $target,
443
- 'match' => $match,
444
- 'action' => $action,
445
- 'group_id' => $group_id,
446
- 'regex' => $regex,
447
  );
448
 
449
- $this->infoMessage( 'redirection_redirection_added', $context );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
450
 
 
451
  }
452
 
453
  } // class
1
  <?php
2
 
3
+ defined( 'ABSPATH' ) || die();
4
 
5
  /**
6
  * Logger for the Redirection plugin
7
+ * https://wordpress.org/plugins/redirection/
8
  */
9
  if ( ! class_exists( 'Plugin_Redirection' ) ) {
10
 
11
+ /**
12
+ * Class to log things from the Redirection plugin.
13
+ */
14
  class Plugin_Redirection extends SimpleLogger {
15
 
16
+ /**
17
+ * Logger slug.
18
+ *
19
+ * @var string
20
+ */
21
  public $slug = __CLASS__;
22
 
23
+ /**
24
+ * Return info about logger.
25
+ *
26
+ * @return array Array with plugin info.
27
+ */
28
+ public function getInfo() {
29
 
30
  $arr_info = array(
31
  'name' => 'Redirection',
34
  'capability' => 'manage_options',
35
  'messages' => array(
36
  'redirection_redirection_added' => _x( 'Added a redirection for URL "{source_url}"', 'Logger: Redirection', 'simple-history' ),
37
+ 'redirection_redirection_edited' => _x( 'Edited redirection for URL "{prev_source_url}"', 'Logger: Redirection', 'simple-history' ),
38
+ 'redirection_redirection_enabled' => _x( 'Enabled redirection for {items_count} URL(s)', 'Logger: Redirection', 'simple-history' ),
39
+ 'redirection_redirection_disabled' => _x( 'Disabled redirection for {items_count} URL(s)', 'Logger: Redirection', 'simple-history' ),
40
+ 'redirection_redirection_deleted' => _x( 'Deleted redirection for {items_count} URL(s)', 'Logger: Redirection', 'simple-history' ),
41
+ 'redirection_options_saved' => _x( 'Updated redirection options', 'Logger: Redirection', 'simple-history' ),
42
+ 'redirection_options_removed_all' => _x( 'Removed all redirection options and deactivated plugin', 'Logger: Redirection', 'simple-history' ),
43
+ 'redirection_group_added' => _x( 'Added redirection group "{group_name}"', 'Logger: Redirection', 'simple-history' ),
44
+ 'redirection_group_enabled' => _x( 'Enabled {items_count} redirection group(s)', 'Logger: Redirection', 'simple-history' ),
45
+ 'redirection_group_disabled' => _x( 'Disabled {items_count} redirection group(s)', 'Logger: Redirection', 'simple-history' ),
46
+ 'redirection_group_deleted' => _x( 'Deleted {items_count} redirection group(s)', 'Logger: Redirection', 'simple-history' ),
47
  ),
48
+
49
  /*
50
  "labels" => array(
51
  "search" => array(
71
  ) // end search array
72
  ) // end labels
73
  */
 
74
  );
75
 
76
  return $arr_info;
77
 
78
  }
79
 
80
+ /**
81
+ * Called when logger is loaded.
82
+ */
83
+ public function loaded() {
84
+ // Redirection plugin uses the WP REST API, so catch when requests do the API is done.
85
+ // We use filter *_before_callbacks so we can access the old title
86
+ // of the Redirection object, i.e. before new values are saved.
87
+ add_filter( 'rest_request_before_callbacks', array( $this, 'on_rest_request_before_callbacks' ), 10, 3 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  }
89
 
90
  /**
91
+ * Fired when WP REST API call is done.
92
+ *
93
+ * @param WP_HTTP_Response $response Result to send to the client. Usually a WP_REST_Response.
94
+ * @param WP_REST_Server $handler ResponseHandler instance (usually WP_REST_Server).
95
+ * @param WP_REST_Request $request Request used to generate the response.
96
+ *
97
+ * @return WP_HTTP_Response $response
98
  */
99
+ public function on_rest_request_before_callbacks( $response, $handler, $request ) {
100
+ // API route callback object, for example "Redirection_Api_Redirect" Object.
101
+ $route_callback_object = isset( $handler['callback'][0] ) ? $handler['callback'][0] : false;
102
+ $route_callback_object_class = get_class( $route_callback_object );
103
+
104
+ // Method name to call on callback class, for example "route_bulk".
105
+ $route_callback_method = isset( $handler['callback'][1] ) ? $handler['callback'][1] : false;
106
+
107
+ $redirection_api_classes = array(
108
+ 'Redirection_Api_Redirect',
109
+ 'Redirection_Api_Group',
110
+ 'Redirection_Api_Settings',
111
+ );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
+ // Bail directly if this is not a Redirection API call.
114
+ if ( ! in_array( $route_callback_object_class, $redirection_api_classes ) ) {
115
+ return $response;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  }
117
 
118
+ if ( 'Redirection_Api_Redirect' == $route_callback_object_class && 'route_create' === $route_callback_method ) {
119
+ $this->log_redirection_add( $request );
120
+ } elseif ( 'route_update' === $route_callback_method ) {
121
+ $this->log_redirection_edit( $request );
122
+ } else if ( 'Redirection_Api_Redirect' == $route_callback_object_class && 'route_bulk' === $route_callback_method ) {
123
+ $bulk_action = $request->get_param( 'bulk' );
124
+
125
+ $bulk_items = $request->get_param( 'items' );
126
+ $bulk_items = explode( ',', $bulk_items );
127
+
128
+ if ( is_array( $bulk_items ) ) {
129
+ $bulk_items = array_map( 'intval', $bulk_items );
130
+ }
131
+
132
+ if ( empty( $bulk_items ) ) {
133
+ return $response;
134
+ }
135
+
136
+ if ( 'enable' === $bulk_action ) {
137
+ $this->log_redirection_enable_or_disable( $request, $bulk_items );
138
+ } elseif ( 'disable' === $bulk_action ) {
139
+ $this->log_redirection_enable_or_disable( $request, $bulk_items );
140
+ } elseif ( 'delete' === $bulk_action ) {
141
+ $this->log_redirection_delete( $request, $bulk_items );
142
+ }
143
+ } elseif ( 'Redirection_Api_Group' == $route_callback_object_class && 'route_create' === $route_callback_method ) {
144
+ $this->log_group_add( $request );
145
+ } else if ( 'Redirection_Api_Group' == $route_callback_object_class && 'route_bulk' === $route_callback_method ) {
146
+ $bulk_action = $request->get_param( 'bulk' );
147
+
148
+ $bulk_items = $request->get_param( 'items' );
149
+ $bulk_items = explode( ',', $bulk_items );
150
+
151
+ if ( is_array( $bulk_items ) ) {
152
+ $bulk_items = array_map( 'intval', $bulk_items );
153
+ }
154
+
155
+ if ( empty( $bulk_items ) ) {
156
+ return $response;
157
+ }
158
+
159
+ if ( 'enable' === $bulk_action ) {
160
+ $this->log_group_enable_or_disable( $request, $bulk_items );
161
+ } elseif ( 'disable' === $bulk_action ) {
162
+ $this->log_group_enable_or_disable( $request, $bulk_items );
163
+ } elseif ( 'delete' === $bulk_action ) {
164
+ $this->log_group_delete( $request, $bulk_items );
165
+ }
166
+ } else if ( 'Redirection_Api_Settings' == $route_callback_object_class ) {
167
+ $this->log_options_save( $request );
168
  }
169
 
170
+ return $response;
 
 
 
 
171
  }
172
 
173
+ /**
174
+ * Log when a Redirection group is deleted.
175
+ *
176
+ * @param object $req Request.
177
+ * @param array $bulk_items Array with item ids.
178
+ */
179
+ public function log_group_delete( $req, $bulk_items ) {
180
  $context = array(
181
+ 'items' => $bulk_items,
182
+ 'items_count' => count( $bulk_items ),
183
  );
184
 
185
  $this->infoMessage(
186
  'redirection_group_deleted',
187
  $context
188
  );
 
189
  }
190
 
191
+ /**
192
+ * Log when a Redirection grouop is added
193
+ *
194
+ * @param WP_REST_Request $req Request.
195
+ */
196
+ public function log_group_add( $req ) {
197
+ $group_name = $req->get_param( 'name' );
198
 
199
  if ( ! $group_name ) {
200
  return;
208
  'redirection_group_added',
209
  $context
210
  );
 
211
  }
212
 
213
+ /**
214
+ * Log enabling and disabling of redirection groups.
215
+ *
216
+ * @param object $req Request.
217
+ * @param array $bulk_items Array with item ids.
218
+ */
219
+ public function log_group_enable_or_disable( $req, $bulk_items ) {
220
+ $bulk_action = $req->get_param( 'bulk' );
 
 
 
 
 
221
 
222
+ $message_key = 'enable' === $bulk_action ? 'redirection_group_enabled' : 'redirection_group_disabled';
223
 
224
  $context = array(
225
+ 'items' => $bulk_items,
226
+ 'items_count' => count( $bulk_items ),
227
  );
228
 
 
 
229
  $this->infoMessage(
230
  $message_key,
231
  $context
232
  );
 
233
  }
234
 
235
+ /**
236
+ * Log when options are saved.
237
+ *
238
+ * @param object $req Request.
239
+ */
240
+ protected function log_options_save( $req ) {
241
+ $this->infoMessage( 'redirection_options_saved' );
242
+ }
 
 
 
 
 
 
 
 
 
 
243
 
244
+ /**
245
+ * Log the deletion of a redirection.
246
+ *
247
+ * @param object $req Request.
248
+ * @param array $bulk_items Array with item ids.
249
+ */
250
+ protected function log_redirection_delete( $req, $bulk_items ) {
251
  $context = array(
252
+ 'items' => $bulk_items,
253
+ 'items_count' => count( $bulk_items ),
 
 
 
 
 
 
 
 
254
  );
255
 
256
+ $message_key = 'redirection_redirection_deleted';
257
 
258
  $this->infoMessage(
259
  $message_key,
260
  $context
261
  );
 
262
  }
263
 
264
+ /**
265
+ * Log enable or disable of items.
266
+ *
267
+ * @param Object $req Req.
268
+ * @param Array $bulk_items Array.
269
+ */
270
+ protected function log_redirection_enable_or_disable( $req, $bulk_items ) {
271
+ $bulk_action = $req->get_param( 'bulk' );
272
 
273
+ $message_key = 'enable' === $bulk_action ? 'redirection_redirection_enabled' : 'redirection_redirection_disabled';
274
 
275
  $context = array(
276
+ 'items' => $bulk_items,
277
+ 'items_count' => count( $bulk_items ),
278
  );
279
 
280
  $this->infoMessage(
281
  $message_key,
282
  $context
283
  );
284
+ }
285
+
286
+ /**
287
+ * Log when a Redirection is added.
288
+ *
289
+ * @param WP_REST_Request $req Request.
290
+ */
291
+ protected function log_redirection_add( $req ) {
292
+ $action_data = $req->get_param( 'action_data' );
293
+
294
+ if ( ! $action_data || ! is_array( $action_data ) ) {
295
+ return false;
296
+ }
297
 
298
+ $context = array(
299
+ 'source_url' => $req->get_param( 'url' ),
300
+ 'target_url' => $action_data['url'],
301
+ );
302
+
303
+ $this->infoMessage( 'redirection_redirection_added', $context );
304
  }
305
 
306
+ /**
307
+ * Log when a Redirection is changed.
308
+ *
309
+ * @param WP_REST_Request $req Request.
310
+ */
311
+ protected function log_redirection_edit( $req ) {
312
+ $action_data = $req->get_param( 'action_data' );
313
 
314
+ if ( ! $action_data || ! is_array( $action_data ) ) {
315
+ return false;
316
  }
317
 
318
+ $message_key = 'redirection_redirection_edited';
319
+
320
+ $redirection_id = $req->get_param( 'id' );
 
 
 
321
 
322
  $context = array(
323
+ 'new_source_url' => $req->get_param( 'url' ),
324
+ 'new_target_url' => $action_data['url'],
325
+ 'redirection_id' => $redirection_id,
 
 
 
326
  );
327
 
328
+ // Get old values.
329
+ $redirection_item = Red_Item::get_by_id( $redirection_id );
330
+
331
+ if ( false !== $redirection_item ) {
332
+ $context['prev_source_url'] = $redirection_item->get_url();
333
+ $context['prev_target_url'] = $redirection_item->get_action_data();
334
+ }
335
+
336
+ $this->infoMessage(
337
+ $message_key,
338
+ $context
339
+ );
340
+ }
341
+
342
+ /**
343
+ * Return more info about an logged redirection event.
344
+ *
345
+ * @param array $row Row with info.
346
+ */
347
+ public function getLogRowDetailsOutput( $row ) {
348
+ $context = $row->context;
349
+ $message_key = $context['_message_key'];
350
+
351
+ $out = '';
352
+
353
+ if ( 'redirection_redirection_edited' === $message_key ) {
354
+ if ( $context['new_source_url'] !== $context['prev_source_url'] ) {
355
+ $diff_table_output = sprintf(
356
+ '<tr>
357
+ <td>%1$s</td>
358
+ <td>
359
+ <ins class="SimpleHistoryLogitem__keyValueTable__addedThing">%2$s</ins>
360
+ <del class="SimpleHistoryLogitem__keyValueTable__removedThing">%3$s</del>
361
+ </td>
362
+ </tr>',
363
+ esc_html_x( 'Source URL', 'Logger: Redirection', 'simple-history' ), // 1
364
+ esc_html( $context['new_source_url'] ), // 2
365
+ esc_html( $context['prev_source_url'] ) // 3
366
+ );
367
+
368
+ $out .= '<table class="SimpleHistoryLogitem__keyValueTable">' . $diff_table_output . '</table>';
369
+ }
370
+
371
+ if ( $context['new_target_url'] !== $context['prev_target_url'] ) {
372
+ $diff_table_output = sprintf(
373
+ '<tr>
374
+ <td>%1$s</td>
375
+ <td>
376
+ <ins class="SimpleHistoryLogitem__keyValueTable__addedThing">%2$s</ins>
377
+ <del class="SimpleHistoryLogitem__keyValueTable__removedThing">%3$s</del>
378
+ </td>
379
+ </tr>',
380
+ esc_html_x( 'Target URL', 'Logger: Redirection', 'simple-history' ), // 1
381
+ esc_html( $context['new_target_url'] ), // 2
382
+ esc_html( $context['prev_target_url'] ) // 3
383
+ );
384
+
385
+ $out .= '<table class="SimpleHistoryLogitem__keyValueTable">' . $diff_table_output . '</table>';
386
+ }
387
+ }
388
 
389
+ return $out;
390
  }
391
 
392
  } // class
loggers/SimpleLogger.php CHANGED
@@ -1208,7 +1208,23 @@ class SimpleLogger {
1208
  // Add remote addr to context.
1209
  if ( ! isset( $context['_server_remote_addr'] ) ) {
1210
 
1211
- $context['_server_remote_addr'] = empty( $_SERVER['REMOTE_ADDR'] ) ? '' : $_SERVER['REMOTE_ADDR'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1212
 
1213
  // If web server is behind a load balancer then the ip address will always be the same
1214
  // See bug report: https://wordpress.org/support/topic/use-x-forwarded-for-http-header-when-logging-remote_addr?replies=1#post-6422981
@@ -1225,18 +1241,23 @@ class SimpleLogger {
1225
 
1226
  if ( array_key_exists( $key, $_SERVER ) === true ) {
1227
 
1228
- // Loop through all IPs
1229
  $ip_loop_num = 0;
1230
  foreach ( explode( ',', $_SERVER[ $key ] ) as $ip ) {
1231
 
1232
- // trim for safety measures
1233
  $ip = trim( $ip );
1234
 
1235
- // attempt to validate IP
1236
  if ( $this->validate_ip( $ip ) ) {
1237
 
1238
- // valid, add to context, with loop index appended so we can store many IPs
1239
  $key_lower = strtolower( $key );
 
 
 
 
 
1240
  $context[ "_server_{$key_lower}_{$ip_loop_num}" ] = $ip;
1241
 
1242
  }
1208
  // Add remote addr to context.
1209
  if ( ! isset( $context['_server_remote_addr'] ) ) {
1210
 
1211
+ $remote_addr = empty( $_SERVER['REMOTE_ADDR'] ) ? '' : wp_unslash( $_SERVER['REMOTE_ADDR'] );
1212
+
1213
+ /**
1214
+ * Filter to control if ip addresses should be anonymized or not.
1215
+ *
1216
+ * @since 2.x
1217
+ *
1218
+ * @param bool true to anonymize ip address, false to keep original ip address.
1219
+ * @return bool
1220
+ */
1221
+ $anonymize_ip_address = apply_filters( 'simple_history/privacy/anonymize_ip_address', true );
1222
+
1223
+ if ( $anonymize_ip_address ) {
1224
+ $remote_addr = SimpleHistoryIpAnonymizer::anonymizeIp( $remote_addr );
1225
+ }
1226
+
1227
+ $context['_server_remote_addr'] = $remote_addr;
1228
 
1229
  // If web server is behind a load balancer then the ip address will always be the same
1230
  // See bug report: https://wordpress.org/support/topic/use-x-forwarded-for-http-header-when-logging-remote_addr?replies=1#post-6422981
1241
 
1242
  if ( array_key_exists( $key, $_SERVER ) === true ) {
1243
 
1244
+ // Loop through all IPs.
1245
  $ip_loop_num = 0;
1246
  foreach ( explode( ',', $_SERVER[ $key ] ) as $ip ) {
1247
 
1248
+ // trim for safety measures.
1249
  $ip = trim( $ip );
1250
 
1251
+ // attempt to validate IP.
1252
  if ( $this->validate_ip( $ip ) ) {
1253
 
1254
+ // valid, add to context, with loop index appended so we can store many IPs.
1255
  $key_lower = strtolower( $key );
1256
+
1257
+ if ( $anonymize_ip_address ) {
1258
+ $ip = SimpleHistoryIpAnonymizer::anonymizeIp( $ip );
1259
+ }
1260
+
1261
  $context[ "_server_{$key_lower}_{$ip_loop_num}" ] = $ip;
1262
 
1263
  }
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: history, log, changes, changelog, audit, trail, pages, attachments, users,
5
  Requires at least: 4.5.1
6
  Tested up to: 4.9
7
  Requires PHP: 5.3
8
- Stable tag: 2.21.1
9
 
10
  View changes made by users within WordPress. See who created a page, uploaded an attachment or approved an comment, and more.
11
 
@@ -163,10 +163,25 @@ A simple way to see any uncommon activity, for example an increased number of lo
163
 
164
  ## Changelog
165
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  = 2.21.1 (May 2018) =
167
 
168
  - Make sure support for Advanced Custom Fields is activated for all users – and not only for the developer of the plugin ;)
169
 
 
170
  = 2.21 (May 2018) =
171
 
172
  - 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.
5
  Requires at least: 4.5.1
6
  Tested up to: 4.9
7
  Requires PHP: 5.3
8
+ Stable tag: 2.22
9
 
10
  View changes made by users within WordPress. See who created a page, uploaded an attachment or approved an comment, and more.
11
 
163
 
164
  ## Changelog
165
 
166
+ = 2.22 (May 2018) =
167
+
168
+ - 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)
169
+ Both IPv4 and IPv6 addresses will be anonymized and the IP addresses are anonymized to their network ID.
170
+ So for example the IPv4 address `192.168.123.124` is anonymized to `192.168.123.0` and
171
+ the IPv6 address `2a03:2880:2110:df07:face:b00c::1` is anonymized by default to `2610:28:3090:3001::`.
172
+
173
+ - Added filter `simple_history/privacy/anonymize_ip_address` than can be used to disable ip address anonymization.
174
+
175
+ - Added function `sh_error_log()` to easily log variables to the error log. Probably only of interest to developers.
176
+
177
+ - 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!
178
+
179
+
180
  = 2.21.1 (May 2018) =
181
 
182
  - Make sure support for Advanced Custom Fields is activated for all users – and not only for the developer of the plugin ;)
183
 
184
+
185
  = 2.21 (May 2018) =
186
 
187
  - 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.