Advanced Access Manager - Version 6.5.3

Version Description

  • Fixed Bug: PHP Warning: Parameter must be an array or an object that implements Countable in /service/core.php https://github.com/aamplugin/advanced-access-manager/issues/126
  • Added New: Allow to target the same resource with multiple statements https://github.com/aamplugin/advanced-access-manager/issues/124
  • Added New: Enhance "In" condition for the access policies https://github.com/aamplugin/advanced-access-manager/issues/123
  • Changed: Change the access policy initialization order https://github.com/aamplugin/advanced-access-manager/issues/122
Download this release

Release Info

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

Code changes from version 6.5.2 to 6.5.3

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.5.2
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.5.2');
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.5.3
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.5.3');
268
  define('AAM_BASEDIR', __DIR__);
269
 
270
  //load vendor
application/Addon/Repository.php CHANGED
@@ -143,13 +143,13 @@ class AAM_Addon_Repository
143
  'Plus Package',
144
  'plus-package',
145
  __('Manage access to your WordPress website posts, pages, media, custom post types, categories, tags and custom taxonomies for any role, individual user, visitors or even define default access for everybody; and do this separately for frontend, backend or API levels.', AAM_KEY),
146
- '5.4.0'
147
  ),
148
  'aam-ip-check' => $this->buildAddonObject(
149
  'IP Check',
150
  'ip-check',
151
  __('Manage access to your WordPress website by users IP address or referred host and completely lock down the entire website if necessary. Define the unlimited number of whitelisted or blacklisted IPs or hosts.', AAM_KEY),
152
- '4.1.3'
153
  ),
154
  'aam-role-hierarchy' => $this->buildAddonObject(
155
  'Role Hierarchy',
@@ -171,7 +171,7 @@ class AAM_Addon_Repository
171
  'Complete Package',
172
  'complete-package',
173
  __('Get the complete list of all premium AAM addons in one package and all future premium addons will be included for now additional cost.', AAM_KEY),
174
- '5.2.5'
175
  )
176
  );
177
  }
143
  'Plus Package',
144
  'plus-package',
145
  __('Manage access to your WordPress website posts, pages, media, custom post types, categories, tags and custom taxonomies for any role, individual user, visitors or even define default access for everybody; and do this separately for frontend, backend or API levels.', AAM_KEY),
146
+ '5.4.2'
147
  ),
148
  'aam-ip-check' => $this->buildAddonObject(
149
  'IP Check',
150
  'ip-check',
151
  __('Manage access to your WordPress website by users IP address or referred host and completely lock down the entire website if necessary. Define the unlimited number of whitelisted or blacklisted IPs or hosts.', AAM_KEY),
152
+ '4.1.4'
153
  ),
154
  'aam-role-hierarchy' => $this->buildAddonObject(
155
  'Role Hierarchy',
171
  'Complete Package',
172
  'complete-package',
173
  __('Get the complete list of all premium AAM addons in one package and all future premium addons will be included for now additional cost.', AAM_KEY),
174
+ '5.2.8'
175
  )
176
  );
177
  }
application/Core/Policy/Condition.php CHANGED
@@ -10,12 +10,13 @@
10
  /**
11
  * AAM core policy condition evaluator
12
  *
 
13
  * @since 6.2.0 Added support for the (*date) type casting
14
  * @since 6.1.0 Improved type casting functionality
15
  * @since 6.0.0 Initial implementation of the class
16
  *
17
  * @package AAM
18
- * @version 6.2.0
19
  */
20
  class AAM_Core_Policy_Condition
21
  {
@@ -254,18 +255,29 @@ class AAM_Core_Policy_Condition
254
  *
255
  * @return boolean
256
  *
 
 
 
257
  * @access protected
258
- * @version 6.0.0
259
  */
260
  protected function evaluateInConditions($conditions, $args)
261
  {
262
- $result = false;
263
 
264
  foreach ($this->prepareConditions($conditions, $args) as $cnd) {
265
- $result = $result || in_array($cnd['left'], (array) $cnd['right'], true);
 
 
 
 
 
 
 
 
266
  }
267
 
268
- return $result;
269
  }
270
 
271
  /**
10
  /**
11
  * AAM core policy condition evaluator
12
  *
13
+ * @since 6.5.3 https://github.com/aamplugin/advanced-access-manager/issues/123
14
  * @since 6.2.0 Added support for the (*date) type casting
15
  * @since 6.1.0 Improved type casting functionality
16
  * @since 6.0.0 Initial implementation of the class
17
  *
18
  * @package AAM
19
+ * @version 6.5.3
20
  */
21
  class AAM_Core_Policy_Condition
22
  {
255
  *
256
  * @return boolean
257
  *
258
+ * @since 6.5.3 https://github.com/aamplugin/advanced-access-manager/issues/123
259
+ * @since 6.0.0 Initial implementation of the method
260
+ *
261
  * @access protected
262
+ * @version 6.5.3
263
  */
264
  protected function evaluateInConditions($conditions, $args)
265
  {
266
+ $res = false;
267
 
268
  foreach ($this->prepareConditions($conditions, $args) as $cnd) {
269
+ if (is_array($cnd['left'])) {
270
+ $cl = count($cnd['left']);
271
+ $cr = count($cnd['right']);
272
+ $ci = count(array_intersect($cnd['left'], (array) $cnd['right']));
273
+
274
+ $res = $res || (($cl === $cr) && ($ci === $cl));
275
+ } else {
276
+ $res = $res || in_array($cnd['left'], (array) $cnd['right'], true);
277
+ }
278
  }
279
 
280
+ return $res;
281
  }
282
 
283
  /**
application/Core/Policy/Manager.php CHANGED
@@ -10,6 +10,8 @@
10
  /**
11
  * AAM policy manager for a specific subject
12
  *
 
 
13
  * @since 6.4.0 Supporting Param's "Value" to be an array
14
  * @since 6.3.1 Fixed bug where draft policies get applied to assignees
15
  * @since 6.2.1 Added support for the POLICY_META token
@@ -19,7 +21,7 @@
19
  * @since 6.0.0 Initial implementation of the class
20
  *
21
  * @package AAM
22
- * @version 6.4.0
23
  */
24
  class AAM_Core_Policy_Manager
25
  {
@@ -151,11 +153,12 @@ class AAM_Core_Policy_Manager
151
  *
152
  * @return array
153
  *
154
- * @since 6.4.1 Fixed https://github.com/aamplugin/advanced-access-manager/issues/84
 
155
  * @since 6.0.0 Initial implementation of the method
156
  *
157
  * @access public
158
- * @version 6.4.1
159
  */
160
  public function getResources($s, $args = array())
161
  {
@@ -167,10 +170,14 @@ class AAM_Core_Policy_Manager
167
 
168
  $statements = array();
169
 
170
- foreach ($this->tree['Statement'] as $key => $stm) {
171
- if (preg_match($regex, $key) && $this->isApplicable($stm, $args)) {
172
- // Remove the resource type to keep it clean
173
- $statements[preg_replace($regex, '', $key)] = $stm;
 
 
 
 
174
  }
175
  }
176
 
@@ -217,8 +224,11 @@ class AAM_Core_Policy_Manager
217
  *
218
  * @return boolean|null
219
  *
 
 
 
220
  * @access public
221
- * @version 6.0.0
222
  */
223
  public function isAllowed($resource, $args = array())
224
  {
@@ -226,9 +236,11 @@ class AAM_Core_Policy_Manager
226
  $id = strtolower($resource);
227
 
228
  if (isset($this->tree['Statement'][$id])) {
229
- $stm = $this->tree['Statement'][$id];
 
 
230
 
231
- if ($this->isApplicable($stm, $args)) {
232
  $allowed = (strtolower($stm['Effect']) === 'allow');
233
  }
234
  }
@@ -236,6 +248,43 @@ class AAM_Core_Policy_Manager
236
  return $allowed;
237
  }
238
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  /**
240
  * Get parsed policy tree
241
  *
@@ -254,13 +303,14 @@ class AAM_Core_Policy_Manager
254
  *
255
  * @return void
256
  *
 
257
  * @since 6.4.1 Changed the way updatePolicyTree is invoked
258
  * @since 6.3.1 Fixed bug https://github.com/aamplugin/advanced-access-manager/issues/49
259
  * @since 6.2.0 Changed the way access policies are fetched
260
  * @since 6.0.0 Initial implementation of the method
261
  *
262
  * @access public
263
- * @version 6.4.1
264
  */
265
  public function initialize()
266
  {
@@ -281,7 +331,7 @@ class AAM_Core_Policy_Manager
281
  $this->updatePolicyTree($this->parsePolicy($policy));
282
  }
283
 
284
- $this->_cleanupTree();
285
  }
286
  }
287
 
@@ -394,6 +444,8 @@ class AAM_Core_Policy_Manager
394
  *
395
  * @return array
396
  *
 
 
397
  * @since 6.4.1 Simplified by removing &$tree first param
398
  * @since 6.4.0 Supporting Param's Value to be more than just a scalar value
399
  * @since 6.2.1 Typecasting param's value
@@ -401,35 +453,16 @@ class AAM_Core_Policy_Manager
401
  * @since 6.0.0 Initial implementation of the method
402
  *
403
  * @access protected
404
- * @version 6.4.1
405
  */
406
  protected function updatePolicyTree($addition)
407
  {
408
  $stmts = &$this->tree['Statement'];
409
  $params = &$this->tree['Param'];
410
 
411
- // Step #1. If there are any statements, let's index them by resource:action
412
- // and insert into the list of statements
413
- foreach ($addition['Statement'] as $stm) {
414
- $resources = (isset($stm['Resource']) ? (array) $stm['Resource'] : array());
415
- $actions = (isset($stm['Action']) ? (array) $stm['Action'] : array(''));
416
-
417
- foreach ($resources as $res) {
418
- foreach($this->evaluatePolicyKey($res) as $resource) {
419
- foreach ($actions as $act) {
420
- $id = strtolower($resource . (!empty($act) ? ":{$act}" : ''));
421
-
422
- if (!isset($stmts[$id]) || empty($stmts[$id]['Enforce'])) {
423
- $stmts[$id] = $stm;
424
- }
425
- }
426
- }
427
- }
428
- }
429
-
430
  $callback = array($this, 'getOption'); // Callback that hooks into get_option
431
 
432
- // Step #2. If there are any params, let's index them and insert into the list
433
  foreach ($addition['Param'] as $param) {
434
  if (!empty($param['Key'])) {
435
  $param['Value'] = $this->replaceTokens($param['Value'], true);
@@ -450,6 +483,31 @@ class AAM_Core_Policy_Manager
450
  }
451
  }
452
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
453
  }
454
 
455
  /**
@@ -564,19 +622,28 @@ class AAM_Core_Policy_Manager
564
  /**
565
  * Perform some internal clean-up
566
  *
 
 
567
  * @return void
568
  *
 
 
 
569
  * @access private
570
- * @version 6.0.0
571
  */
572
- private function _cleanupTree()
573
  {
574
- foreach($this->tree['Statement'] as $id => $stm) {
575
- if (isset($stm['Resource'])) {
576
- unset($this->tree['Statement'][$id]['Resource']);
577
- }
578
- if (isset($stm['Action'])) {
579
- unset($this->tree['Statement'][$id]['Action']);
 
 
 
 
580
  }
581
  }
582
  }
10
  /**
11
  * AAM policy manager for a specific subject
12
  *
13
+ * @since 6.5.3 https://github.com/aamplugin/advanced-access-manager/issues/122
14
+ * https://github.com/aamplugin/advanced-access-manager/issues/124
15
  * @since 6.4.0 Supporting Param's "Value" to be an array
16
  * @since 6.3.1 Fixed bug where draft policies get applied to assignees
17
  * @since 6.2.1 Added support for the POLICY_META token
21
  * @since 6.0.0 Initial implementation of the class
22
  *
23
  * @package AAM
24
+ * @version 6.5.3
25
  */
26
  class AAM_Core_Policy_Manager
27
  {
153
  *
154
  * @return array
155
  *
156
+ * @since 6.5.3 https://github.com/aamplugin/advanced-access-manager/issues/124
157
+ * @since 6.4.1 https://github.com/aamplugin/advanced-access-manager/issues/84
158
  * @since 6.0.0 Initial implementation of the method
159
  *
160
  * @access public
161
+ * @version 6.5.3
162
  */
163
  public function getResources($s, $args = array())
164
  {
170
 
171
  $statements = array();
172
 
173
+ foreach ($this->tree['Statement'] as $key => $stms) {
174
+ if (preg_match($regex, $key)) {
175
+ $stm = $this->getCandidateStatement($stms, $args);
176
+
177
+ if (!is_null($stm)) {
178
+ // Remove the resource type to keep it clean
179
+ $statements[preg_replace($regex, '', $key)] = $stm;
180
+ }
181
  }
182
  }
183
 
224
  *
225
  * @return boolean|null
226
  *
227
+ * @since 6.5.3 https://github.com/aamplugin/advanced-access-manager/issues/124
228
+ * @since 6.0.0 Initial implementation of the method
229
+ *
230
  * @access public
231
+ * @version 6.5.3
232
  */
233
  public function isAllowed($resource, $args = array())
234
  {
236
  $id = strtolower($resource);
237
 
238
  if (isset($this->tree['Statement'][$id])) {
239
+ $stm = $this->getCandidateStatement(
240
+ $this->tree['Statement'][$id], $args
241
+ );
242
 
243
+ if (!is_null($stm)) {
244
  $allowed = (strtolower($stm['Effect']) === 'allow');
245
  }
246
  }
248
  return $allowed;
249
  }
250
 
251
+ /**
252
+ * Based on multiple competing statements, get the best candidate
253
+ *
254
+ * @param array $statements
255
+ * @param array $args
256
+ *
257
+ * @return array|null
258
+ *
259
+ * @access protected
260
+ * @version 6.5.3
261
+ */
262
+ protected function getCandidateStatement($statements, $args = array())
263
+ {
264
+ $candidate = null;
265
+
266
+ if (is_array($statements) && isset($statements[0])) {
267
+ // Take in consideration ONLY currently applicable statements and select
268
+ // either the last statement or the one that is enforced
269
+ $enforced = false;
270
+
271
+ foreach($statements as $stm) {
272
+ if ($this->isApplicable($stm, $args)) {
273
+ if (!empty($stm['Enforce'])) {
274
+ $candidate = $stm;
275
+ $enforced = true;
276
+ } elseif ($enforced === false) {
277
+ $candidate = $stm;
278
+ }
279
+ }
280
+ }
281
+ } else {
282
+ $candidate = $statements;
283
+ }
284
+
285
+ return $candidate;
286
+ }
287
+
288
  /**
289
  * Get parsed policy tree
290
  *
303
  *
304
  * @return void
305
  *
306
+ * @since 6.5.3 https://github.com/aamplugin/advanced-access-manager/issues/124
307
  * @since 6.4.1 Changed the way updatePolicyTree is invoked
308
  * @since 6.3.1 Fixed bug https://github.com/aamplugin/advanced-access-manager/issues/49
309
  * @since 6.2.0 Changed the way access policies are fetched
310
  * @since 6.0.0 Initial implementation of the method
311
  *
312
  * @access public
313
+ * @version 6.5.3
314
  */
315
  public function initialize()
316
  {
331
  $this->updatePolicyTree($this->parsePolicy($policy));
332
  }
333
 
334
+ $this->_cleanupTree($this->tree['Statement']);
335
  }
336
  }
337
 
444
  *
445
  * @return array
446
  *
447
+ * @since 6.5.3 https://github.com/aamplugin/advanced-access-manager/issues/122
448
+ * https://github.com/aamplugin/advanced-access-manager/issues/124
449
  * @since 6.4.1 Simplified by removing &$tree first param
450
  * @since 6.4.0 Supporting Param's Value to be more than just a scalar value
451
  * @since 6.2.1 Typecasting param's value
453
  * @since 6.0.0 Initial implementation of the method
454
  *
455
  * @access protected
456
+ * @version 6.5.3
457
  */
458
  protected function updatePolicyTree($addition)
459
  {
460
  $stmts = &$this->tree['Statement'];
461
  $params = &$this->tree['Param'];
462
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
463
  $callback = array($this, 'getOption'); // Callback that hooks into get_option
464
 
465
+ // Step #1. If there are any params, let's index them and insert into the list
466
  foreach ($addition['Param'] as $param) {
467
  if (!empty($param['Key'])) {
468
  $param['Value'] = $this->replaceTokens($param['Value'], true);
483
  }
484
  }
485
  }
486
+
487
+ // Step #2. If there are any statements, let's index them by resource:action
488
+ // and insert into the list of statements
489
+ foreach ($addition['Statement'] as $stm) {
490
+ $resources = (isset($stm['Resource']) ? (array) $stm['Resource'] : array());
491
+ $actions = (isset($stm['Action']) ? (array) $stm['Action'] : array(''));
492
+
493
+ foreach ($resources as $res) {
494
+ foreach($this->evaluatePolicyKey($res) as $resource) {
495
+ foreach ($actions as $act) {
496
+ $id = strtolower($resource . (!empty($act) ? ":{$act}" : ''));
497
+
498
+ if (isset($stmts[$id])) {
499
+ if (isset($stmts[$id][0])) {
500
+ $stmts[$id][] = $stm;
501
+ } else {
502
+ $stmts[$id] = array($stmts[$id], $stm);
503
+ }
504
+ } else {
505
+ $stmts[$id] = $stm;
506
+ }
507
+ }
508
+ }
509
+ }
510
+ }
511
  }
512
 
513
  /**
622
  /**
623
  * Perform some internal clean-up
624
  *
625
+ * @param array &$statements
626
+ *
627
  * @return void
628
  *
629
+ * @since 6.5.3 https://github.com/aamplugin/advanced-access-manager/issues/124
630
+ * @since 6.0.0 Initial implementation of the method
631
+ *
632
  * @access private
633
+ * @version 6.5.3
634
  */
635
+ private function _cleanupTree(&$statements)
636
  {
637
+ foreach($statements as $id => &$stm) {
638
+ if (is_array($stm) && isset($stm[0])) {
639
+ $this->_cleanupTree($stm);
640
+ } else {
641
+ if (isset($stm['Resource'])) {
642
+ unset($statements[$id]['Resource']);
643
+ }
644
+ if (isset($stm['Action'])) {
645
+ unset($statements[$id]['Action']);
646
+ }
647
  }
648
  }
649
  }
application/Service/Core.php CHANGED
@@ -10,6 +10,7 @@
10
  /**
11
  * AAM core service
12
  *
 
13
  * @since 6.4.2 Fixed https://github.com/aamplugin/advanced-access-manager/issues/82
14
  * @since 6.4.0 Added "Manage Access" toolbar item to single & multisite network
15
  * @since 6.0.5 Making sure that only if user is allowed to manage other users
@@ -17,7 +18,7 @@
17
  * @since 6.0.0 Initial implementation of the class
18
  *
19
  * @package AAM
20
- * @version 6.4.2
21
  */
22
  class AAM_Service_Core
23
  {
@@ -144,8 +145,11 @@ class AAM_Service_Core
144
  *
145
  * @return array
146
  *
 
 
 
147
  * @access public
148
- * @version 6.0.0
149
  */
150
  public function checkForUpdates($response, $r, $url)
151
  {
@@ -177,12 +181,14 @@ class AAM_Service_Core
177
  // currently installed version on the website and if match found,
178
  // override the original response to indicate that new version is
179
  // available
180
- foreach ($new_body['products'] as $item) {
181
- $v = $repository->getPluginVersion($item['plugin']);
182
- $new_v = $item['new_version'];
 
183
 
184
- if (!empty($v) && (version_compare($v, $new_v) === -1)) {
185
- $original['plugins'][$item['plugin']] = $item;
 
186
  }
187
  }
188
 
@@ -283,15 +289,18 @@ class AAM_Service_Core
283
  *
284
  * @return array
285
  *
 
 
 
286
  * @access public
287
- * @version 6.0.0
288
  */
289
  public function mapMetaCaps($caps, $cap, $user_id, $args)
290
  {
291
  $objectId = (isset($args[0]) ? $args[0] : null);
292
 
293
  // Mutate any AAM specific capability if it does not exist
294
- foreach ($caps as $i => $capability) {
295
  if (
296
  (strpos($capability, 'aam_') === 0)
297
  && !AAM_Core_API::capExists($capability)
10
  /**
11
  * AAM core service
12
  *
13
+ * @since 6.5.3 https://github.com/aamplugin/advanced-access-manager/issues/126
14
  * @since 6.4.2 Fixed https://github.com/aamplugin/advanced-access-manager/issues/82
15
  * @since 6.4.0 Added "Manage Access" toolbar item to single & multisite network
16
  * @since 6.0.5 Making sure that only if user is allowed to manage other users
18
  * @since 6.0.0 Initial implementation of the class
19
  *
20
  * @package AAM
21
+ * @version 6.5.3
22
  */
23
  class AAM_Service_Core
24
  {
145
  *
146
  * @return array
147
  *
148
+ * @since 6.5.3 https://github.com/aamplugin/advanced-access-manager/issues/126
149
+ * @since 6.0.0 Initial implementation of the method
150
+ *
151
  * @access public
152
+ * @version 6.5.3
153
  */
154
  public function checkForUpdates($response, $r, $url)
155
  {
181
  // currently installed version on the website and if match found,
182
  // override the original response to indicate that new version is
183
  // available
184
+ if (!empty($new_body['products']) && is_array($new_body['products'])) {
185
+ foreach ($new_body['products'] as $item) {
186
+ $v = $repository->getPluginVersion($item['plugin']);
187
+ $new_v = $item['new_version'];
188
 
189
+ if (!empty($v) && (version_compare($v, $new_v) === -1)) {
190
+ $original['plugins'][$item['plugin']] = $item;
191
+ }
192
  }
193
  }
194
 
289
  *
290
  * @return array
291
  *
292
+ * @since 6.5.3 https://github.com/aamplugin/advanced-access-manager/issues/126
293
+ * @since 6.0.0 Initial implementation of the method
294
+ *
295
  * @access public
296
+ * @version 6.5.3
297
  */
298
  public function mapMetaCaps($caps, $cap, $user_id, $args)
299
  {
300
  $objectId = (isset($args[0]) ? $args[0] : null);
301
 
302
  // Mutate any AAM specific capability if it does not exist
303
+ foreach ((array) $caps as $i => $capability) {
304
  if (
305
  (strpos($capability, 'aam_') === 0)
306
  && !AAM_Core_API::capExists($capability)
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.4.1
7
- Stable tag: 6.5.2
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,12 @@ We take security and privacy very seriously, that is why there are several non-n
91
 
92
  == Changelog ==
93
 
 
 
 
 
 
 
94
  = 6.5.2 =
95
  * Fixed Bug: Passwordless authentication disregards "redirect_to" query param [https://github.com/aamplugin/advanced-access-manager/issues/117](https://github.com/aamplugin/advanced-access-manager/issues/117)
96
  * Fixed Bug: Failing to reset user expiration settings [https://github.com/aamplugin/advanced-access-manager/issues/119](https://github.com/aamplugin/advanced-access-manager/issues/119)
4
  Requires at least: 4.7.0
5
  Requires PHP: 5.6.0
6
  Tested up to: 5.4.1
7
+ Stable tag: 6.5.3
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.5.3 =
95
+ * Fixed Bug: PHP Warning: Parameter must be an array or an object that implements Countable in /service/core.php [https://github.com/aamplugin/advanced-access-manager/issues/126](https://github.com/aamplugin/advanced-access-manager/issues/126)
96
+ * Added New: Allow to target the same resource with multiple statements [https://github.com/aamplugin/advanced-access-manager/issues/124](https://github.com/aamplugin/advanced-access-manager/issues/124)
97
+ * Added New: Enhance "In" condition for the access policies [https://github.com/aamplugin/advanced-access-manager/issues/123](https://github.com/aamplugin/advanced-access-manager/issues/123)
98
+ * Changed: Change the access policy initialization order [https://github.com/aamplugin/advanced-access-manager/issues/122](https://github.com/aamplugin/advanced-access-manager/issues/122)
99
+
100
  = 6.5.2 =
101
  * Fixed Bug: Passwordless authentication disregards "redirect_to" query param [https://github.com/aamplugin/advanced-access-manager/issues/117](https://github.com/aamplugin/advanced-access-manager/issues/117)
102
  * Fixed Bug: Failing to reset user expiration settings [https://github.com/aamplugin/advanced-access-manager/issues/119](https://github.com/aamplugin/advanced-access-manager/issues/119)