Advanced Access Manager - Version 6.0.1

Version Description

  • Fixed Bug: Numerous bugs fixed in the migration script. New script prepared to do additional clean-up and fix corrupted data
  • Fixed Bug: https://forum.aamplugin.com/d/369-notice-undefined-offset-1-service-content-php-on-line-509
  • Fixed Bug: https://wordpress.org/support/topic/6-0-issues/
  • Fixed Bug: https://forum.aamplugin.com/d/353-comment-system-activated
  • Fixed Bug: Migration script was skipping access settings conversion for roles that have white space in slug
  • Added New: Additional migration script for clean-up and fixing corrupted data
Download this release

Release Info

Developer vasyltech
Plugin Icon 128x128 Advanced Access Manager
Version 6.0.1
Comparing to
See all releases

Code changes from version 6.0.0 to 6.0.1

aam.php CHANGED
@@ -3,7 +3,7 @@
3
  /**
4
  * Plugin Name: Advanced Access Manager
5
  * Description: Collection of features to manage your WordPress website authentication, authorization and monitoring
6
- * Version: 6.0.0
7
  * Author: Vasyl Martyniuk <vasyl@vasyltech.com>
8
  * Author URI: https://vasyltech.com
9
  * Text Domain: advanced-access-manager
@@ -264,7 +264,7 @@ if (defined('ABSPATH')) {
264
  //define few common constants
265
  define('AAM_MEDIA', plugins_url('/media', __FILE__));
266
  define('AAM_KEY', 'advanced-access-manager');
267
- define('AAM_VERSION', '6.0.0');
268
  define('AAM_BASEDIR', __DIR__);
269
 
270
  //load vendor
3
  /**
4
  * Plugin Name: Advanced Access Manager
5
  * Description: Collection of features to manage your WordPress website authentication, authorization and monitoring
6
+ * Version: 6.0.1
7
  * Author: Vasyl Martyniuk <vasyl@vasyltech.com>
8
  * Author URI: https://vasyltech.com
9
  * Text Domain: advanced-access-manager
264
  //define few common constants
265
  define('AAM_MEDIA', plugins_url('/media', __FILE__));
266
  define('AAM_KEY', 'advanced-access-manager');
267
+ define('AAM_VERSION', '6.0.1');
268
  define('AAM_BASEDIR', __DIR__);
269
 
270
  //load vendor
application/Core/Migration.php CHANGED
@@ -82,6 +82,19 @@ final class AAM_Core_Migration
82
  return AAM_Core_API::getOption(self::DB_FAILURE_OPTION, array());
83
  }
84
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  /**
86
  * Store completed script
87
  *
82
  return AAM_Core_API::getOption(self::DB_FAILURE_OPTION, array());
83
  }
84
 
85
+ /**
86
+ * Clear failure log from the database
87
+ *
88
+ * @return boolean
89
+ *
90
+ * @access public
91
+ * @version 6.0.1
92
+ */
93
+ public static function resetFailureLog()
94
+ {
95
+ return AAM_Core_API::deleteOption(self::DB_FAILURE_OPTION);
96
+ }
97
+
98
  /**
99
  * Store completed script
100
  *
application/Core/Object/Post.php CHANGED
@@ -156,6 +156,25 @@ class AAM_Core_Object_Post extends AAM_Core_Object
156
  return $result;
157
  }
158
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  /**
160
  * Check if particular action is allowed
161
  *
156
  return $result;
157
  }
158
 
159
+ /**
160
+ * Determine if property is defined
161
+ *
162
+ * This is useful for managing access to commenting system
163
+ *
164
+ * @param string $property
165
+ *
166
+ * @return boolean
167
+ *
168
+ * @access public
169
+ * @link https://forum.aamplugin.com/d/353-comment-system-activated
170
+ * @see AAM_Service_Content::initializeHooks
171
+ * @version 6.0.1
172
+ */
173
+ public function isDefined($property)
174
+ {
175
+ return array_key_exists($property, $this->getOption());
176
+ }
177
+
178
  /**
179
  * Check if particular action is allowed
180
  *
application/Migration/2019_06_30-base.php CHANGED
@@ -28,27 +28,35 @@ use WP_Error,
28
  *
29
  * The main purpose for this class is to eliminate AAM_Core_Compatibility
30
  *
 
 
 
 
 
31
  * @package AAM
32
- * @version 6.0.0
33
  */
34
  class Migration600 implements AAM_Core_Contract_MigrationInterface
35
  {
36
  /**
37
- * Migration script version
38
  *
 
 
 
39
  * @version 6.0.0
40
  */
41
- const VERSION = '6.0.0';
42
 
43
  /**
44
- * Migration callbacks
45
  *
46
  * @var array
47
  *
48
  * @access protected
49
- * @version 6.0.0
50
  */
51
- protected $migrationCallbacks = array();
52
 
53
  /**
54
  * Constructor
@@ -82,34 +90,31 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
82
  /**
83
  * @inheritdoc
84
  *
85
- * @version 6.0.0
 
 
 
 
 
 
86
  */
87
  public function run()
88
  {
 
 
 
89
  // Fetch the list of all the access settings that are going to be converted
90
  // Prior to AAM v6, access settings were distributed between following db
91
  // tables: wp_options, wp_usermeta, wp_postmeta
92
  $settings = $this->fetchAccessSettings();
93
 
94
- // Iterate over each group of settings and convert them to AAM v6 format
95
- $results = array(
96
- 'errors' => array(),
97
- 'dump' => $settings
98
- );
99
-
100
  foreach($settings as $group => $collection) {
101
  if ($group === 'options') {
102
- $results['errors'] = array_merge(
103
- $results['errors'], $this->processOptions($collection)
104
- );
105
  } elseif ($group === 'usermeta') {
106
- $results['errors'] = array_merge(
107
- $results['errors'], $this->processUsermeta($collection)
108
- );
109
  } elseif ($group === 'postmeta') {
110
- $results['errors'] = array_merge(
111
- $results['errors'], $this->processPostmeta($collection)
112
- );
113
  }
114
  }
115
 
@@ -125,7 +130,35 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
125
  // Finally store this script as completed
126
  AAM_Core_Migration::storeCompletedScript(basename(__FILE__));
127
 
128
- return $results;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
129
  }
130
 
131
  /**
@@ -170,50 +203,59 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
170
  *
171
  * @param array $options
172
  *
173
- * @return array
 
 
 
 
174
  *
175
  * @access protected
176
- * @version 6.0.0
177
  */
178
  protected function processOptions($options)
179
  {
180
- $results = array();
181
-
182
  foreach($options as $option) {
183
  switch($option->option_name) {
184
  case 'aam-configpress':
185
- $result = $this->_convertConfigPress($option);
186
  break;
187
 
188
  case 'aam-extensions':
189
- $result = $this->_convertExtensionRegistry($option);
190
  break;
191
 
192
  case 'aam-utilities':
193
- $result = $this->_convertSettings($option);
194
  break;
195
 
196
- case 'aam_metabox_cache':
197
- case 'aam_menu_cache':
198
- case 'aam_toolbar_cache':
199
  case 'aam-check':
200
  case 'aam-uid':
 
 
 
201
  // Skip this one and just delete
202
- $result = true;
203
- //$result = AAM_Core_API::deleteOption($option->option_name);
204
  break;
205
 
206
- default:
207
- $result = $this->_parseObjectOption($option);
 
 
 
 
 
208
  break;
209
- }
210
 
211
- if ($result !== true) {
212
- $results[] = $result;
 
 
 
 
 
 
213
  }
214
  }
215
-
216
- return $results;
217
  }
218
 
219
  /**
@@ -221,25 +263,31 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
221
  *
222
  * @param object $options
223
  *
224
- * @return array
 
 
 
 
 
225
  *
226
  * @access protected
227
- * @version 6.0.0
228
  */
229
  protected function processPostmeta($options)
230
  {
231
- $results = array();
232
-
233
  foreach($options as $option) {
234
  $name = str_replace('aam-post-access-', '', $option->meta_key);
235
  $value = $this->_convertPostObject(maybe_unserialize($option->meta_value));
236
 
 
 
 
237
  if (strpos($name, 'user') === 0) {
238
- $xpath = 'user.' . substr($name, 4) . '.post.' . $option->post_id;
239
  } elseif (strpos($name, 'role') === 0) {
240
- $xpath = 'role.' . substr($name, 4) . '.post.' . $option->post_id;
241
  } elseif (in_array($name, array('visitor', 'default'), true)) {
242
- $xpath = $name . '.post.' . $option->post_id;
243
  } else {
244
  $xpath = null;
245
  }
@@ -248,17 +296,16 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
248
  AAM_Core_AccessSettings::getInstance()->set($xpath, $value);
249
 
250
  // Delete legacy option
251
- delete_post_meta($option->post_id, $option->meta_key);
 
252
  } else {
253
- $results[] = new WP_Error(
254
  'migration_error',
255
  sprintf('Failed to convert post "%d" options', $option->post_id),
256
  $option
257
  );
258
  }
259
  }
260
-
261
- return $results;
262
  }
263
 
264
  /**
@@ -266,17 +313,19 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
266
  *
267
  * @param object $options
268
  *
269
- * @return array
 
 
 
 
270
  *
271
  * @access protected
272
- * @version 6.0.0
273
  */
274
  protected function processUsermeta($options)
275
  {
276
  global $wpdb;
277
 
278
- $results = array();
279
-
280
  foreach($options as $option) {
281
  // e.g. "wp_aam_type_post", "wp_aam_term_1|category"
282
  $regex = '/^' . $wpdb->prefix . 'aam_([a-z]+)_?([a-z0-9_\-\|]*)$/i';
@@ -309,9 +358,10 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
309
  AAM_Core_AccessSettings::getInstance()->set($xpath, $options);
310
 
311
  // Delete legacy meta
312
- delete_user_meta($option->user_id, $option->meta_key);
313
- } else {
314
- $results[] = new WP_Error(
 
315
  'migration_error',
316
  sprintf('Unrecognized object type "%s"', $match[1]),
317
  $option
@@ -320,17 +370,16 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
320
  }elseif ($option->meta_key === 'aam-jwt') {
321
  // Just delete it. AAM v5 JWT tokens are no longer valid due to the
322
  // new way to calculate exp property
323
- delete_user_meta($option->user_id, $option->meta_key);
 
324
  } else {
325
- $results[] = new WP_Error(
326
  'migration_error',
327
  sprintf('Failed to parse access option %s', $option->meta_key),
328
  $option
329
  );
330
  }
331
  }
332
-
333
- return $results;
334
  }
335
 
336
  /**
@@ -338,6 +387,11 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
338
  *
339
  * @return void
340
  *
 
 
 
 
 
341
  * @access protected
342
  * @version 6.0.0
343
  */
@@ -349,6 +403,11 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
349
  'change_own_password', 'change_passwords', 'access_dashboard'
350
  );
351
 
 
 
 
 
 
352
  $roles = AAM_Core_API::getRoles();
353
  $option = AAM_Core_API::getOption($roles->role_key);
354
 
@@ -357,6 +416,9 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
357
  if (in_array($cap, $legacy_caps, true)) {
358
  unset($option[$id]['capabilities'][$cap]);
359
  $option[$id]['capabilities']['aam_' . $cap] = $effect;
 
 
 
360
  }
361
  }
362
  }
@@ -369,10 +431,14 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
369
  *
370
  * @param object $option
371
  *
372
- * @return array|WP_Error
 
 
 
 
373
  *
374
  * @access private
375
- * @version 6.0.0
376
  */
377
  private function _convertConfigPress($option)
378
  {
@@ -380,14 +446,13 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
380
 
381
  if ($result === true) {
382
  // Delete legacy option
 
383
  // AAM_Core_API::deleteOption($option->option_name);
384
  } else {
385
- $response = new WP_Error(
386
  'migration_error', 'Failed to convert ConfigPress settings', $option
387
  );
388
  }
389
-
390
- return (!empty($response) ? $response : true);
391
  }
392
 
393
  /**
@@ -395,10 +460,14 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
395
  *
396
  * @param object $option
397
  *
398
- * @return array|WP_Error
 
 
 
 
399
  *
400
  * @access private
401
- * @version 6.0.0
402
  */
403
  private function _convertExtensionRegistry($option)
404
  {
@@ -408,14 +477,13 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
408
 
409
  if ($result === true) {
410
  // Delete legacy option
 
411
  // AAM_Core_API::deleteOption($option->option_name);
412
  } else {
413
- $response = new WP_Error(
414
  'migration_error', 'Failed to convert Addon settings', $option
415
  );
416
  }
417
-
418
- return (!empty($response) ? $response : true);
419
  }
420
 
421
  /**
@@ -423,10 +491,14 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
423
  *
424
  * @param object $option
425
  *
426
- * @return array|WP_Error
 
 
 
 
427
  *
428
  * @access private
429
- * @version 6.0.0
430
  */
431
  private function _convertSettings($option)
432
  {
@@ -476,14 +548,13 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
476
 
477
  if ($result === true) {
478
  // Delete legacy option
 
479
  // AAM_Core_API::deleteOption($option->option_name);
480
  } else {
481
- $response = new WP_Error(
482
  'migration_error', 'Failed to convert core settings', $option
483
  );
484
  }
485
-
486
- return (!empty($response) ? $response : true);
487
  }
488
 
489
  /**
@@ -513,10 +584,14 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
513
  *
514
  * @param object $option
515
  *
516
- * @return array
 
 
 
 
517
  *
518
  * @access private
519
- * @version 6.0.0
520
  */
521
  private function _parseObjectOption($option)
522
  {
@@ -525,7 +600,7 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
525
  $regex = '/^aam_visitor_([a-z]+)_?([a-z0-9_\-\|]*)$/i';
526
  } else {
527
  // e.g. "aam_route_role_administrator", "aam_type_post_role_editor"
528
- $regex = '/^aam_([a-z]+)_([a-z0-9_\-\|]+)?_?(role|default)_?([a-z0-9_\-]*)$/i';
529
  }
530
 
531
  // Let's parse the option name and determine object & subject
@@ -573,25 +648,12 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
573
  }
574
 
575
  AAM_Core_AccessSettings::getInstance()->set($xpath, $options);
576
-
577
- // Delete legacy option
578
- // AAM_Core_API::deleteOption($option->option_name);
579
- } else {
580
- $error = new WP_Error(
581
- 'migration_error',
582
- sprintf('Skipped unrecognized object type "%s"', $match[1]),
583
- $option
584
- );
585
  }
586
- } else {
587
- $error = new WP_Error(
588
- 'migration_error',
589
- sprintf('Skipped unrecognized option "%s"', $option->option_name),
590
- $option
591
- );
592
  }
593
 
594
- return (!empty($error) ? $error : true);
 
 
595
  }
596
 
597
  /**
@@ -773,34 +835,47 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
773
  *
774
  * @return array
775
  *
 
 
 
 
 
776
  * @access private
777
- * @version 6.0.0
778
  */
779
  private function _convertPostObject($options, $ns = '')
780
  {
781
  $converted = array();
782
- $normalized = $this->_normalizeContentOptions($options);
783
 
784
- foreach($normalized as $key => $val) {
785
  switch($key) {
786
  case 'list':
787
- $converted[$ns . 'hidden'] = filter_var($val, FILTER_VALIDATE_BOOLEAN);
 
 
788
  break;
789
 
790
  case 'list_others':
791
- $converted[$ns . 'hidden_others'] = filter_var($val, FILTER_VALIDATE_BOOLEAN);
 
 
792
  break;
793
 
794
  case 'read':
795
- $converted[$ns . 'restricted'] = filter_var($val, FILTER_VALIDATE_BOOLEAN);
 
 
796
  break;
797
 
798
  case 'read_others':
799
- $converted[$ns . 'restricted_others'] = filter_var($val, FILTER_VALIDATE_BOOLEAN);
 
 
800
  break;
801
 
802
  case 'limit':
803
- $msg = (!empty($normalized['teaser']) ? $normalized['teaser'] : '');
804
  $converted[$ns . 'teaser'] = array(
805
  'enabled' => filter_var($val, FILTER_VALIDATE_BOOLEAN),
806
  'message' => $msg
@@ -808,10 +883,15 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
808
  break;
809
 
810
  case 'access_counter':
811
- $l = (!empty($normalized['access_counter_limit']) ? $normalized['access_counter_limit'] : 0);
 
 
 
 
 
812
  $converted[$ns . 'limited'] = array(
813
  'enabled' => filter_var($val, FILTER_VALIDATE_BOOLEAN),
814
- 'threshold' => $l
815
  );
816
  break;
817
 
@@ -822,41 +902,57 @@ class Migration600 implements AAM_Core_Contract_MigrationInterface
822
  case 'edit_others':
823
  case 'delete_others':
824
  case 'publish_others':
825
- $converted[$ns . $key] = filter_var($val, FILTER_VALIDATE_BOOLEAN);
 
 
826
  break;
827
 
828
  case 'add':
829
- $converted[$ns . 'create'] = filter_var($val, FILTER_VALIDATE_BOOLEAN);
 
 
830
  break;
831
 
832
  case 'redirect':
833
- $chunks = explode('|', $normalized['location']);
834
 
835
  $converted[$ns . 'redirected'] = array(
836
  'enabled' => filter_var($val, FILTER_VALIDATE_BOOLEAN),
837
- 'type' => $chunks[0],
838
- 'destination' => $chunks[1],
839
- 'httpCode' => (isset($chunks[2]) ? intval($chunks[2]) : 307)
840
  );
841
  break;
842
 
843
  case 'protected':
844
  $converted[$ns . 'protected'] = array(
845
  'enabled' => filter_var($val, FILTER_VALIDATE_BOOLEAN),
846
- 'password' => $normalized['password']
847
  );
848
  break;
849
 
850
  case 'expire':
851
- $datetime = \DateTime::createFromFormat(
852
- 'm/d/Y, H:i O', $normalized['expire_datetime']
853
  );
854
- $datetime->setTimezone(new \DateTimeZone('UTC'));
855
 
856
- $converted[$ns . 'ceased'] = array(
857
- 'enabled' => filter_var($val, FILTER_VALIDATE_BOOLEAN),
858
- 'after' => $datetime->getTimestamp()
859
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
860
  break;
861
 
862
  case 'access_counter_limit':
28
  *
29
  * The main purpose for this class is to eliminate AAM_Core_Compatibility
30
  *
31
+ * @since 6.0.1 Slightly refactored the way errors are collected during the migration
32
+ * execution. Fixed fatal error when incorrectly defined "Expire" post
33
+ * option
34
+ * @since 6.0.0 Initial implementation of the class
35
+ *
36
  * @package AAM
37
+ * @version 6.0.1
38
  */
39
  class Migration600 implements AAM_Core_Contract_MigrationInterface
40
  {
41
  /**
42
+ * Migration callbacks
43
  *
44
+ * @var array
45
+ *
46
+ * @access protected
47
  * @version 6.0.0
48
  */
49
+ protected $migrationCallbacks = array();
50
 
51
  /**
52
+ * Collection of errors during the migration
53
  *
54
  * @var array
55
  *
56
  * @access protected
57
+ * @version 6.0.1
58
  */
59
+ protected $errors = array();
60
 
61
  /**
62
  * Constructor
90
  /**
91
  * @inheritdoc
92
  *
93
+ * @since 6.0.1 Changed the way `errors` are collected. Now any method pushes
94
+ * directly to the $this->errors array to avoid passing $errors
95
+ * array to multiple methods. Also, invoking cache clearing prior to
96
+ * fetching settings
97
+ * @since 6.0.0 Initial implementation of the method
98
+ *
99
+ * @version 6.0.1
100
  */
101
  public function run()
102
  {
103
+ // Clear any cache that AAM set in the past
104
+ $this->clearInternalCache();
105
+
106
  // Fetch the list of all the access settings that are going to be converted
107
  // Prior to AAM v6, access settings were distributed between following db
108
  // tables: wp_options, wp_usermeta, wp_postmeta
109
  $settings = $this->fetchAccessSettings();
110
 
 
 
 
 
 
 
111
  foreach($settings as $group => $collection) {
112
  if ($group === 'options') {
113
+ $this->processOptions($collection);
 
 
114
  } elseif ($group === 'usermeta') {
115
+ $this->processUsermeta($collection);
 
 
116
  } elseif ($group === 'postmeta') {
117
+ $this->processPostmeta($collection);
 
 
118
  }
119
  }
120
 
130
  // Finally store this script as completed
131
  AAM_Core_Migration::storeCompletedScript(basename(__FILE__));
132
 
133
+ return array(
134
+ 'errors' => $this->errors,
135
+ 'dump' => $settings
136
+ );
137
+ }
138
+
139
+ /**
140
+ * Clear internal AAM cache
141
+ *
142
+ * @return void
143
+ *
144
+ * @access protected
145
+ * @version 6.0.1
146
+ */
147
+ protected function clearInternalCache()
148
+ {
149
+ global $wpdb;
150
+
151
+ // Delete AAM internal cache from the _options table
152
+ $opt_query = "DELETE FROM {$wpdb->options} WHERE (`option_name` LIKE %s) ";
153
+ $opt_query .= "OR (`option_name` LIKE %s)";
154
+ $wpdb->query($wpdb->prepare($opt_query, array('aam_cache_%', 'aam_%_cache')));
155
+
156
+ // Fetch access settings from the wp_usermeta table
157
+ $query = "DELETE FROM {$wpdb->usermeta} WHERE (`meta_key` = %s) OR ";
158
+ $query .= '(`meta_key` = %s)';
159
+ $wpdb->query(
160
+ $wpdb->prepare($query, array("{$wpdb->prefix}aam_cache", 'aam-cache'))
161
+ );
162
  }
163
 
164
  /**
203
  *
204
  * @param array $options
205
  *
206
+ * @return void
207
+ *
208
+ * @since 6.0.1 Any errors are pushed directly to the $this->errors array instead
209
+ * of returning them. Skipping user switch flags
210
+ * @since 6.0.0 Initialize implementation of the method
211
  *
212
  * @access protected
213
+ * @version 6.0.1
214
  */
215
  protected function processOptions($options)
216
  {
 
 
217
  foreach($options as $option) {
218
  switch($option->option_name) {
219
  case 'aam-configpress':
220
+ $this->_convertConfigPress($option);
221
  break;
222
 
223
  case 'aam-extensions':
224
+ $this->_convertExtensionRegistry($option);
225
  break;
226
 
227
  case 'aam-utilities':
228
+ $this->_convertSettings($option);
229
  break;
230
 
 
 
 
231
  case 'aam-check':
232
  case 'aam-uid':
233
+ case 'aam-extension-list':
234
+ case 'aam-extension-repository':
235
+ case 'aam-welcome':
236
  // Skip this one and just delete
237
+ AAM_Core_API::deleteOption($option->option_name);
 
238
  break;
239
 
240
+ case AAM_Core_AccessSettings::DB_OPTION:
241
+ case AAM_Core_Config::DB_OPTION:
242
+ case AAM_Core_ConfigPress::DB_OPTION:
243
+ case AAM_Core_Migration::DB_OPTION:
244
+ case AAM_Core_Migration::DB_FAILURE_OPTION:
245
+ // Silently skip in case somebody forces to rerun the entire
246
+ // migration process
247
  break;
 
248
 
249
+ default:
250
+ // aam-user-switch-36
251
+ if (strpos($option->option_name, 'aam-user-switch') !== false) {
252
+ AAM_Core_API::deleteOption($option->option_name);
253
+ } else {
254
+ $this->_parseObjectOption($option);
255
+ }
256
+ break;
257
  }
258
  }
 
 
259
  }
260
 
261
  /**
263
  *
264
  * @param object $options
265
  *
266
+ * @return void
267
+ *
268
+ * @link https://forum.aamplugin.com/d/369-notice-undefined-offset-1-service-content-php-on-line-509
269
+ * @since 6.0.1 Any errors are pushed directly to the $this->errors array instead
270
+ * of returning them. Fixed bug with incorrectly set post ID.
271
+ * @since 6.0.0 Initialize implementation of the method
272
  *
273
  * @access protected
274
+ * @version 6.0.1
275
  */
276
  protected function processPostmeta($options)
277
  {
 
 
278
  foreach($options as $option) {
279
  $name = str_replace('aam-post-access-', '', $option->meta_key);
280
  $value = $this->_convertPostObject(maybe_unserialize($option->meta_value));
281
 
282
+ $post = get_post($option->post_id);
283
+ $id = (is_a($post, 'WP_Post') ? "{$post->ID}|{$post->post_type}" : '');
284
+
285
  if (strpos($name, 'user') === 0) {
286
+ $xpath = 'user.' . substr($name, 4) . '.post.' . $id;
287
  } elseif (strpos($name, 'role') === 0) {
288
+ $xpath = 'role.' . substr($name, 4) . '.post.' . $id;
289
  } elseif (in_array($name, array('visitor', 'default'), true)) {
290
+ $xpath = $name . '.post.' . $id;
291
  } else {
292
  $xpath = null;
293
  }
296
  AAM_Core_AccessSettings::getInstance()->set($xpath, $value);
297
 
298
  // Delete legacy option
299
+ // TODO: Enable in the 6.0.2 release
300
+ // delete_post_meta($option->post_id, $option->meta_key);
301
  } else {
302
+ $this->errors[] = new WP_Error(
303
  'migration_error',
304
  sprintf('Failed to convert post "%d" options', $option->post_id),
305
  $option
306
  );
307
  }
308
  }
 
 
309
  }
310
 
311
  /**
313
  *
314
  * @param object $options
315
  *
316
+ * @return void
317
+ *
318
+ * @since 6.0.1 Any errors are pushed directly to the $this->errors array instead
319
+ * of returning them. Skipping wp_aam_capability option
320
+ * @since 6.0.0 Initialize implementation of the method
321
  *
322
  * @access protected
323
+ * @version 6.0.1
324
  */
325
  protected function processUsermeta($options)
326
  {
327
  global $wpdb;
328
 
 
 
329
  foreach($options as $option) {
330
  // e.g. "wp_aam_type_post", "wp_aam_term_1|category"
331
  $regex = '/^' . $wpdb->prefix . 'aam_([a-z]+)_?([a-z0-9_\-\|]*)$/i';
358
  AAM_Core_AccessSettings::getInstance()->set($xpath, $options);
359
 
360
  // Delete legacy meta
361
+ // TODO: Enable in the 6.0.2 release
362
+ // delete_user_meta($option->user_id, $option->meta_key);
363
+ } elseif (!in_array($match[1], array('capability'), true)) {
364
+ $this->errors[] = new WP_Error(
365
  'migration_error',
366
  sprintf('Unrecognized object type "%s"', $match[1]),
367
  $option
370
  }elseif ($option->meta_key === 'aam-jwt') {
371
  // Just delete it. AAM v5 JWT tokens are no longer valid due to the
372
  // new way to calculate exp property
373
+ // TODO: Enable in the 6.0.2 release
374
+ // delete_user_meta($option->user_id, $option->meta_key);
375
  } else {
376
+ $this->errors[] = new WP_Error(
377
  'migration_error',
378
  sprintf('Failed to parse access option %s', $option->meta_key),
379
  $option
380
  );
381
  }
382
  }
 
 
383
  }
384
 
385
  /**
387
  *
388
  * @return void
389
  *
390
+ * @link https://wordpress.org/support/topic/6-0-issues/
391
+ * @since 6.0.1 Fixed the bug with `show_admin_bar` not converted to
392
+ * `aam_show_toolbar`
393
+ * @since 6.0.0 Initialize implementation of the method
394
+ *
395
  * @access protected
396
  * @version 6.0.0
397
  */
403
  'change_own_password', 'change_passwords', 'access_dashboard'
404
  );
405
 
406
+ // Totally replaced caps
407
+ $replaced_caps = array(
408
+ 'show_admin_bar' => 'aam_show_toolbar'
409
+ );
410
+
411
  $roles = AAM_Core_API::getRoles();
412
  $option = AAM_Core_API::getOption($roles->role_key);
413
 
416
  if (in_array($cap, $legacy_caps, true)) {
417
  unset($option[$id]['capabilities'][$cap]);
418
  $option[$id]['capabilities']['aam_' . $cap] = $effect;
419
+ } elseif (array_key_exists($cap, $replaced_caps)) {
420
+ unset($option[$id]['capabilities'][$cap]);
421
+ $option[$id]['capabilities'][$replaced_caps[$cap]] = $effect;
422
  }
423
  }
424
  }
431
  *
432
  * @param object $option
433
  *
434
+ * @return void
435
+ *
436
+ * @since 6.0.1 Any errors are pushed directly to the $this->errors array instead
437
+ * of returning them
438
+ * @since 6.0.0 Initialize implementation of the method
439
  *
440
  * @access private
441
+ * @version 6.0.1
442
  */
443
  private function _convertConfigPress($option)
444
  {
446
 
447
  if ($result === true) {
448
  // Delete legacy option
449
+ // TODO: Enable in the 6.0.2 release
450
  // AAM_Core_API::deleteOption($option->option_name);
451
  } else {
452
+ $this->errors[] = new WP_Error(
453
  'migration_error', 'Failed to convert ConfigPress settings', $option
454
  );
455
  }
 
 
456
  }
457
 
458
  /**
460
  *
461
  * @param object $option
462
  *
463
+ * @return void
464
+ *
465
+ * @since 6.0.1 Any errors are pushed directly to the $this->errors array instead
466
+ * of returning them
467
+ * @since 6.0.0 Initialize implementation of the method
468
  *
469
  * @access private
470
+ * @version 6.0.1
471
  */
472
  private function _convertExtensionRegistry($option)
473
  {
477
 
478
  if ($result === true) {
479
  // Delete legacy option
480
+ // TODO: Enable in the 6.0.2 release
481
  // AAM_Core_API::deleteOption($option->option_name);
482
  } else {
483
+ $this->errors[] = new WP_Error(
484
  'migration_error', 'Failed to convert Addon settings', $option
485
  );
486
  }
 
 
487
  }
488
 
489
  /**
491
  *
492
  * @param object $option
493
  *
494
+ * @return void
495
+ *
496
+ * @since 6.0.1 Any errors are pushed directly to the $this->errors array instead
497
+ * of returning them
498
+ * @since 6.0.0 Initialize implementation of the method
499
  *
500
  * @access private
501
+ * @version 6.0.1
502
  */
503
  private function _convertSettings($option)
504
  {
548
 
549
  if ($result === true) {
550
  // Delete legacy option
551
+ // TODO: Enable in the 6.0.2 release
552
  // AAM_Core_API::deleteOption($option->option_name);
553
  } else {
554
+ $this->errors[] = new WP_Error(
555
  'migration_error', 'Failed to convert core settings', $option
556
  );
557
  }
 
 
558
  }
559
 
560
  /**
584
  *
585
  * @param object $option
586
  *
587
+ * @return void
588
+ *
589
+ * @since 6.0.1 Removed unrecognized option errors. Fixed bug that skips access
590
+ * settings conversion for roles that have white space in slug
591
+ * @since 6.0.0 Initialize implementation of the method
592
  *
593
  * @access private
594
+ * @version 6.0.1
595
  */
596
  private function _parseObjectOption($option)
597
  {
600
  $regex = '/^aam_visitor_([a-z]+)_?([a-z0-9_\-\|]*)$/i';
601
  } else {
602
  // e.g. "aam_route_role_administrator", "aam_type_post_role_editor"
603
+ $regex = '/^aam_([a-z]+)_([a-z0-9_\-\|]+)?_?(role|default)_?([a-z0-9_\-\s]*)$/i';
604
  }
605
 
606
  // Let's parse the option name and determine object & subject
648
  }
649
 
650
  AAM_Core_AccessSettings::getInstance()->set($xpath, $options);
 
 
 
 
 
 
 
 
 
651
  }
 
 
 
 
 
 
652
  }
653
 
654
+ // Delete legacy option
655
+ // TODO: Enable in the 6.0.2 release
656
+ // AAM_Core_API::deleteOption($option->option_name);
657
  }
658
 
659
  /**
835
  *
836
  * @return array
837
  *
838
+ * @since 6.0.1 Improved code formating. Fixed the error when unexpected datetime
839
+ * is set for "Expire" option (Uncaught Error: Call to a member
840
+ * function setTimezone() on boolean)
841
+ * @since 6.0.0 Initialize implementation of the method
842
+ *
843
  * @access private
844
+ * @version 6.0.1
845
  */
846
  private function _convertPostObject($options, $ns = '')
847
  {
848
  $converted = array();
849
+ $prepped = $this->_normalizeContentOptions($options);
850
 
851
+ foreach($prepped as $key => $val) {
852
  switch($key) {
853
  case 'list':
854
+ $converted[$ns . 'hidden'] = filter_var(
855
+ $val, FILTER_VALIDATE_BOOLEAN
856
+ );
857
  break;
858
 
859
  case 'list_others':
860
+ $converted[$ns . 'hidden_others'] = filter_var(
861
+ $val, FILTER_VALIDATE_BOOLEAN
862
+ );
863
  break;
864
 
865
  case 'read':
866
+ $converted[$ns . 'restricted'] = filter_var(
867
+ $val, FILTER_VALIDATE_BOOLEAN
868
+ );
869
  break;
870
 
871
  case 'read_others':
872
+ $converted[$ns . 'restricted_others'] = filter_var(
873
+ $val, FILTER_VALIDATE_BOOLEAN
874
+ );
875
  break;
876
 
877
  case 'limit':
878
+ $msg = (!empty($prepped['teaser']) ? $prepped['teaser'] : '');
879
  $converted[$ns . 'teaser'] = array(
880
  'enabled' => filter_var($val, FILTER_VALIDATE_BOOLEAN),
881
  'message' => $msg
883
  break;
884
 
885
  case 'access_counter':
886
+ if (!empty($prepped['access_counter_limit'])) {
887
+ $threshold = intval($prepped['access_counter_limit']);
888
+ } else {
889
+ $threshold = 0;
890
+ }
891
+
892
  $converted[$ns . 'limited'] = array(
893
  'enabled' => filter_var($val, FILTER_VALIDATE_BOOLEAN),
894
+ 'threshold' => $threshold
895
  );
896
  break;
897
 
902
  case 'edit_others':
903
  case 'delete_others':
904
  case 'publish_others':
905
+ $converted[$ns . $key] = filter_var(
906
+ $val, FILTER_VALIDATE_BOOLEAN
907
+ );
908
  break;
909
 
910
  case 'add':
911
+ $converted[$ns . 'create'] = filter_var(
912
+ $val, FILTER_VALIDATE_BOOLEAN
913
+ );
914
  break;
915
 
916
  case 'redirect':
917
+ $chks = explode('|', $prepped['location']);
918
 
919
  $converted[$ns . 'redirected'] = array(
920
  'enabled' => filter_var($val, FILTER_VALIDATE_BOOLEAN),
921
+ 'type' => $chks[0],
922
+ 'destination' => $chks[1],
923
+ 'httpCode' => (isset($chks[2]) ? intval($chks[2]) : 307)
924
  );
925
  break;
926
 
927
  case 'protected':
928
  $converted[$ns . 'protected'] = array(
929
  'enabled' => filter_var($val, FILTER_VALIDATE_BOOLEAN),
930
+ 'password' => $prepped['password']
931
  );
932
  break;
933
 
934
  case 'expire':
935
+ $datetime = new \DateTime(
936
+ '@' . strtotime($prepped['expire_datetime'])
937
  );
 
938
 
939
+ if ($datetime) { // Cover any unexpected issues with the option
940
+ $datetime->setTimezone(new \DateTimeZone('UTC'));
941
+
942
+ $converted[$ns . 'ceased'] = array(
943
+ 'enabled' => filter_var($val, FILTER_VALIDATE_BOOLEAN),
944
+ 'after' => $datetime->getTimestamp()
945
+ );
946
+ } else {
947
+ $this->errors[] = new WP_Error(
948
+ 'migration_error',
949
+ sprintf(
950
+ 'Unrecognized time format %s',
951
+ $prepped['expire_datetime']
952
+ ),
953
+ $prepped
954
+ );
955
+ }
956
  break;
957
 
958
  case 'access_counter_limit':
application/Migration/2019_11_20-base.php ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * ======================================================================
5
+ * LICENSE: This file is subject to the terms and conditions defined in *
6
+ * file 'license.txt', which is part of this source code package. *
7
+ * ======================================================================
8
+ *
9
+ * @version 6.0.1
10
+ */
11
+
12
+ namespace AAM\Migration;
13
+
14
+ use AAM_Core_Migration,
15
+ AAM_Core_AccessSettings,
16
+ AAM_Core_Contract_MigrationInterface;
17
+
18
+ /**
19
+ * This migration class clears legacy AAM cache options
20
+ *
21
+ * The Migration600 does not take in consideration legacy AAM cache options and this
22
+ * migration script clears them up as well as migration log
23
+ *
24
+ * @package AAM
25
+ * @version 6.0.1
26
+ */
27
+ class Migration601 implements AAM_Core_Contract_MigrationInterface
28
+ {
29
+
30
+ /**
31
+ * @inheritdoc
32
+ *
33
+ * @version 6.0.1
34
+ */
35
+ public function run()
36
+ {
37
+ // Reset failure log
38
+ AAM_Core_Migration::resetFailureLog();
39
+
40
+ // Clear any cache that AAM set in the past
41
+ $this->clearInternalCache();
42
+
43
+ // Clear corrupted data from the previous migration script
44
+ $this->clearCorruptedData();
45
+
46
+ // Finally store this script as completed
47
+ AAM_Core_Migration::storeCompletedScript(basename(__FILE__));
48
+
49
+ return array('errors' => array());
50
+ }
51
+
52
+ /**
53
+ * Clear internal AAM cache
54
+ *
55
+ * @return void
56
+ *
57
+ * @access protected
58
+ * @version 6.0.1
59
+ */
60
+ protected function clearInternalCache()
61
+ {
62
+ global $wpdb;
63
+
64
+ // Delete AAM internal cache from the _options table
65
+ $opt_query = "DELETE FROM {$wpdb->options} WHERE (`option_name` LIKE %s) ";
66
+ $opt_query .= "OR (`option_name` LIKE %s)";
67
+ $wpdb->query($wpdb->prepare($opt_query, array('aam_cache_%', 'aam_%_cache')));
68
+
69
+ // Fetch access settings from the wp_usermeta table
70
+ $query = "DELETE FROM {$wpdb->usermeta} WHERE (`meta_key` = %s)";
71
+ $wpdb->query($wpdb->prepare($query, array("{$wpdb->prefix}aam_cache")));
72
+ }
73
+
74
+ /**
75
+ * Clear corrupted data from the previously incorrectly executed script
76
+ *
77
+ * @link https://forum.aamplugin.com/d/369-notice-undefined-offset-1-service-content-php-on-line-509
78
+ *
79
+ * @return void
80
+ *
81
+ * @access protected
82
+ * @version 6.0.1
83
+ */
84
+ protected function clearCorruptedData()
85
+ {
86
+ $settings = AAM_Core_AccessSettings::getInstance();
87
+
88
+ // Possibly fix role settings
89
+ foreach($settings->get('role') as $role => $data) {
90
+ if (isset($data['post'])) {
91
+ $this->_fixPostSettingsCorruption("role.{$role}", $data['post']);
92
+ }
93
+ }
94
+
95
+ // Possibly fix user settings
96
+ foreach($settings->get('user') as $id => $data) {
97
+ if (isset($data['post'])) {
98
+ $this->_fixPostSettingsCorruption("user.{$id}", $data['post']);
99
+ }
100
+ }
101
+
102
+ // Possibly fix visitor settings
103
+ $visitor = $settings->get('visitor');
104
+ if (isset($visitor['post'])) {
105
+ $this->_fixPostSettingsCorruption('visitor', $visitor['post']);
106
+ }
107
+
108
+ // Possibly fix default settings
109
+ $default = $settings->get('default');
110
+ if (isset($default['post'])) {
111
+ $this->_fixPostSettingsCorruption('default', $default['post']);
112
+ }
113
+
114
+ // Save access settings
115
+ $settings->save();
116
+ }
117
+
118
+ /**
119
+ * Fix the post settings corruption
120
+ *
121
+ * @param string $prefix
122
+ * @param array $posts
123
+ *
124
+ * @return void
125
+ *
126
+ * @access private
127
+ * @version 6.0.1
128
+ */
129
+ private function _fixPostSettingsCorruption($prefix, $posts)
130
+ {
131
+ $settings = AAM_Core_AccessSettings::getInstance();
132
+
133
+ foreach( $posts as $id => $options) {
134
+ if (strpos($id, '|') === false && is_numeric($id)) {
135
+ $settings->delete("{$prefix}.post.{$id}");
136
+ $post = get_post($id);
137
+ $settings->set(
138
+ "{$prefix}.post.{$post->ID}|{$post->post_type}", $options
139
+ );
140
+ }
141
+ }
142
+ }
143
+
144
+ }
145
+
146
+ if (defined('AAM_KEY')) {
147
+ return (new Migration601())->run();
148
+ }
application/Service/Content.php CHANGED
@@ -133,8 +133,11 @@ class AAM_Service_Content
133
  *
134
  * @return void
135
  *
 
 
 
136
  * @access protected
137
- * @version 6.0.0
138
  */
139
  protected function initializeHooks()
140
  {
@@ -167,9 +170,17 @@ class AAM_Service_Content
167
  // capability and meta data
168
  add_filter('map_meta_cap', array($this, 'filterMetaMaps'), 999, 4);
169
 
170
- //get control over commenting stuff
171
  add_filter('comments_open', function($open, $id) {
172
- return AAM::getUser()->getObject('post', $id)->isAllowedTo('comment');
 
 
 
 
 
 
 
 
173
  }, 10, 2);
174
 
175
  // REST API action authorization. Triggered before call is dispatched
133
  *
134
  * @return void
135
  *
136
+ * @since 6.0.1 Fixed bug related to enabling commenting on all posts
137
+ * @since 6.0.0 Initial implementation of the method
138
+ *
139
  * @access protected
140
+ * @version 6.0.1
141
  */
142
  protected function initializeHooks()
143
  {
170
  // capability and meta data
171
  add_filter('map_meta_cap', array($this, 'filterMetaMaps'), 999, 4);
172
 
173
+ // Get control over commenting stuff
174
  add_filter('comments_open', function($open, $id) {
175
+ $object = AAM::getUser()->getObject('post', $id);
176
+
177
+ // If Leave Comments option is defined then override the default status.
178
+ // Otherwise keep it as-is
179
+ if ($object->isDefined('comment')) {
180
+ $open = $object->isAllowedTo('comment');
181
+ }
182
+
183
+ return $open;
184
  }, 10, 2);
185
 
186
  // REST API action authorization. Triggered before call is dispatched
readme.txt CHANGED
@@ -4,7 +4,7 @@ Tags: access control, membership, backend menu, user role, restricted content, s
4
  Requires at least: 4.7.0
5
  Requires PHP: 5.6.0
6
  Tested up to: 5.3
7
- Stable tag: 6.0.0
8
 
9
  All you need to manage access to WordPress websites on the frontend, backend and API levels for any role, user or visitors.
10
 
@@ -91,6 +91,14 @@ We take security and privacy very seriously, that is why there are several non-n
91
 
92
  == Changelog ==
93
 
 
 
 
 
 
 
 
 
94
  = 6.0.0 =
95
  * Complete rewrite of the entire plugin. For more information, check [this article](https://aamplugin.com/article/advanced-access-manager-next-generation)
96
 
4
  Requires at least: 4.7.0
5
  Requires PHP: 5.6.0
6
  Tested up to: 5.3
7
+ Stable tag: 6.0.1
8
 
9
  All you need to manage access to WordPress websites on the frontend, backend and API levels for any role, user or visitors.
10
 
91
 
92
  == Changelog ==
93
 
94
+ = 6.0.1 =
95
+ * Fixed Bug: Numerous bugs fixed in the migration script. New script prepared to do additional clean-up and fix corrupted data
96
+ * Fixed Bug: https://forum.aamplugin.com/d/369-notice-undefined-offset-1-service-content-php-on-line-509
97
+ * Fixed Bug: https://wordpress.org/support/topic/6-0-issues/
98
+ * Fixed Bug: https://forum.aamplugin.com/d/353-comment-system-activated
99
+ * Fixed Bug: Migration script was skipping access settings conversion for roles that have white space in slug
100
+ * Added New: Additional migration script for clean-up and fixing corrupted data
101
+
102
  = 6.0.0 =
103
  * Complete rewrite of the entire plugin. For more information, check [this article](https://aamplugin.com/article/advanced-access-manager-next-generation)
104