Advanced Access Manager - Version 5.3

Version Description

  • Fixed the bug with ConfigPress settings when array is defined
  • Fixed the bug with jwt authentication
  • Fixed the bug with infinite logout loop when user is locked
  • Refactored internal functionality to make it fully compatible with WP REST API
  • Split Posts & Pages access control on Backend, Frontend and API sections
  • Cleaned up posts and pages access settings
  • Refactored internal AAM cache to make it more flexible and faster
  • Added "API Access Control" option
  • Added ability to change user role after certain period of time
  • Removed ability to lock Dashboard menu
Download this release

Release Info

Developer vasyl_m
Plugin Icon 128x128 Advanced Access Manager
Version 5.3
Comparing to
See all releases

Code changes from version 5.2.7 to 5.3

Files changed (44) hide show
  1. Application/Api/Manager.php +166 -0
  2. Application/{Frontend/Rest.php → Api/Rest/Resource/Post.php} +109 -144
  3. Application/Api/Rest/Resource/Revision.php +66 -0
  4. Application/Api/Rest/Resource/User.php +99 -0
  5. Application/Backend/Authorization.php +0 -120
  6. Application/Backend/Feature/Main/Post.php +22 -6
  7. Application/Backend/Feature/Settings/Core.php +6 -1
  8. Application/Backend/Feature/Settings/Tools.php +3 -1
  9. Application/Backend/Feature/Subject/User.php +5 -3
  10. Application/Backend/Filter.php +20 -67
  11. Application/Backend/Manager.php +4 -1
  12. Application/Backend/View.php +17 -11
  13. Application/Backend/View/PostOptionList.php +104 -40
  14. Application/Backend/phtml/index.phtml +7 -0
  15. Application/Backend/phtml/main/menu.phtml +14 -12
  16. Application/Backend/phtml/main/post.phtml +11 -58
  17. Application/Backend/phtml/{frame.phtml → metabox/metabox-content.phtml} +8 -61
  18. Application/Backend/phtml/{post-metabox.phtml → metabox/post-metabox.phtml} +0 -0
  19. Application/Backend/phtml/{term-metabox.phtml → metabox/term-metabox.phtml} +1 -1
  20. Application/Backend/phtml/partial/post-access-form.phtml +118 -0
  21. Application/Backend/phtml/partial/post-advanced-settings.phtml +31 -32
  22. Application/Backend/phtml/partial/role-inheritance.phtml +1 -1
  23. Application/Backend/phtml/partial/term-type.phtml +1 -1
  24. Application/Core/API.php +67 -71
  25. Application/Core/Api/Area.php +79 -0
  26. Application/Core/Cache.php +6 -112
  27. Application/Core/Compatibility.php +1 -16
  28. Application/Core/ConfigPress/Reader.php +1 -1
  29. Application/Core/JwtAuth.php +23 -15
  30. Application/Core/Media.php +1 -1
  31. Application/Core/Object/Cache.php +146 -0
  32. Application/Core/Object/Post.php +111 -23
  33. Application/Core/Subject/Role.php +0 -8
  34. Application/Core/Subject/User.php +23 -13
  35. Application/Core/Wp.php +0 -88
  36. Application/Frontend/Filter.php +5 -202
  37. Application/Frontend/Manager.php +56 -0
  38. Application/Shared/Manager.php +424 -0
  39. Lang/advanced-access-manager-en_US.po +1 -1
  40. Lang/advanced-access-manager.pot +1 -1
  41. aam.php +7 -7
  42. media/css/aam.css +6 -0
  43. media/js/aam.js +129 -12
  44. readme.txt +14 -2
Application/Api/Manager.php ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
10
+ /**
11
+ * AAM Api access manager
12
+ *
13
+ * @package AAM
14
+ * @author Vasyl Martyniuk <vasyl@vasyltech.com>
15
+ */
16
+ class AAM_Api_Manager {
17
+
18
+ /**
19
+ * Instance of itself
20
+ *
21
+ * @var AAM_Api_Manager
22
+ *
23
+ * @access private
24
+ */
25
+ private static $_instance = null;
26
+
27
+ /**
28
+ * Map of routes and resources
29
+ *
30
+ * @var array
31
+ *
32
+ * @access protected
33
+ */
34
+ protected $resources = array(
35
+ 'post' => array (
36
+ '/wp/v2/posts',
37
+ '/wp/v2/posts/(?P<id>[\d]+)',
38
+ '/wp/v2/pages',
39
+ '/wp/v2/pages/(?P<id>[\d]+)',
40
+ '/wp/v2/media',
41
+ '/wp/v2/media/(?P<id>[\d]+)',
42
+ ),
43
+ 'user' => array (
44
+ '/wp/v2/users'
45
+ ),
46
+ 'revision' => array (
47
+ '/wp/v2/posts/(?P<parent>[\d]+)/revisions/(?P<id>[\d]+)',
48
+ '/wp/v2/pages/(?P<parent>[\d]+)/revisions/(?P<id>[\d]+)'
49
+ )
50
+ );
51
+
52
+ /**
53
+ * Construct the manager
54
+ *
55
+ * @return void
56
+ *
57
+ * @access public
58
+ */
59
+ protected function __construct() {
60
+ // REST API action authorization. Triggered before call is dispatched
61
+ add_filter(
62
+ 'rest_request_before_callbacks', array($this, 'beforeDispatch'), 10, 3
63
+ );
64
+
65
+ // Manage access to the RESTful endpoints
66
+ add_filter('rest_pre_dispatch', array($this, 'authorizeRest'), 1, 3);
67
+
68
+ // Check if user has ability to perform certain task based on provided
69
+ // capability and meta data
70
+ if (AAM_Core_Config::get('api-access-control', true)) {
71
+ add_filter(
72
+ 'user_has_cap',
73
+ array(AAM_Shared_Manager::getInstance(), 'userHasCap'),
74
+ 999,
75
+ 3
76
+ );
77
+ }
78
+
79
+ // Register any additional endpoints with ConfigPress
80
+ $additional = AAM_Core_Config::get('rest.manage.endpoint');
81
+
82
+ if (!empty($additional) && is_array($additional)) {
83
+ $this->resources = array_merge_recursive($this->resources, $additional);
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Authorize RESTful action before it is dispatched by RESTful Server
89
+ *
90
+ * @param mixed $response
91
+ * @param object $handler
92
+ * @param object $request
93
+ *
94
+ * @return mixed
95
+ *
96
+ * @access public
97
+ */
98
+ public function beforeDispatch($response, $handler, $request) {
99
+ $result = null;
100
+
101
+ foreach($this->resources as $res => $routes) {
102
+ foreach($routes as $regex) {
103
+ // Route to work with single post
104
+ if(preg_match('#^' . $regex . '$#i', $request->get_route())) {
105
+ $classname = 'AAM_Api_Rest_Resource_' . ucfirst($res);
106
+ $result = $classname::getInstance()->authorize($request);
107
+ }
108
+ }
109
+ }
110
+
111
+ return (is_null($result) ? $response : $result);
112
+ }
113
+
114
+ /**
115
+ * Authorize REST request
116
+ *
117
+ * Based on the matched route, check if it is disabled for current user
118
+ *
119
+ * @param WP_Error|null $response
120
+ * @param WP_REST_Server $server
121
+ * @param WP_REST_Request $request
122
+ *
123
+ * @return WP_Error|null
124
+ *
125
+ * @access public
126
+ */
127
+ public function authorizeRest($response, $server, $request) {
128
+ $user = AAM::getUser();
129
+ $object = $user->getObject('route');
130
+ $matched = $request->get_route();
131
+ $method = $request->get_method();
132
+
133
+ foreach(array_keys($server->get_routes()) as $route) {
134
+ if ($route == $matched || preg_match("#^{$route}$#i", $matched)) {
135
+ if ($object->has('restful', $route, $method)) {
136
+ $response = new WP_Error(
137
+ 'rest_access_denied',
138
+ __('Access denied', AAM_KEY),
139
+ array('status' => 401)
140
+ );
141
+ break;
142
+ }
143
+ }
144
+ }
145
+
146
+ return $response;
147
+ }
148
+
149
+ /**
150
+ * Bootstrap the manager
151
+ *
152
+ * @return void
153
+ *
154
+ * @access public
155
+ */
156
+ public static function bootstrap() {
157
+ global $wp;
158
+
159
+ if (!empty($wp->query_vars['rest_route'])) {
160
+ if (is_null(self::$_instance)) {
161
+ self::$_instance = new self;
162
+ }
163
+ }
164
+ }
165
+
166
+ }
Application/{Frontend/Rest.php → Api/Rest/Resource/Post.php} RENAMED
@@ -8,130 +8,59 @@
8
  */
9
 
10
  /**
11
- * AAM frontend RESTful authorization
12
  *
13
  * @package AAM
14
  * @author Vasyl Martyniuk <vasyl@vasyltech.com>
15
  * @todo Rethink about DRY approach to the post access control
16
  */
17
- class AAM_Frontend_Rest {
18
 
19
  /**
20
  * Instance of itself
21
  *
22
- * @var AAM_Frontend_Rest
23
  *
24
  * @access private
25
  */
26
  private static $_instance = null;
27
 
28
  /**
29
- *
30
- * @var type
31
- */
32
- protected $defaultRoutes = array(
33
- 'posts' => array(
34
- '/wp/v2/posts/(?P<id>[\d]+)',
35
- '/wp/v2/pages/(?P<id>[\d]+)',
36
- '/wp/v2/media/(?P<id>[\d]+)'
37
- )
38
- );
39
-
40
- /**
41
  *
42
- */
43
- protected function __construct() {
44
- add_filter('aam-rest-auth-request-filter', array($this, 'authorize'), 10, 4);
45
-
46
- add_filter('rest_user_query', array($this, 'userQuery'), 10, 2);
47
- }
48
-
49
- /**
50
  *
51
- * @param type $response
52
- * @param type $group
53
- * @param type $request
54
- * @return type
55
- */
56
- public function authorize($response, $group, $request) {
57
- if ($group == 'posts') {
58
- $response = $this->authorizePostAction(
59
- $request['id'], $request->get_method()
60
- );
61
- }
62
-
63
- return $response;
64
- }
65
-
66
- /**
67
  *
68
- * @param array $args
69
- * @param type $request
70
- * @return type
71
- */
72
- public function userQuery($args, $request) {
73
- //current user max level
74
- $max = AAM_Core_API::maxLevel(AAM::getUser()->allcaps);
75
- $exclude = isset($args['role__not_in']) ? $args['role__not_in'] : array();
76
- $roles = AAM_Core_API::getRoles();
77
-
78
- foreach($roles->role_objects as $id => $role) {
79
- if (AAM_Core_API::maxLevel($role->capabilities) > $max) {
80
- $exclude[] = $id;
81
- }
82
- }
83
-
84
- $args['role__not_in'] = $exclude;
85
-
86
- return $args;
87
- }
88
-
89
- /**
90
- *
91
- * @return type
92
- */
93
- public function getRoutes() {
94
- $posts = AAM_Core_Config::get('restful.routes.posts', array());
95
-
96
- $routes = array(
97
- 'posts' => array_merge(
98
- (is_array($posts) ? $posts : array()), $this->defaultRoutes['posts']
99
- )
100
- );
101
-
102
- return apply_filters('aam-rest-auth-routes-filter', $routes);
103
- }
104
-
105
- /**
106
- *
107
- * @param type $id
108
- * @param type $method
109
- * @return type
110
  */
111
- protected function authorizePostAction($id, $method) {
112
- $post = AAM::getUser()->getObject('post', $id);
113
 
114
- switch($method) {
115
- case 'GET':
116
- $result = $this->chechReadAuth($post);
117
- break;
118
 
119
- case 'POST':
120
- case 'PUT':
121
- case 'PATCH':
122
- $result = $this->chechUpdateAuth($post);
123
- break;
124
 
125
- case 'DELETE':
126
- $result = $this->chechDeleteAuth($post);
127
- break;
 
 
 
 
 
 
128
 
129
- default:
130
- $result = null;
131
- break;
132
  }
133
 
134
- return $result;
135
  }
136
 
137
  /**
@@ -141,14 +70,16 @@ class AAM_Frontend_Rest {
141
  * This method run multiple checks at-once
142
  *
143
  * @param AAM_Core_Object_Post $post
 
144
  *
145
  * @return void
146
  *
147
  * @access protected
148
  */
149
- protected function chechReadAuth(AAM_Core_Object_Post $post) {
150
  $result = null;
151
 
 
152
  $steps = apply_filters('aam-post-read-auth-pipeline-filter', array(
153
  // Step #1. Check if access expired to the post
154
  array($this, 'checkExpiration'),
@@ -157,16 +88,16 @@ class AAM_Frontend_Rest {
157
  // Step #3. Check if counter exceeded max allowed views
158
  array($this, 'checkCounter'),
159
  // Step #4. Check if redirect is defined for the post
160
- array($this, 'checkRedirect')
 
 
161
  ));
162
 
163
  if (is_array($steps)) {
164
  foreach($steps as $callback) {
165
- $result = call_user_func_array($callback, array($post));
166
 
167
- if (is_wp_error($result)) {
168
- break;
169
- }
170
  }
171
  } else {
172
  $result = new WP_Error(
@@ -183,10 +114,10 @@ class AAM_Frontend_Rest {
183
  * @param AAM_Core_Object_Post $post
184
  * @return type
185
  */
186
- protected function chechUpdateAuth(AAM_Core_Object_Post $post) {
187
  $result = null;
188
 
189
- $steps = apply_filters('aam-post-update-auth-steps-filter', array(
190
  // Step #1. Check if edit action is alloed
191
  array($this, 'checkUpdate'),
192
  ));
@@ -195,9 +126,7 @@ class AAM_Frontend_Rest {
195
  foreach($steps as $callback) {
196
  $result = call_user_func_array($callback, array($post));
197
 
198
- if (is_wp_error($result)) {
199
- break;
200
- }
201
  }
202
  } else {
203
  $result = new WP_Error(
@@ -214,7 +143,7 @@ class AAM_Frontend_Rest {
214
  * @param AAM_Core_Object_Post $post
215
  * @return type
216
  */
217
- protected function chechDeleteAuth(AAM_Core_Object_Post $post) {
218
  $result = null;
219
 
220
  $steps = apply_filters('aam-post-delete-auth-steps-filter', array(
@@ -226,9 +155,7 @@ class AAM_Frontend_Rest {
226
  foreach($steps as $callback) {
227
  $result = call_user_func_array($callback, array($post));
228
 
229
- if (is_wp_error($result)) {
230
- break;
231
- }
232
  }
233
  } else {
234
  $result = new WP_Error(
@@ -253,14 +180,12 @@ class AAM_Frontend_Rest {
253
  * @access protected
254
  */
255
  protected function checkExpiration($post) {
256
- $expire = $post->has('frontend.expire');
257
 
258
  if ($expire) {
259
- $date = strtotime($post->get('frontend.expire_datetime'));
260
  if ($date <= time()) {
261
- $actions = AAM_Core_Config::get(
262
- 'post.access.expired', 'frontend.read'
263
- );
264
 
265
  foreach(array_map('trim', explode(',', $actions)) as $action) {
266
  $post->set($action, 1);
@@ -281,15 +206,15 @@ class AAM_Frontend_Rest {
281
  protected function checkReadAccess(AAM_Core_Object_Post $post) {
282
  $result = null;
283
 
284
- $read = $post->has('frontend.read');
285
- $others = $post->has('frontend.read_others');
286
 
287
  if ($read || ($others && ($post->post_author != get_current_user_id()))) {
288
  $result = new WP_Error(
289
- 'post_read_access_denied',
290
  "User is unauthorized to read the post. Access denied.",
291
  array(
292
- 'action' => 'frontend.read',
293
  'status' => 401
294
  )
295
  );
@@ -312,16 +237,16 @@ class AAM_Frontend_Rest {
312
  $user = get_current_user_id();
313
 
314
  //check counter only for authenticated users and if ACCESS COUNTER is set
315
- if ($user && $post->has('frontend.access_counter')) {
316
- $option = 'aam-post-' . $post->ID . '-access-counter';
317
  $counter = intval(get_user_meta($user, $option, true));
318
 
319
- if ($counter >= $post->get('frontend.access_counter_limit')) {
320
  $result = new WP_Error(
321
- 'post_read_access_denied',
322
  "User exceeded allowed read number. Access denied.",
323
  array(
324
- 'action' => 'frontend.access_counter',
325
  'status' => 401
326
  )
327
  );
@@ -345,13 +270,13 @@ class AAM_Frontend_Rest {
345
  protected function checkRedirect(AAM_Core_Object_Post $post) {
346
  $result = null;
347
 
348
- if ($post->has('frontend.redirect')) {
349
  $result = new WP_Error(
350
- 'post_read_access_denied',
351
- "Direct access is not allowed. Access redirected",
352
  array(
353
- 'action' => 'frontend.redirect',
354
- 'redirect' => $post->get('frontend.location'),
355
  'status' => 307
356
  )
357
  );
@@ -360,6 +285,47 @@ class AAM_Frontend_Rest {
360
  return $result;
361
  }
362
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
363
  /**
364
  * Check EDIT & EDIT_BY_OTHERS options
365
  *
@@ -372,15 +338,15 @@ class AAM_Frontend_Rest {
372
  protected function checkUpdate(AAM_Core_Object_Post $post) {
373
  $result = null;
374
 
375
- $edit = $post->has('backend.edit');
376
- $others = $post->has('backend.edit_others');
377
 
378
  if ($edit || ($others && ($post->post_author != get_current_user_id()))) {
379
  $result = new WP_Error(
380
- 'post_update_access_denied',
381
  "User is unauthorized to update the post. Access denied.",
382
  array(
383
- 'action' => 'backend.edit',
384
  'status' => 401
385
  )
386
  );
@@ -401,15 +367,15 @@ class AAM_Frontend_Rest {
401
  protected function checkDelete(AAM_Core_Object_Post $post) {
402
  $result = null;
403
 
404
- $delete = $post->has('backend.delete');
405
- $others = $post->has('backend.delete_others');
406
 
407
  if ($delete || ($others && ($post->post_author != get_current_user_id()))) {
408
  $result = new WP_Error(
409
- 'post_delete_access_denied',
410
  "User is unauthorized to delete the post. Access denied.",
411
  array(
412
- 'action' => 'backend.delete',
413
  'status' => 401
414
  )
415
  );
@@ -421,7 +387,7 @@ class AAM_Frontend_Rest {
421
  /**
422
  * Alias for the bootstrap
423
  *
424
- * @return AAM_Frontend_Authorization
425
  *
426
  * @access public
427
  * @static
@@ -433,7 +399,7 @@ class AAM_Frontend_Rest {
433
  /**
434
  * Bootstrap authorization layer
435
  *
436
- * @return void
437
  *
438
  * @access public
439
  */
@@ -444,5 +410,4 @@ class AAM_Frontend_Rest {
444
 
445
  return self::$_instance;
446
  }
447
-
448
  }
8
  */
9
 
10
  /**
11
+ * AAM RESTful Posts Resource
12
  *
13
  * @package AAM
14
  * @author Vasyl Martyniuk <vasyl@vasyltech.com>
15
  * @todo Rethink about DRY approach to the post access control
16
  */
17
+ class AAM_Api_Rest_Resource_Post {
18
 
19
  /**
20
  * Instance of itself
21
  *
22
+ * @var AAM_Api_Rest_Resource_Post
23
  *
24
  * @access private
25
  */
26
  private static $_instance = null;
27
 
28
  /**
29
+ * Authorize Post actions
 
 
 
 
 
 
 
 
 
 
 
30
  *
31
+ * @param WP_REST_Request $request
 
 
 
 
 
 
 
32
  *
33
+ * @return WP_Error|null
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  *
35
+ * @access public
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  */
37
+ public function authorize($request) {
38
+ $result = null;
39
 
40
+ if ($request['id']) {
41
+ $post = AAM::getUser()->getObject('post', $request['id']);
 
 
42
 
43
+ switch($request->get_method()) {
44
+ case 'GET':
45
+ $result = $this->authorizeRead($post, $request);
46
+ break;
 
47
 
48
+ case 'POST':
49
+ case 'PUT':
50
+ case 'PATCH':
51
+ $result = $this->authorizeUpdate($post);
52
+ break;
53
+
54
+ case 'DELETE':
55
+ $result = $this->authorizeDelete($post);
56
+ break;
57
 
58
+ default:
59
+ break;
60
+ }
61
  }
62
 
63
+ return apply_filters('aam-rest-post-authorization', $result, $request);
64
  }
65
 
66
  /**
70
  * This method run multiple checks at-once
71
  *
72
  * @param AAM_Core_Object_Post $post
73
+ * @param WP_REST_Request $request
74
  *
75
  * @return void
76
  *
77
  * @access protected
78
  */
79
+ protected function authorizeRead(AAM_Core_Object_Post $post, $request) {
80
  $result = null;
81
 
82
+ //TODO: remove pipeline filter for all methods
83
  $steps = apply_filters('aam-post-read-auth-pipeline-filter', array(
84
  // Step #1. Check if access expired to the post
85
  array($this, 'checkExpiration'),
88
  // Step #3. Check if counter exceeded max allowed views
89
  array($this, 'checkCounter'),
90
  // Step #4. Check if redirect is defined for the post
91
+ array($this, 'checkRedirect'),
92
+ // Step #5. Check if post is password protected
93
+ array($this, 'checkPassword')
94
  ));
95
 
96
  if (is_array($steps)) {
97
  foreach($steps as $callback) {
98
+ $result = call_user_func_array($callback, array($post, $request));
99
 
100
+ if (is_wp_error($result)) { break; }
 
 
101
  }
102
  } else {
103
  $result = new WP_Error(
114
  * @param AAM_Core_Object_Post $post
115
  * @return type
116
  */
117
+ protected function authorizeUpdate(AAM_Core_Object_Post $post) {
118
  $result = null;
119
 
120
+ $steps = apply_filters('aam-post-update-auth-pipeline-filter', array(
121
  // Step #1. Check if edit action is alloed
122
  array($this, 'checkUpdate'),
123
  ));
126
  foreach($steps as $callback) {
127
  $result = call_user_func_array($callback, array($post));
128
 
129
+ if (is_wp_error($result)) { break; }
 
 
130
  }
131
  } else {
132
  $result = new WP_Error(
143
  * @param AAM_Core_Object_Post $post
144
  * @return type
145
  */
146
+ protected function authorizeDelete(AAM_Core_Object_Post $post) {
147
  $result = null;
148
 
149
  $steps = apply_filters('aam-post-delete-auth-steps-filter', array(
155
  foreach($steps as $callback) {
156
  $result = call_user_func_array($callback, array($post));
157
 
158
+ if (is_wp_error($result)) { break; }
 
 
159
  }
160
  } else {
161
  $result = new WP_Error(
180
  * @access protected
181
  */
182
  protected function checkExpiration($post) {
183
+ $expire = $post->has('api.expire');
184
 
185
  if ($expire) {
186
+ $date = strtotime($post->get('api.expire_datetime'));
187
  if ($date <= time()) {
188
+ $actions = AAM_Core_Config::get('post.access.expired', 'api.read');
 
 
189
 
190
  foreach(array_map('trim', explode(',', $actions)) as $action) {
191
  $post->set($action, 1);
206
  protected function checkReadAccess(AAM_Core_Object_Post $post) {
207
  $result = null;
208
 
209
+ $read = $post->has('api.read');
210
+ $others = $post->has('api.read_others');
211
 
212
  if ($read || ($others && ($post->post_author != get_current_user_id()))) {
213
  $result = new WP_Error(
214
+ 'rest_cannot_read',
215
  "User is unauthorized to read the post. Access denied.",
216
  array(
217
+ 'action' => 'api.read',
218
  'status' => 401
219
  )
220
  );
237
  $user = get_current_user_id();
238
 
239
  //check counter only for authenticated users and if ACCESS COUNTER is set
240
+ if ($user && $post->has('api.access_counter')) {
241
+ $option = 'aam-post-api-' . $post->ID . '-access-counter';
242
  $counter = intval(get_user_meta($user, $option, true));
243
 
244
+ if ($counter >= $post->get('api.access_counter_limit')) {
245
  $result = new WP_Error(
246
+ 'rest_cannot_read',
247
  "User exceeded allowed read number. Access denied.",
248
  array(
249
+ 'action' => 'api.access_counter',
250
  'status' => 401
251
  )
252
  );
270
  protected function checkRedirect(AAM_Core_Object_Post $post) {
271
  $result = null;
272
 
273
+ if ($post->has('api.redirect')) {
274
  $result = new WP_Error(
275
+ 'rest_cannot_read',
276
+ "Direct access is not allowed. Follow the redirect link.",
277
  array(
278
+ 'action' => 'api.redirect',
279
+ 'redirect' => $post->get('api.location'),
280
  'status' => 307
281
  )
282
  );
285
  return $result;
286
  }
287
 
288
+ /**
289
+ * Check PASSWORD PROTECTED option
290
+ *
291
+ * @param AAM_Core_Object_Post $post
292
+ * @param WP_REST_Request $request
293
+ *
294
+ * @return null|WP_Error
295
+ *
296
+ * @access public
297
+ */
298
+ public function checkPassword(AAM_Core_Object_Post $post, $request) {
299
+ $result = null;
300
+
301
+ if ($post->has('api.protected')) {
302
+ $pass = $post->get('api.password');
303
+
304
+ // initialize hasher
305
+ require_once( ABSPATH . 'wp-includes/class-phpass.php' );
306
+ $hasher = new PasswordHash(8, true);
307
+
308
+ if ($pass != $request['password']
309
+ && !$hasher->CheckPassword($pass, $request['password'])) {
310
+ $result = new WP_Error(
311
+ 'rest_cannot_read',
312
+ "The content is password protected. Provide valid password to read.",
313
+ array(
314
+ 'action' => 'api.protected',
315
+ 'status' => 401
316
+ )
317
+ );
318
+ }
319
+
320
+ // Very important! Unset password. Otherwise it will fall back to the
321
+ // default password verification and this will cause invalid password
322
+ // response
323
+ $request['password'] = null;
324
+ }
325
+
326
+ return $result;
327
+ }
328
+
329
  /**
330
  * Check EDIT & EDIT_BY_OTHERS options
331
  *
338
  protected function checkUpdate(AAM_Core_Object_Post $post) {
339
  $result = null;
340
 
341
+ $edit = $post->has('api.edit');
342
+ $others = $post->has('api.edit_others');
343
 
344
  if ($edit || ($others && ($post->post_author != get_current_user_id()))) {
345
  $result = new WP_Error(
346
+ 'rest_cannot_update',
347
  "User is unauthorized to update the post. Access denied.",
348
  array(
349
+ 'action' => 'api.edit',
350
  'status' => 401
351
  )
352
  );
367
  protected function checkDelete(AAM_Core_Object_Post $post) {
368
  $result = null;
369
 
370
+ $delete = $post->has('api.delete');
371
+ $others = $post->has('api.delete_others');
372
 
373
  if ($delete || ($others && ($post->post_author != get_current_user_id()))) {
374
  $result = new WP_Error(
375
+ 'rest_cannot_delete',
376
  "User is unauthorized to delete the post. Access denied.",
377
  array(
378
+ 'action' => 'api.delete',
379
  'status' => 401
380
  )
381
  );
387
  /**
388
  * Alias for the bootstrap
389
  *
390
+ * @return AAM_Api_Rest_Resource_Post
391
  *
392
  * @access public
393
  * @static
399
  /**
400
  * Bootstrap authorization layer
401
  *
402
+ * @return AAM_Api_Rest_Resource_Post
403
  *
404
  * @access public
405
  */
410
 
411
  return self::$_instance;
412
  }
 
413
  }
Application/Api/Rest/Resource/Revision.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
10
+ /**
11
+ * AAM REST Revision Resource
12
+ *
13
+ * @package AAM
14
+ * @author Vasyl Martyniuk <vasyl@vasyltech.com>
15
+ */
16
+ class AAM_Api_Rest_Resource_Revision {
17
+
18
+ /**
19
+ * Instance of itself
20
+ *
21
+ * @var AAM_Api_Rest_Resource_Revision
22
+ *
23
+ * @access private
24
+ */
25
+ private static $_instance = null;
26
+
27
+ /**
28
+ * Authorize User actions
29
+ *
30
+ * @param WP_REST_Request $request
31
+ *
32
+ * @return WP_Error|null
33
+ *
34
+ * @access public
35
+ */
36
+ public function authorize($request) {
37
+ return null;
38
+ }
39
+
40
+ /**
41
+ * Alias for the bootstrap
42
+ *
43
+ * @return AAM_Api_Rest_Resource_Revision
44
+ *
45
+ * @access public
46
+ * @static
47
+ */
48
+ public static function getInstance() {
49
+ return self::bootstrap();
50
+ }
51
+
52
+ /**
53
+ * Bootstrap authorization layer
54
+ *
55
+ * @return AAM_Api_Rest_Resource_Revision
56
+ *
57
+ * @access public
58
+ */
59
+ public static function bootstrap() {
60
+ if (is_null(self::$_instance)) {
61
+ self::$_instance = new self;
62
+ }
63
+
64
+ return self::$_instance;
65
+ }
66
+ }
Application/Api/Rest/Resource/User.php ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
10
+ /**
11
+ * AAM RESTful Users Resource
12
+ *
13
+ * @package AAM
14
+ * @author Vasyl Martyniuk <vasyl@vasyltech.com>
15
+ */
16
+ class AAM_Restful_Resource_User {
17
+
18
+ /**
19
+ * Instance of itself
20
+ *
21
+ * @var AAM_Api_Rest_Resource_User
22
+ *
23
+ * @access private
24
+ */
25
+ private static $_instance = null;
26
+
27
+ /**
28
+ *
29
+ */
30
+ protected function __construct() {
31
+ add_filter('rest_user_query', array($this, 'userQuery'));
32
+ }
33
+
34
+ /**
35
+ * Authorize User actions
36
+ *
37
+ * @param WP_REST_Request $request
38
+ *
39
+ * @return WP_Error|null
40
+ *
41
+ * @access public
42
+ */
43
+ public function authorize($request) {
44
+ return null;
45
+ }
46
+
47
+ /**
48
+ * Alter user select query
49
+ *
50
+ * @param array $args
51
+ *
52
+ * @return array
53
+ *
54
+ * @access public
55
+ */
56
+ public function userQuery($args) {
57
+ //current user max level
58
+ $max = AAM_Core_API::maxLevel(AAM::getUser()->allcaps);
59
+ $exclude = isset($args['role__not_in']) ? $args['role__not_in'] : array();
60
+ $roles = AAM_Core_API::getRoles();
61
+
62
+ foreach($roles->role_objects as $id => $role) {
63
+ if (AAM_Core_API::maxLevel($role->capabilities) > $max) {
64
+ $exclude[] = $id;
65
+ }
66
+ }
67
+
68
+ $args['role__not_in'] = $exclude;
69
+
70
+ return $args;
71
+ }
72
+
73
+ /**
74
+ * Alias for the bootstrap
75
+ *
76
+ * @return AAM_Api_Restf_Resource_User
77
+ *
78
+ * @access public
79
+ * @static
80
+ */
81
+ public static function getInstance() {
82
+ return self::bootstrap();
83
+ }
84
+
85
+ /**
86
+ * Bootstrap authorization layer
87
+ *
88
+ * @return AAM_Api_Rest_Resource_User
89
+ *
90
+ * @access public
91
+ */
92
+ public static function bootstrap() {
93
+ if (is_null(self::$_instance)) {
94
+ self::$_instance = new self;
95
+ }
96
+
97
+ return self::$_instance;
98
+ }
99
+ }
Application/Backend/Authorization.php CHANGED
@@ -37,9 +37,6 @@ class AAM_Backend_Authorization {
37
  add_action('admin_init', array($this, 'checkScreenAccess'));
38
  }
39
 
40
- //additional filter for user capabilities
41
- add_filter('user_has_cap', array($this, 'isUserCapable'), 999, 3);
42
-
43
  //post access
44
  add_action('admin_action_edit', array($this, 'checkEditAccess'));
45
  }
@@ -80,45 +77,6 @@ class AAM_Backend_Authorization {
80
  }
81
  }
82
 
83
- /**
84
- * Check user capability
85
- *
86
- * This is a hack function that add additional layout on top of WordPress
87
- * core functionality. Based on the capability passed in the $args array as
88
- * "0" element, it performs additional check on user's capability to manage
89
- * post.
90
- *
91
- * @param array $allCaps
92
- * @param array $metaCaps
93
- * @param array $args
94
- *
95
- * @return array
96
- *
97
- * @access public
98
- */
99
- public function isUserCapable($allCaps, $metaCaps, $args) {
100
- global $post;
101
-
102
- //check if current user is allowed to edit or delete user
103
- if (in_array($args[0], array('edit_user', 'delete_user'))) {
104
- $allCaps = $this->isAllowedToManagerUser($args[0], $allCaps, $metaCaps);
105
- } elseif (isset($args[2]) && is_scalar($args[2])) { //make sure it is post ID
106
- $allCaps = $this->isAllowedToManagerPost(
107
- $args[0], $args[2], $allCaps, $metaCaps
108
- );
109
- } elseif (is_a($post, 'WP_Post')) {
110
- if (in_array($args[0], array('publish_posts', 'publish_pages'))) {
111
- $object = AAM::getUser()->getObject('post', $post->ID);
112
-
113
- if (!$this->isAllowed('backend.publish', $object)) {
114
- $allCaps = $this->restrictCapabilities($allCaps, $metaCaps);
115
- }
116
- }
117
- }
118
-
119
- return $allCaps;
120
- }
121
-
122
  /**
123
  * Control Edit Post
124
  *
@@ -170,62 +128,6 @@ class AAM_Backend_Authorization {
170
  return $post;
171
  }
172
 
173
- /**
174
- * Check if current user is allowed to manager specified user
175
- *
176
- * @param int $id
177
- * @param array $allcaps
178
- * @param array $metacaps
179
- *
180
- * @return array
181
- *
182
- * @access protected
183
- */
184
- protected function isAllowedToManagerUser($id, $allcaps, $metacaps) {
185
- $user = new WP_User($id);
186
-
187
- //current user max level
188
- $cuserLevel = AAM_Core_API::maxLevel(AAM::getUser()->allcaps);
189
- //userLevel
190
- $userLevel = AAM_Core_API::maxLevel($user->allcaps);
191
-
192
- if ($cuserLevel < $userLevel) {
193
- $allcaps = $this->restrictCapabilities($allcaps, $metacaps);
194
- }
195
-
196
- return $allcaps;
197
- }
198
-
199
- /**
200
- * Check if current user is allowed to manage post
201
- *
202
- * @param string $cap
203
- * @param int $id
204
- * @param array $allcaps
205
- * @param array $metacaps
206
- *
207
- * @return array
208
- *
209
- * @access protected
210
- */
211
- protected function isAllowedToManagerPost($cap, $id, $allcaps, $metacaps) {
212
- if ($cap == 'edit_post') {
213
- $object = AAM::getUser()->getObject('post', $id);
214
- $draft = $object->post_status == 'auto-draft';
215
-
216
- if (!$draft && !$this->isAllowed('backend.edit', $object)) {
217
- $allcaps = $this->restrictCapabilities($allcaps, $metacaps);
218
- }
219
- } elseif ($cap == 'delete_post') {
220
- $object = AAM::getUser()->getObject('post', $id);
221
- if (!$this->isAllowed('backend.delete', $object)) {
222
- $allcaps = $this->restrictCapabilities($allcaps, $metacaps);
223
- }
224
- }
225
-
226
- return $allcaps;
227
- }
228
-
229
  /**
230
  * Check if action is allowed
231
  *
@@ -246,28 +148,6 @@ class AAM_Backend_Authorization {
246
  return ($edit || ($others && !$author)) ? false : true;
247
  }
248
 
249
- /**
250
- * Restrict user capabilities
251
- *
252
- * Iterate through the list of meta capabilities and disable them in the
253
- * list of all user capabilities. Keep in mind that this disable caps only
254
- * for one time call.
255
- *
256
- * @param array $allCaps
257
- * @param array $metaCaps
258
- *
259
- * @return array
260
- *
261
- * @access protected
262
- */
263
- protected function restrictCapabilities($allCaps, $metaCaps) {
264
- foreach($metaCaps as $cap) {
265
- $allCaps[$cap] = false;
266
- }
267
-
268
- return $allCaps;
269
- }
270
-
271
  /**
272
  * Alias for the bootstrap
273
  *
37
  add_action('admin_init', array($this, 'checkScreenAccess'));
38
  }
39
 
 
 
 
40
  //post access
41
  add_action('admin_action_edit', array($this, 'checkEditAccess'));
42
  }
77
  }
78
  }
79
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
80
  /**
81
  * Control Edit Post
82
  *
128
  return $post;
129
  }
130
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  /**
132
  * Check if action is allowed
133
  *
148
  return ($edit || ($others && !$author)) ? false : true;
149
  }
150
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
151
  /**
152
  * Alias for the bootstrap
153
  *
Application/Backend/Feature/Main/Post.php CHANGED
@@ -433,18 +433,18 @@ class AAM_Backend_Feature_Main_Post extends AAM_Backend_Feature_Abstract {
433
  $param = AAM_Core_Request::post('param');
434
  $value = AAM_Core_Request::post('value');
435
 
436
- if (strpos($param, 'frontend.expire_datetime') !== false) {
437
  $value = date('Y-m-d H:i:s', strtotime($value));
438
  }
439
 
440
  //clear cache
441
- AAM_Core_Cache::clear();
442
 
443
  $result = $subject->save($param, $value, $object, $id);
444
 
445
  return json_encode(array(
446
- 'status' => ($result ? 'success' : 'failure'),
447
- 'value' => $value,
448
  'preview' => $this->getPreviewValue($param, $value)
449
  ));
450
  }
@@ -464,7 +464,7 @@ class AAM_Backend_Feature_Main_Post extends AAM_Backend_Feature_Abstract {
464
  if ($object instanceof AAM_Core_Object) {
465
  $result = $object->reset();
466
  //clear cache
467
- AAM_Core_Cache::clear();
468
  } else {
469
  $result = false;
470
  }
@@ -513,6 +513,22 @@ class AAM_Backend_Feature_Main_Post extends AAM_Backend_Feature_Abstract {
513
  return $filtered;
514
  }
515
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
516
  /**
517
  *
518
  * @return type
@@ -546,7 +562,7 @@ class AAM_Backend_Feature_Main_Post extends AAM_Backend_Feature_Abstract {
546
  AAM_Backend_Feature::registerFeature((object) array(
547
  'uid' => 'post',
548
  'position' => 20,
549
- 'title' => __('Posts & Pages', AAM_KEY),
550
  'capability' => 'aam_manage_posts',
551
  'type' => 'main',
552
  'subjects' => array(
433
  $param = AAM_Core_Request::post('param');
434
  $value = AAM_Core_Request::post('value');
435
 
436
+ if (strpos($param, '.expire_datetime') !== false) {
437
  $value = date('Y-m-d H:i:s', strtotime($value));
438
  }
439
 
440
  //clear cache
441
+ AAM_Core_API::clearCache();
442
 
443
  $result = $subject->save($param, $value, $object, $id);
444
 
445
  return json_encode(array(
446
+ 'status' => ($result ? 'success' : 'failure'),
447
+ 'value' => $value,
448
  'preview' => $this->getPreviewValue($param, $value)
449
  ));
450
  }
464
  if ($object instanceof AAM_Core_Object) {
465
  $result = $object->reset();
466
  //clear cache
467
+ AAM_Core_API::clearCache();
468
  } else {
469
  $result = false;
470
  }
513
  return $filtered;
514
  }
515
 
516
+ /**
517
+ *
518
+ * @param type $renderBackButton
519
+ * @param type $extraClass
520
+ */
521
+ public static function renderAccessForm() {
522
+ ob_start();
523
+ require_once(
524
+ AAM_BASEDIR . '/Application/Backend/phtml/partial/post-access-form.phtml'
525
+ );
526
+ $content = ob_get_contents();
527
+ ob_end_clean();
528
+
529
+ return $content;
530
+ }
531
+
532
  /**
533
  *
534
  * @return type
562
  AAM_Backend_Feature::registerFeature((object) array(
563
  'uid' => 'post',
564
  'position' => 20,
565
+ 'title' => __('Posts & Terms', AAM_KEY),
566
  'capability' => 'aam_manage_posts',
567
  'type' => 'main',
568
  'subjects' => array(
Application/Backend/Feature/Settings/Core.php CHANGED
@@ -43,6 +43,11 @@ class AAM_Backend_Feature_Settings_Core extends AAM_Backend_Feature_Abstract {
43
  'descr' => __('Allow AAM to manage access to frontend resources. If there is no need to manage access to the website frontend then keep this option unchecked as it may increase your webiste performance.', AAM_KEY),
44
  'value' => AAM_Core_Config::get('frontend-access-control', true)
45
  ),
 
 
 
 
 
46
  'render-access-metabox' => array(
47
  'title' => __('Render Access Manager Metabox', AAM_KEY),
48
  'descr' => __('Render Access Manager metabox on all post and category edit pages. Access Manager metabox is the quick way to manage access to any post or category without leaving an edit page.', AAM_KEY),
@@ -70,7 +75,7 @@ class AAM_Backend_Feature_Settings_Core extends AAM_Backend_Feature_Abstract {
70
  ),
71
  'jwt-authentication' => array(
72
  'title' => __('JWT Authentication', AAM_KEY),
73
- 'descr' => sprintf(AAM_Backend_View_Helper::preparePhrase('[Note!] PHP 5.4 or higher is required for this feature. Enable the ability to authenticate user with WordPress RESTfull API and JWT token. For more information, check %sHow to authenticate WordPress user with JWT token%s article', 'b'), '<a href="https://aamplugin.com/help/how-to-authenticate-wordpress-user-with-jwt-token">', '</a>'),
74
  'value' => AAM_Core_Config::get('jwt-authentication', false)
75
  )
76
  );
43
  'descr' => __('Allow AAM to manage access to frontend resources. If there is no need to manage access to the website frontend then keep this option unchecked as it may increase your webiste performance.', AAM_KEY),
44
  'value' => AAM_Core_Config::get('frontend-access-control', true)
45
  ),
46
+ 'api-access-control' => array(
47
+ 'title' => __('API Access Control', AAM_KEY),
48
+ 'descr' => __('Allow AAM to manage access to the website resources that are invoked with WordPress core API (currently only for RESTful API). If there is no need to manage access to the website API then keep this option unchecked as it may increase your webiste performance.', AAM_KEY),
49
+ 'value' => AAM_Core_Config::get('api-access-control', true)
50
+ ),
51
  'render-access-metabox' => array(
52
  'title' => __('Render Access Manager Metabox', AAM_KEY),
53
  'descr' => __('Render Access Manager metabox on all post and category edit pages. Access Manager metabox is the quick way to manage access to any post or category without leaving an edit page.', AAM_KEY),
75
  ),
76
  'jwt-authentication' => array(
77
  'title' => __('JWT Authentication', AAM_KEY),
78
+ 'descr' => sprintf(AAM_Backend_View_Helper::preparePhrase('[Note!] PHP 5.4 or higher is required for this feature. Enable the ability to authenticate user with WordPress RESTful API and JWT token. For more information, check %sHow to authenticate WordPress user with JWT token%s article', 'b'), '<a href="https://aamplugin.com/help/how-to-authenticate-wordpress-user-with-jwt-token">', '</a>'),
79
  'value' => AAM_Core_Config::get('jwt-authentication', false)
80
  )
81
  );
Application/Backend/Feature/Settings/Tools.php CHANGED
@@ -74,6 +74,8 @@ class AAM_Backend_Feature_Settings_Tools extends AAM_Backend_Feature_Abstract {
74
 
75
  $mquery = "DELETE FROM {$wpdb->usermeta} WHERE `meta_key` LIKE %s";
76
  $wpdb->query($wpdb->prepare($mquery, $wpdb->prefix . 'aam%'));
 
 
77
 
78
  return json_encode(array('status' => 'success'));
79
  }
@@ -83,7 +85,7 @@ class AAM_Backend_Feature_Settings_Tools extends AAM_Backend_Feature_Abstract {
83
  * @return type
84
  */
85
  public function clearCache() {
86
- AAM_Core_Cache::clear();
87
 
88
  return json_encode(array('status' => 'success'));
89
  }
74
 
75
  $mquery = "DELETE FROM {$wpdb->usermeta} WHERE `meta_key` LIKE %s";
76
  $wpdb->query($wpdb->prepare($mquery, $wpdb->prefix . 'aam%'));
77
+
78
+ $this->clearCache();
79
 
80
  return json_encode(array('status' => 'success'));
81
  }
85
  * @return type
86
  */
87
  public function clearCache() {
88
+ AAM_Core_API::clearCache();
89
 
90
  return json_encode(array('status' => 'success'));
91
  }
Application/Backend/Feature/Subject/User.php CHANGED
@@ -66,11 +66,12 @@ class AAM_Backend_Feature_Subject_User {
66
  $userId = filter_input(INPUT_POST, 'user');
67
  $expires = filter_input(INPUT_POST, 'expires');
68
  $action = filter_input(INPUT_POST, 'after');
 
69
 
70
  if (current_user_can('edit_users')) {
71
  if ($userId != get_current_user_id()) {
72
  if ($this->isAllowed(new AAM_Core_Subject_User($userId))) {
73
- $this->updateUserExpiration($userId, $expires, $action);
74
  $response['status'] = 'success';
75
  }
76
  } else {
@@ -217,17 +218,18 @@ class AAM_Backend_Feature_Subject_User {
217
  * @param int $user
218
  * @param string $expires
219
  * @param string $action
 
220
  *
221
  * @return bool
222
  *
223
  * @access protected
224
  */
225
- protected function updateUserExpiration($user, $expires, $action) {
226
  if (trim($expires)) {
227
  update_user_meta(
228
  $user,
229
  'aam_user_expiration',
230
- date('Y-m-d H:i:s', strtotime($expires)) . "|" . ($action ? $action : 'delete')
231
  );
232
  } else {
233
  delete_user_meta($user, 'aam_user_expiration');
66
  $userId = filter_input(INPUT_POST, 'user');
67
  $expires = filter_input(INPUT_POST, 'expires');
68
  $action = filter_input(INPUT_POST, 'after');
69
+ $role = filter_input(INPUT_POST, 'role');
70
 
71
  if (current_user_can('edit_users')) {
72
  if ($userId != get_current_user_id()) {
73
  if ($this->isAllowed(new AAM_Core_Subject_User($userId))) {
74
+ $this->updateUserExpiration($userId, $expires, $action, $role);
75
  $response['status'] = 'success';
76
  }
77
  } else {
218
  * @param int $user
219
  * @param string $expires
220
  * @param string $action
221
+ * @param string $role
222
  *
223
  * @return bool
224
  *
225
  * @access protected
226
  */
227
+ protected function updateUserExpiration($user, $expires, $action, $role = '') {
228
  if (trim($expires)) {
229
  update_user_meta(
230
  $user,
231
  'aam_user_expiration',
232
+ date('Y-m-d H:i:s', strtotime($expires)) . "|" . ($action ? $action : 'delete') . '|' . $role
233
  );
234
  } else {
235
  delete_user_meta($user, 'aam_user_expiration');
Application/Backend/Filter.php CHANGED
@@ -61,8 +61,6 @@ class AAM_Backend_Filter {
61
  //add post filter for LIST restriction
62
  if (!AAM::isAAM() && AAM_Core_Config::get('check-post-visibility', true)) {
63
  add_filter('found_posts', array($this, 'filterPostCount'), 999, 2);
64
- add_filter('posts_fields_request', array($this, 'fieldsRequest'), 999, 2);
65
- add_action('pre_get_posts', array($this, 'preparePostQuery'), 999);
66
  }
67
 
68
  add_action('pre_post_update', array($this, 'prePostUpdate'), 10, 2);
@@ -74,6 +72,17 @@ class AAM_Backend_Filter {
74
  add_filter('views_users', array($this, 'filterViews'));
75
  }
76
 
 
 
 
 
 
 
 
 
 
 
 
77
  AAM_Backend_Authorization::bootstrap(); //bootstrap backend authorization
78
  }
79
 
@@ -288,6 +297,7 @@ class AAM_Backend_Filter {
288
  */
289
  public function filterPostCount($counter, $query) {
290
  $filtered = array();
 
291
 
292
  foreach ($query->posts as $post) {
293
  if (isset($post->post_type)) {
@@ -296,9 +306,14 @@ class AAM_Backend_Filter {
296
  $type = AAM_Core_API::getQueryPostType($query);
297
  }
298
 
299
- $object = (is_scalar($post) ? get_post($post) : $post);
 
 
 
 
 
300
 
301
- if (!AAM_Core_API::isHiddenPost($object, $type, 'backend')) {
302
  $filtered[] = $post;
303
  } else {
304
  $counter--;
@@ -311,68 +326,6 @@ class AAM_Backend_Filter {
311
  return $counter;
312
  }
313
 
314
- /**
315
- * Filter pages fields
316
- *
317
- * @param string $fields
318
- * @param WP_Query $query
319
- *
320
- * @return string
321
- *
322
- * @access public
323
- * @global WPDB $wpdb
324
- */
325
- public function fieldsRequest($fields, $query) {
326
- global $wpdb;
327
-
328
- $qfields = (isset($query->query['fields']) ? $query->query['fields'] : '');
329
-
330
- if ($qfields == 'id=>parent') {
331
- $author = "{$wpdb->posts}.post_author";
332
- if (strpos($fields, $author) === false) {
333
- $fields .= ", $author";
334
- }
335
-
336
- $status = "{$wpdb->posts}.post_status";
337
- if (strpos($fields, $status) === false) {
338
- $fields .= ", $status";
339
- }
340
-
341
- $type = "{$wpdb->posts}.post_type";
342
- if (strpos($fields, $type) === false) {
343
- $fields .= ", $type";
344
- }
345
- }
346
-
347
- return $fields;
348
- }
349
-
350
- /**
351
- * Prepare pre post query
352
- *
353
- * @param WP_Query $query
354
- *
355
- * @return void
356
- *
357
- * @access public
358
- */
359
- public function preparePostQuery($query) {
360
- if ($this->skip === false) {
361
- $this->skip = true;
362
- $filtered = AAM_Core_API::getFilteredPostList($query, 'backend');
363
- $this->skip = false;
364
-
365
- if (isset($query->query_vars['post__not_in'])
366
- && is_array($query->query_vars['post__not_in'])) {
367
- $query->query_vars['post__not_in'] = array_merge(
368
- $query->query_vars['post__not_in'], $filtered
369
- );
370
- } else {
371
- $query->query_vars['post__not_in'] = $filtered;
372
- }
373
- }
374
- }
375
-
376
  /**
377
  * Post update hook
378
  *
@@ -389,7 +342,7 @@ class AAM_Backend_Filter {
389
  $post = get_post($id);
390
 
391
  if ($post->post_author != $data['post_author']) {
392
- AAM_Core_Cache::clear($id);
393
  }
394
  }
395
 
61
  //add post filter for LIST restriction
62
  if (!AAM::isAAM() && AAM_Core_Config::get('check-post-visibility', true)) {
63
  add_filter('found_posts', array($this, 'filterPostCount'), 999, 2);
 
 
64
  }
65
 
66
  add_action('pre_post_update', array($this, 'prePostUpdate'), 10, 2);
72
  add_filter('views_users', array($this, 'filterViews'));
73
  }
74
 
75
+ // Check if user has ability to perform certain task based on provided
76
+ // capability and meta data
77
+ if (AAM_Core_Config::get('backend-access-control', true)) {
78
+ add_filter(
79
+ 'user_has_cap',
80
+ array(AAM_Shared_Manager::getInstance(), 'userHasCap'),
81
+ 999,
82
+ 3
83
+ );
84
+ }
85
+
86
  AAM_Backend_Authorization::bootstrap(); //bootstrap backend authorization
87
  }
88
 
297
  */
298
  public function filterPostCount($counter, $query) {
299
  $filtered = array();
300
+ $subject = AAM::getUser();
301
 
302
  foreach ($query->posts as $post) {
303
  if (isset($post->post_type)) {
306
  $type = AAM_Core_API::getQueryPostType($query);
307
  }
308
 
309
+ $object = $subject->getObject(
310
+ 'post', (is_a($post, 'WP_Post') ? $post->ID : $post)
311
+ );
312
+
313
+ $hidden = $object->get('backend.hidden');
314
+ $list = $object->get('backend.list');
315
 
316
+ if (empty($hidden) && empty($list)) {
317
  $filtered[] = $post;
318
  } else {
319
  $counter--;
326
  return $counter;
327
  }
328
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
329
  /**
330
  * Post update hook
331
  *
342
  $post = get_post($id);
343
 
344
  if ($post->post_author != $data['post_author']) {
345
+ AAM_Core_API::clearCache();
346
  }
347
  }
348
 
Application/Backend/Manager.php CHANGED
@@ -38,6 +38,9 @@ class AAM_Backend_Manager {
38
  //check if user switch is required
39
  $this->checkUserSwitch();
40
 
 
 
 
41
  //print required JS & CSS
42
  add_action('admin_print_scripts', array($this, 'printJavascript'));
43
  add_action('admin_print_styles', array($this, 'printStylesheet'));
@@ -154,7 +157,7 @@ class AAM_Backend_Manager {
154
 
155
  //role changed?
156
  if (implode('', $user->roles) != implode('', $old->roles)) {
157
- AAM_Core_Cache::clear($id);
158
 
159
  //check if role has expiration data set
160
  $role = (is_array($user->roles) ? $user->roles[0] : '');
38
  //check if user switch is required
39
  $this->checkUserSwitch();
40
 
41
+ //cache clearing hook
42
+ add_action('aam-clear-cache-action', 'AAM_Core_API::clearCache');
43
+
44
  //print required JS & CSS
45
  add_action('admin_print_scripts', array($this, 'printJavascript'));
46
  add_action('admin_print_styles', array($this, 'printStylesheet'));
157
 
158
  //role changed?
159
  if (implode('', $user->roles) != implode('', $old->roles)) {
160
+ AAM_Core_API::clearCache(new AAM_Core_Subject_User($id));
161
 
162
  //check if role has expiration data set
163
  $role = (is_array($user->roles) ? $user->roles[0] : '');
Application/Backend/View.php CHANGED
@@ -77,7 +77,7 @@ class AAM_Backend_View {
77
  */
78
  public function renderAccessFrame() {
79
  ob_start();
80
- require_once(dirname(__FILE__) . '/phtml/frame.phtml');
81
  $content = ob_get_contents();
82
  ob_end_clean();
83
 
@@ -91,7 +91,7 @@ class AAM_Backend_View {
91
  */
92
  public function renderPostMetabox($post) {
93
  ob_start();
94
- require_once(dirname(__FILE__) . '/phtml/post-metabox.phtml');
95
  $content = ob_get_contents();
96
  ob_end_clean();
97
 
@@ -105,7 +105,7 @@ class AAM_Backend_View {
105
  */
106
  public function renderTermMetabox($term) {
107
  ob_start();
108
- require_once(dirname(__FILE__) . '/phtml/term-metabox.phtml');
109
  $content = ob_get_contents();
110
  ob_end_clean();
111
 
@@ -156,15 +156,21 @@ class AAM_Backend_View {
156
  * @access public
157
  */
158
  public function renderContent($type = 'main') {
159
- ob_start();
160
- if ($type == 'extensions') {
161
- AAM_Backend_Feature_Extension_Manager::getInstance()->render();
162
- } else {
163
- require_once(dirname(__FILE__) . '/phtml/main-panel.phtml');
 
 
 
 
 
 
 
 
164
  }
165
- $content = ob_get_contents();
166
- ob_end_clean();
167
-
168
  return $content;
169
  }
170
 
77
  */
78
  public function renderAccessFrame() {
79
  ob_start();
80
+ require_once(dirname(__FILE__) . '/phtml/metabox/metabox-content.phtml');
81
  $content = ob_get_contents();
82
  ob_end_clean();
83
 
91
  */
92
  public function renderPostMetabox($post) {
93
  ob_start();
94
+ require_once(dirname(__FILE__) . '/phtml/metabox/post-metabox.phtml');
95
  $content = ob_get_contents();
96
  ob_end_clean();
97
 
105
  */
106
  public function renderTermMetabox($term) {
107
  ob_start();
108
+ require_once(dirname(__FILE__) . '/phtml/metabox/term-metabox.phtml');
109
  $content = ob_get_contents();
110
  ob_end_clean();
111
 
156
  * @access public
157
  */
158
  public function renderContent($type = 'main') {
159
+ $content = apply_filters('aam-ui-content-filter', null, $type);
160
+
161
+ if (is_null($content)) {
162
+ ob_start();
163
+ if ($type == 'extensions') {
164
+ AAM_Backend_Feature_Extension_Manager::getInstance()->render();
165
+ } elseif ($type == 'postform') {
166
+ echo AAM_Backend_Feature_Main_Post::renderAccessForm();
167
+ } else {
168
+ require_once(dirname(__FILE__) . '/phtml/main-panel.phtml');
169
+ }
170
+ $content = ob_get_contents();
171
+ ob_end_clean();
172
  }
173
+
 
 
174
  return $content;
175
  }
176
 
Application/Backend/View/PostOptionList.php CHANGED
@@ -24,85 +24,149 @@ class AAM_Backend_View_PostOptionList {
24
  'frontend' => array(
25
  'list' => array(
26
  'title' => __('List', AAM_KEY),
27
- 'descr' => __('Hide %s however access with a direct URL will be still allowed. When there are more than 500 posts, this option may not be applied immediately because, for performance reasons, AAM checks limited number of posts per request.', AAM_KEY) . sprintf(__(' %sSee in action.%s', AAM_KEY), "<a href='https://youtu.be/2jiu_CL6JJg' target='_blank'>", '</a>'),
28
  'config' => 'check-post-visibility'
29
  ),
30
  'read' => array(
31
  'title' => __('Read', AAM_KEY),
32
- 'descr' => __('Restrict access to read the %s. Any attempts to read, view or open the %s will be denied and redirected based on the Access Denied Redirect rule.', AAM_KEY) . sprintf(__(' %sSee in action.%s', AAM_KEY), "<a href='https://youtu.be/1742nVeGvgs' target='_blank'>", '</a>')
33
  ),
34
  'limit' => array(
35
- 'title' => __('Limit', AAM_KEY),
36
- 'sub' => __('Teaser message', AAM_KEY),
37
- 'option' => 'frontend.teaser',
38
  'preview' => 'frontend-teaser-preview',
39
- 'descr' => __('When checked, show defined teaser message instead of the %s content.', AAM_KEY)
 
40
  ),
41
  'access_counter' => array(
42
- 'title' => __('Read Counter', AAM_KEY),
43
- 'sub' => __('Threshold', AAM_KEY),
44
- 'option' => 'frontend.access_counter_limit',
45
  'preview' => 'frontend-access_counter_limit-preview',
 
46
  'exclude' => array(AAM_Core_Subject_Visitor::UID),
47
- 'descr' => __('Define how many times the %s can be opened to read, view or download. After number of time exceeds the defined threshold, the access will be denied to the %s and redirected based on the Access Denied Redirect rule.', AAM_KEY)
48
  ),
49
  'comment' => array(
50
  'title' => __('Comment', AAM_KEY),
51
- 'descr' => __('Restrict access to comment on %s when commenting feature is enabled.', AAM_KEY)
52
  ),
53
- 'redirect' => array(
54
- 'title' => __('Redirect', AAM_KEY),
55
- 'sub' => __('Redirect Rule', AAM_KEY),
56
- 'option' => 'frontend.location',
57
  'preview' => 'frontend-location-preview',
58
- 'descr' => sprintf(__('Redirect user based on the defined redirect rule when user tries to read the %s. The REDIRECT option will be ignored if READ option checked. For more information about this option please refer to the %sHelp Section%s.', AAM_KEY), '%s', '<a href="https://aamplugin.com/help#post-redirect" target="_blank">', '</a>')
 
59
  ),
60
- 'protected' => array(
61
- 'title' => __('Password Protected', AAM_KEY),
62
- 'sub' => __('Password', AAM_KEY),
63
- 'option' => 'frontend.password',
64
  'preview' => 'frontend-option-preview',
65
- 'descr' => __('Password protect the %s. Available with WordPress 4.7.0 or higher.', AAM_KEY)
 
66
  ),
67
  'expire' => array(
68
- 'title' => __('Access Expiration', AAM_KEY),
69
- 'sub' => __('Expires', AAM_KEY),
70
- 'option' => 'frontend.expire_datetime',
71
  'preview' => 'frontend-expire_datetime-preview',
72
- 'descr' => __('Define when access expires for %s.', AAM_KEY) . sprintf(__('After expiration, the access to %s will be denied and user will be redirected based on the Access Denied Redirect rule. For more information %scheck this article%s or ', AAM_KEY), '%s', "<a href='https://aamplugin.com/help/how-to-set-expiration-date-for-any-wordpress-content' target='_blank'>", '</a>') . sprintf(__(' %ssee in action.%s', AAM_KEY), "<a href='https://youtu.be/IgtgVoWs35w' target='_blank'>", '</a>')
 
73
  ),
74
  'monetize' => array(
75
- 'title' => __('Monetized Access', AAM_KEY),
76
- 'sub' => __('E-Product', AAM_KEY),
77
- 'option' => 'frontend.eproduct',
78
  'preview' => 'frontend-eproduct-preview',
 
79
  'exclude' => array(AAM_Core_Subject_Visitor::UID),
80
- 'descr' => sprintf(AAM_Backend_View_Helper::preparePhrase('[Premium feature!] Start selling access to the %s. Access will be granted to read, view or download %s only if selected E-Product had been purchased. For more information %scheck this article%s.', 'b'), '%s', '%s', "<a href='https://aamplugin.com/help/how-to-monetize-access-to-the-wordpress-content' target='_blank'>", '</a>')
81
- ),
82
  ),
83
  'backend' => array(
84
  'list' => array(
85
- 'title' => __('List', AAM_KEY),
86
  'exclude' => array(AAM_Core_Subject_Visitor::UID),
87
- 'descr' => __('Hide %s however access with a direct URL is still allowed. When there are more than 500 posts, this option may not be applied immediately because, for performance reasons, AAM checks limited number of posts per request.', AAM_KEY),
88
- 'config' => 'check-post-visibility'
89
  ),
90
  'edit' => array(
91
- 'title' => __('Edit', AAM_KEY),
92
  'exclude' => array(AAM_Core_Subject_Visitor::UID),
93
- 'descr' => __('Restrict access to edit the %s. Any attempts to edit %s will result in redirecting user based on the Access Denied Redirect rule.', AAM_KEY)
94
  ),
95
  'delete' => array(
96
- 'title' => __('Delete', AAM_KEY),
97
  'exclude' => array(AAM_Core_Subject_Visitor::UID),
98
- 'descr' => __('Restrict access to trash or permanently delete %s.', AAM_KEY)
99
  ),
100
  'publish' => array(
101
- 'title' => __('Publish', AAM_KEY),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  'exclude' => array(AAM_Core_Subject_Visitor::UID),
103
- 'descr' => __('Restrict access to publish the %s. User will be allowed only submit the %s for review.', AAM_KEY)
104
  )
105
  )
106
  );
107
  }
108
- }
24
  'frontend' => array(
25
  'list' => array(
26
  'title' => __('List', AAM_KEY),
27
+ 'descr' => __('Hide %s however still allow access with direct URL.', AAM_KEY) . sprintf(__(' %sSee in action.%s', AAM_KEY), "<a href='https://youtu.be/2jiu_CL6JJg' target='_blank'>", '</a>'),
28
  'config' => 'check-post-visibility'
29
  ),
30
  'read' => array(
31
  'title' => __('Read', AAM_KEY),
32
+ 'descr' => __('Restrict access to view, read or download %s. Any attempts to open %s will be denied and redirected based on the Access Denied Redirect rule.', AAM_KEY) . sprintf(__(' %sSee in action.%s', AAM_KEY), "<a href='https://youtu.be/1742nVeGvgs' target='_blank'>", '</a>')
33
  ),
34
  'limit' => array(
35
+ 'title' => __('Limit', AAM_KEY),
36
+ 'sub' => __('Teaser message', AAM_KEY),
37
+ 'option' => 'frontend.teaser',
38
  'preview' => 'frontend-teaser-preview',
39
+ 'modal' => 'modal-teaser',
40
+ 'descr' => __('Replace %s content with defined teaser message.', AAM_KEY)
41
  ),
42
  'access_counter' => array(
43
+ 'title' => __('Read Counter', AAM_KEY),
44
+ 'sub' => __('Threshold', AAM_KEY),
45
+ 'option' => 'frontend.access_counter_limit',
46
  'preview' => 'frontend-access_counter_limit-preview',
47
+ 'modal' => 'modal-access-counter',
48
  'exclude' => array(AAM_Core_Subject_Visitor::UID),
49
+ 'descr' => __('Define how many times %s can be read, viewed or download. After number of times exceeds the specified threshold, access will be denied and redirected based on the Access Denied Redirect rule.', AAM_KEY)
50
  ),
51
  'comment' => array(
52
  'title' => __('Comment', AAM_KEY),
53
+ 'descr' => __('Restrict access to comment on %s if commenting is allowed.', AAM_KEY)
54
  ),
55
+ 'redirect' => array(
56
+ 'title' => __('Redirect', AAM_KEY),
57
+ 'sub' => __('Redirect Rule', AAM_KEY),
58
+ 'option' => 'frontend.location',
59
  'preview' => 'frontend-location-preview',
60
+ 'modal' => 'modal-redirect',
61
+ 'descr' => __('Redirect user based on the defined redirect rule when user tries to read the %s. The REDIRECT option will be ignored if READ option is checked.', AAM_KEY),
62
  ),
63
+ 'protected' => array(
64
+ 'title' => __('Password Protected', AAM_KEY),
65
+ 'sub' => __('Password', AAM_KEY),
66
+ 'option' => 'frontend.password',
67
  'preview' => 'frontend-option-preview',
68
+ 'modal' => 'modal-password',
69
+ 'descr' => __('Protect access to %s with password. Available with WordPress 4.7.0 or higher.', AAM_KEY)
70
  ),
71
  'expire' => array(
72
+ 'title' => __('Access Expiration', AAM_KEY),
73
+ 'sub' => __('Expires', AAM_KEY),
74
+ 'option' => 'frontend.expire_datetime',
75
  'preview' => 'frontend-expire_datetime-preview',
76
+ 'modal' => 'modal-access-expires',
77
+ 'descr' => __('Define when access will expire for %s.', AAM_KEY) . sprintf(__('After expiration, the access to %s will be denied and redirected based on the Access Denied Redirect rule. For more information %scheck this article%s or ', AAM_KEY), '%s', "<a href='https://aamplugin.com/help/how-to-set-expiration-date-for-any-wordpress-content' target='_blank'>", '</a>') . sprintf(__(' %ssee in action.%s', AAM_KEY), "<a href='https://youtu.be/IgtgVoWs35w' target='_blank'>", '</a>')
78
  ),
79
  'monetize' => array(
80
+ 'title' => __('Monetized Access', AAM_KEY),
81
+ 'sub' => __('E-Product', AAM_KEY),
82
+ 'option' => 'frontend.eproduct',
83
  'preview' => 'frontend-eproduct-preview',
84
+ 'modal' => 'modal-eproduct',
85
  'exclude' => array(AAM_Core_Subject_Visitor::UID),
86
+ 'descr' => sprintf(AAM_Backend_View_Helper::preparePhrase('[Premium feature!] Start selling access to %s. Access will be granted to open %s only if selected E-Product had been purchased. For more information %scheck this article%s.', 'b'), '%s', '%s', "<a href='https://aamplugin.com/help/how-to-monetize-access-to-the-wordpress-content' target='_blank'>", '</a>')
87
+ )
88
  ),
89
  'backend' => array(
90
  'list' => array(
91
+ 'title' => __('List', AAM_KEY),
92
  'exclude' => array(AAM_Core_Subject_Visitor::UID),
93
+ 'descr' => __('Hide %s however still allow access with direct URL.', AAM_KEY),
94
+ 'config' => 'check-post-visibility'
95
  ),
96
  'edit' => array(
97
+ 'title' => __('Edit', AAM_KEY),
98
  'exclude' => array(AAM_Core_Subject_Visitor::UID),
99
+ 'descr' => __('Restrict access to edit %s. Any attempts to edit %s will result in redirecting user based on the Access Denied Redirect rule.', AAM_KEY)
100
  ),
101
  'delete' => array(
102
+ 'title' => __('Delete', AAM_KEY),
103
  'exclude' => array(AAM_Core_Subject_Visitor::UID),
104
+ 'descr' => __('Restrict access to trash or permanently delete %s.', AAM_KEY)
105
  ),
106
  'publish' => array(
107
+ 'title' => __('Publish', AAM_KEY),
108
+ 'exclude' => array(AAM_Core_Subject_Visitor::UID),
109
+ 'descr' => __('Restrict access to publish %s. User will be allowed only to submit %s for review.', AAM_KEY)
110
+ )
111
+ ),
112
+ 'api' => array(
113
+ 'list' => array(
114
+ 'title' => __('List', AAM_KEY),
115
+ 'descr' => __('Hide %s however still allow access to retrieve %s.', AAM_KEY),
116
+ 'config' => 'check-post-visibility'
117
+ ),
118
+ 'read' => array(
119
+ 'title' => __('Read', AAM_KEY),
120
+ 'descr' => __('Restrict access to retrieve %s. Any attempts to retrieve %s will be denied.', AAM_KEY)
121
+ ),
122
+ 'limit' => array(
123
+ 'title' => __('Limit', AAM_KEY),
124
+ 'sub' => __('Teaser message', AAM_KEY),
125
+ 'option' => 'api.teaser',
126
+ 'preview' => 'api-teaser-preview',
127
+ 'modal' => 'modal-teaser',
128
+ 'descr' => __('Replace %s content with defined teaser message.', AAM_KEY)
129
+ ),
130
+ 'access_counter' => array(
131
+ 'title' => __('Read Counter', AAM_KEY),
132
+ 'sub' => __('Threshold', AAM_KEY),
133
+ 'option' => 'api.access_counter_limit',
134
+ 'preview' => 'api-access_counter_limit-preview',
135
+ 'modal' => 'modal-access-counter',
136
+ 'exclude' => array(AAM_Core_Subject_Visitor::UID),
137
+ 'descr' => __('Define how many times %s can be retrieved. After number of time exceeds the defined threshold, the access will be denied to %s.', AAM_KEY)
138
+ ),
139
+ 'comment' => array(
140
+ 'title' => __('Comment', AAM_KEY),
141
+ 'descr' => __('Restrict access to comment on %s if commenting feature is enabled.', AAM_KEY)
142
+ ),
143
+ 'protected' => array(
144
+ 'title' => __('Password Protected', AAM_KEY),
145
+ 'sub' => __('Password', AAM_KEY),
146
+ 'option' => 'api.password',
147
+ 'preview' => 'api-option-preview',
148
+ 'modal' => 'modal-password',
149
+ 'descr' => __('Protected %s with password. Available with WordPress 4.7.0 or higher.', AAM_KEY)
150
+ ),
151
+ 'expire' => array(
152
+ 'title' => __('Access Expiration', AAM_KEY),
153
+ 'sub' => __('Expires', AAM_KEY),
154
+ 'option' => 'api.expire_datetime',
155
+ 'preview' => 'api-expire_datetime-preview',
156
+ 'modal' => 'modal-access-expires',
157
+ 'descr' => __('Define when access expires to %s.', AAM_KEY) . sprintf(__('After expiration, the access to %s will be denied. For more information %scheck this article%s or ', AAM_KEY), '%s', "<a href='https://aamplugin.com/help/how-to-set-expiration-date-for-any-wordpress-content' target='_blank'>", '</a>')
158
+ ),
159
+ 'edit' => array(
160
+ 'title' => __('Update', AAM_KEY),
161
+ 'exclude' => array(AAM_Core_Subject_Visitor::UID),
162
+ 'descr' => __('Restrict access to update %s. Any attempts to update %s will be denied.', AAM_KEY)
163
+ ),
164
+ 'delete' => array(
165
+ 'title' => __('Delete', AAM_KEY),
166
  'exclude' => array(AAM_Core_Subject_Visitor::UID),
167
+ 'descr' => __('Restrict access to trash or permanently delete %s.', AAM_KEY)
168
  )
169
  )
170
  );
171
  }
172
+ }
Application/Backend/phtml/index.phtml CHANGED
@@ -251,6 +251,13 @@
251
  <option value=""><?php echo __('Select Action', AAM_KEY); ?></option>
252
  <option value="delete"><?php echo __('Delete Account', AAM_KEY); ?></option>
253
  <option value="lock"><?php echo __('Lock Account', AAM_KEY); ?></option>
 
 
 
 
 
 
 
254
  </select>
255
  </div>
256
  </div>
251
  <option value=""><?php echo __('Select Action', AAM_KEY); ?></option>
252
  <option value="delete"><?php echo __('Delete Account', AAM_KEY); ?></option>
253
  <option value="lock"><?php echo __('Lock Account', AAM_KEY); ?></option>
254
+ <option value="change-role"><?php echo __('Change User Role', AAM_KEY); ?></option>
255
+ </select>
256
+ </div>
257
+ <div class="form-group hidden" id="expiration-change-role-holder">
258
+ <label><?php echo __('Change To Role', AAM_KEY); ?></label>
259
+ <select class="form-control" id="expiration-change-role">
260
+ <option value=""><?php echo __('Select Role', AAM_KEY); ?></option>
261
  </select>
262
  </div>
263
  </div>
Application/Backend/phtml/main/menu.phtml CHANGED
@@ -63,19 +63,21 @@
63
  <hr class="aam-divider" />
64
  <?php } ?>
65
 
66
- <div class="row<?php echo (!empty($menu['submenu']) ? ' aam-margin-top-xs' : ''); ?>">
67
- <div class="col-xs-10 col-md-6 col-xs-offset-1 col-md-offset-3">
68
- <?php if ($object->has($menu['id'])) { ?>
69
- <a href="#" class="btn btn-primary btn-sm btn-block aam-restrict-menu" data-menu-id="<?php echo $menu['id']; ?>" data-target="#menu-<?php echo $i; ?>">
70
- <i class="icon-eye"></i> <?php echo __('Show Menu', AAM_KEY); ?>
71
- </a>
72
- <?php } else { ?>
73
- <a href="#" class="btn btn-danger btn-sm btn-block aam-restrict-menu" data-menu-id="<?php echo $menu['id']; ?>" data-target="#menu-<?php echo $i; ?>">
74
- <i class="icon-eye-off"></i> <?php echo __('Restrict Menu', AAM_KEY); ?>
75
- </a>
76
- <?php } ?>
 
 
77
  </div>
78
- </div>
79
  </div>
80
  </div>
81
  </div>
63
  <hr class="aam-divider" />
64
  <?php } ?>
65
 
66
+ <?php if ($menu['id'] != 'menu-index.php') { ?>
67
+ <div class="row<?php echo (!empty($menu['submenu']) ? ' aam-margin-top-xs' : ''); ?>">
68
+ <div class="col-xs-10 col-md-6 col-xs-offset-1 col-md-offset-3">
69
+ <?php if ($object->has($menu['id'])) { ?>
70
+ <a href="#" class="btn btn-primary btn-sm btn-block aam-restrict-menu" data-menu-id="<?php echo $menu['id']; ?>" data-target="#menu-<?php echo $i; ?>">
71
+ <i class="icon-eye"></i> <?php echo __('Show Menu', AAM_KEY); ?>
72
+ </a>
73
+ <?php } else { ?>
74
+ <a href="#" class="btn btn-danger btn-sm btn-block aam-restrict-menu" data-menu-id="<?php echo $menu['id']; ?>" data-target="#menu-<?php echo $i; ?>">
75
+ <i class="icon-eye-off"></i> <?php echo __('Restrict Menu', AAM_KEY); ?>
76
+ </a>
77
+ <?php } ?>
78
+ </div>
79
  </div>
80
+ <?php } ?>
81
  </div>
82
  </div>
83
  </div>
Application/Backend/phtml/main/post.phtml CHANGED
@@ -4,7 +4,7 @@
4
  <div class="row">
5
  <div class="col-xs-12">
6
  <p class="aam-notification">
7
- <?php echo sprintf(AAM_Backend_View_Helper::preparePhrase('You are allowed to manage access to unlimited number of posts, pages or custom post types but only on role, user or visitor levels. Consider to purchase %s[AAM Plus Package]%s extension to have the ability to also manage access to categories and custom taxonomies or to define the default access to all posts, pages or custom post types. For more information about this functionality check %sWhat is a WordPress post%s.', 'b'), '<a href="https://aamplugin.com/help/aam-plus-package-extension" target="_blank">', '</a>', '<a href="https://aamplugin.com/help/what-is-a-wordpress-post" target="_blank">', '</a>'); ?>
8
  </p>
9
  </div>
10
  </div>
@@ -12,7 +12,7 @@
12
  <div class="row">
13
  <div class="col-xs-12">
14
  <p class="aam-info">
15
- <?php echo sprintf(__('Manage access to posts, pages and custom post types. For more information about this functionality check %sHow to manage access to the WordPress content%s article.'), '<a href="https://aamplugin.com/help/how-to-manage-access-to-the-wordpress-content" target="_blank">', '</a>'); ?>
16
  </p>
17
  </div>
18
  </div>
@@ -57,74 +57,27 @@
57
 
58
  <div class="aam-slide-form aam-access-form" data-type="type">
59
  <a href="#" class="btn btn-xs btn-primary post-back btn-right">&Lt; <?php echo __('Go Back', AAM_KEY); ?></a>
 
60
  <?php echo apply_filters('aam-post-type-ui-filter', AAM_Backend_View::getInstance()->loadPartial('post-type.phtml')); ?>
61
  <a href="#" class="btn btn-xs btn-primary post-back">&Lt; <?php echo __('Go Back', AAM_KEY); ?></a>
62
  </div>
63
 
64
  <div class="aam-slide-form aam-access-form" data-type="term">
65
  <a href="#" class="btn btn-xs btn-primary post-back btn-right">&Lt; <?php echo __('Go Back', AAM_KEY); ?></a>
 
66
  <?php echo apply_filters('aam-term-type-ui-filter', AAM_Backend_View::getInstance()->loadPartial('term-type.phtml')); ?>
67
  <a href="#" class="btn btn-xs btn-primary post-back">&Lt; <?php echo __('Go Back', AAM_KEY); ?></a>
68
  </div>
 
 
 
 
69
 
70
  <div class="aam-slide-form aam-access-form" data-type="post">
71
  <a href="#" class="btn btn-xs btn-primary post-back btn-right">&Lt; <?php echo __('Go Back', AAM_KEY); ?></a>
72
- <table class="table table-striped table-bordered">
73
- <tbody>
74
- <?php $frontend = $this->getAccessOptionList('frontend'); ?>
75
- <?php $backend = $this->getAccessOptionList('backend'); ?>
76
-
77
- <?php if (count($frontend) && AAM_Core_Config::get('frontend-access-control', true)) { ?>
78
- <tr>
79
- <td colspan="2" class="aam-table-group">
80
- <i class="icon-doc-text-inv"></i> <strong><?php echo __('Frontend', AAM_KEY); ?></strong>
81
- </td>
82
- </tr>
83
-
84
- <?php foreach($frontend as $option => $data) { ?>
85
- <tr>
86
- <td width="90%">
87
- <strong class="aam-block aam-highlight text-uppercase"><?php echo $data['title']; ?></strong>
88
- <?php if (!empty($data['sub'])) { ?>
89
- <small><?php echo $data['sub']; ?>: <b id="<?php echo $data['preview']; ?>" data-ref="<?php echo $data['option']; ?>" class="option-preview">...</b> <a href="#modal-<?php echo str_replace('.', '-', $data['option']); ?>" data-toggle="modal" class="advanced-post-option" data-ref="<?php echo $data['option']; ?>" data-preview="#<?php echo $data['preview']; ?>"><?php echo __('change', AAM_KEY); ?></a></small>
90
- <?php } ?>
91
- <p class="aam-hint" data-dynamic-post-label="<?php echo $data['descr']; ?>"></p>
92
- </td>
93
- <td>
94
- <div class="aam-row-actions">
95
- <i class="aam-row-action text-muted icon-check-empty" data-property="frontend.<?php echo $option; ?>"></i>
96
- </div>
97
- </td>
98
- </tr>
99
- <?php } ?>
100
- <?php } ?>
101
-
102
- <?php if (count($backend) && AAM_Core_Config::get('backend-access-control', true)) { ?>
103
- <tr class="aam-backend-post-access">
104
- <td colspan="2" class="aam-table-group">
105
- <i class="icon-doc-text-inv"></i> <strong><?php echo __('Backend', AAM_KEY); ?></strong>
106
- </td>
107
- </tr>
108
-
109
- <?php foreach($backend as $option => $data) { ?>
110
- <tr class="aam-backend-post-access">
111
- <td width="90%">
112
- <strong class="aam-block aam-highlight text-uppercase"><?php echo $data['title']; ?></strong>
113
- <?php if (!empty($data['sub'])) { ?>
114
- <small><?php echo $data['sub']; ?>: <b id="<?php echo $data['preview']; ?>" data-ref="<?php echo $data['option']; ?>" class="option-preview">...</b> <a href="#modal-<?php echo str_replace('.', '-', $data['option']); ?>" data-toggle="modal" class="advanced-post-option" data-ref="<?php echo $data['option']; ?>" data-preview="#<?php echo $data['preview']; ?>"><?php echo __('change', AAM_KEY); ?></a></small>
115
- <?php } ?>
116
- <p class="aam-hint" data-dynamic-post-label="<?php echo $data['descr']; ?>"></p>
117
- </td>
118
- <td>
119
- <div class="aam-row-actions">
120
- <i class="aam-row-action text-muted icon-check-empty" data-property="backend.<?php echo $option; ?>"></i>
121
- </div>
122
- </td>
123
- </tr>
124
- <?php } ?>
125
- <?php } ?>
126
- </tbody>
127
- </table>
128
 
129
  <a href="#" class="btn btn-xs btn-primary post-back">&Lt; <?php echo __('Go Back', AAM_KEY); ?></a>
130
  </div>
4
  <div class="row">
5
  <div class="col-xs-12">
6
  <p class="aam-notification">
7
+ <?php echo sprintf(AAM_Backend_View_Helper::preparePhrase('You are allowed to manage access to unlimited number of posts, pages or custom post types but only for any role, user or visitor. Consider to purchase %s[AAM Plus Package]%s extension to have the ability to also manage access to categories and custom taxonomies or to define the default access to all posts, pages or custom post types. For more information about this functionality check %sHow to manage access to the WordPress content%s.', 'b'), '<a href="https://aamplugin.com/help/aam-plus-package-extension" target="_blank">', '</a>', '<a href="https://aamplugin.com/help/how-to-manage-access-to-the-wordpress-content" target="_blank">', '</a>'); ?>
8
  </p>
9
  </div>
10
  </div>
12
  <div class="row">
13
  <div class="col-xs-12">
14
  <p class="aam-info">
15
+ <?php echo sprintf(__('Manage access to posts, pages, custom post types, categories or custom hierarchical taxonomies. For more information about this functionality check %sHow to manage access to the WordPress content%s article.'), '<a href="https://aamplugin.com/help/how-to-manage-access-to-the-wordpress-content" target="_blank">', '</a>'); ?>
16
  </p>
17
  </div>
18
  </div>
57
 
58
  <div class="aam-slide-form aam-access-form" data-type="type">
59
  <a href="#" class="btn btn-xs btn-primary post-back btn-right">&Lt; <?php echo __('Go Back', AAM_KEY); ?></a>
60
+ <span class="aam-clear"></span>
61
  <?php echo apply_filters('aam-post-type-ui-filter', AAM_Backend_View::getInstance()->loadPartial('post-type.phtml')); ?>
62
  <a href="#" class="btn btn-xs btn-primary post-back">&Lt; <?php echo __('Go Back', AAM_KEY); ?></a>
63
  </div>
64
 
65
  <div class="aam-slide-form aam-access-form" data-type="term">
66
  <a href="#" class="btn btn-xs btn-primary post-back btn-right">&Lt; <?php echo __('Go Back', AAM_KEY); ?></a>
67
+ <span class="aam-clear"></span>
68
  <?php echo apply_filters('aam-term-type-ui-filter', AAM_Backend_View::getInstance()->loadPartial('term-type.phtml')); ?>
69
  <a href="#" class="btn btn-xs btn-primary post-back">&Lt; <?php echo __('Go Back', AAM_KEY); ?></a>
70
  </div>
71
+
72
+ <?php $frontendOptions = $this->getAccessOptionList('frontend'); ?>
73
+ <?php $backendOptions = $this->getAccessOptionList('backend'); ?>
74
+ <?php $apiOptions = $this->getAccessOptionList('api'); ?>
75
 
76
  <div class="aam-slide-form aam-access-form" data-type="post">
77
  <a href="#" class="btn btn-xs btn-primary post-back btn-right">&Lt; <?php echo __('Go Back', AAM_KEY); ?></a>
78
+ <span class="aam-clear"></span>
79
+
80
+ <?php echo $this->renderAccessForm(); ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81
 
82
  <a href="#" class="btn btn-xs btn-primary post-back">&Lt; <?php echo __('Go Back', AAM_KEY); ?></a>
83
  </div>
Application/Backend/phtml/{frame.phtml → metabox/metabox-content.phtml} RENAMED
@@ -108,70 +108,17 @@
108
  <?php } ?>
109
 
110
  <div class="aam-access-form" data-type="<?php echo $object->type; ?>">
111
- <?php if ($object->type == 'post') { ?>
112
- <table class="table table-striped table-bordered">
113
- <tbody>
114
- <?php $frontend = AAM_Backend_Feature_Main_Post::getAccessOptionList('frontend'); ?>
115
- <?php $backend = AAM_Backend_Feature_Main_Post::getAccessOptionList('backend'); ?>
116
-
117
- <?php if (count($frontend) && AAM_Core_Config::get('frontend-access-control', true)) { ?>
118
- <tr>
119
- <td colspan="2" class="aam-table-group">
120
- <i class="icon-doc-text-inv"></i> <strong><?php echo __('Frontend', AAM_KEY); ?></strong>
121
- </td>
122
- </tr>
123
-
124
- <?php foreach ($frontend as $option => $data) { ?>
125
- <tr>
126
- <td width="90%">
127
- <strong class="aam-block aam-highlight text-uppercase"><?php echo $data['title']; ?></strong>
128
- <?php if (!empty($data['sub'])) { ?>
129
- <small><?php echo $data['sub']; ?>: <b id="<?php echo $data['preview']; ?>" data-ref="<?php echo $data['option']; ?>" class="option-preview">...</b> <a href="#modal-<?php echo str_replace('.', '-', $data['option']); ?>" data-toggle="modal" class="advanced-post-option" data-ref="<?php echo $data['option']; ?>" data-preview="#<?php echo $data['preview']; ?>"><?php echo __('change', AAM_KEY); ?></a></small>
130
- <?php } ?>
131
- <p class="aam-hint" data-dynamic-post-label="<?php echo $data['descr']; ?>">---</p>
132
- </td>
133
- <td>
134
- <div class="aam-row-actions">
135
- <i class="aam-row-action text-muted icon-check-empty" data-property="frontend.<?php echo $option; ?>"></i>
136
- </div>
137
- </td>
138
- </tr>
139
- <?php } ?>
140
- <?php } ?>
141
-
142
- <?php if (count($backend) && AAM_Core_Config::get('backend-access-control', true)) { ?>
143
- <tr class="aam-backend-post-access">
144
- <td colspan="2" class="aam-table-group">
145
- <i class="icon-doc-text-inv"></i> <strong><?php echo __('Backend', AAM_KEY); ?></strong>
146
- </td>
147
- </tr>
148
-
149
- <?php foreach ($backend as $option => $data) { ?>
150
- <tr class="aam-backend-post-access">
151
- <td width="90%">
152
- <strong class="aam-block aam-highlight text-uppercase"><?php echo $data['title']; ?></strong>
153
- <?php if (!empty($data['sub'])) { ?>
154
- <small><?php echo $data['sub']; ?>: <b id="<?php echo $data['preview']; ?>" data-ref="<?php echo $data['option']; ?>" class="option-preview">...</b> <a href="#modal-<?php echo str_replace('.', '-', $data['option']); ?>" data-toggle="modal" class="advanced-post-option" data-ref="<?php echo $data['option']; ?>" data-preview="#<?php echo $data['preview']; ?>"><?php echo __('change', AAM_KEY); ?></a></small>
155
- <?php } ?>
156
- <p class="aam-hint" data-dynamic-post-label="<?php echo $data['descr']; ?>">---</p>
157
- </td>
158
- <td>
159
- <div class="aam-row-actions">
160
- <i class="aam-row-action text-muted icon-check-empty" data-property="backend.<?php echo $option; ?>"></i>
161
- </div>
162
- </td>
163
- </tr>
164
- <?php } ?>
165
- <?php } ?>
166
- </tbody>
167
- </table>
168
- <?php } else {
169
- echo apply_filters('aam-term-type-ui-filter', AAM_Backend_View::getInstance()->loadPartial('term-type.phtml'));
170
- } ?>
171
  <div class="aam-overlay"></div>
172
  </div>
173
 
174
- <?php require dirname(__FILE__) . '/partial/post-advanced-settings.phtml'; ?>
175
  </div>
176
  </div>
177
 
108
  <?php } ?>
109
 
110
  <div class="aam-access-form" data-type="<?php echo $object->type; ?>">
111
+ <div id="metabox-post-access-form">
112
+ <?php if ($object->type == 'post') { ?>
113
+ <?php echo AAM_Backend_Feature_Main_Post::renderAccessForm(); ?>
114
+ <?php } else {
115
+ echo apply_filters('aam-term-type-ui-filter', AAM_Backend_View::getInstance()->loadPartial('term-type.phtml'));
116
+ } ?>
117
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  <div class="aam-overlay"></div>
119
  </div>
120
 
121
+ <?php require AAM_BASEDIR . '/Application/Backend/phtml/partial/post-advanced-settings.phtml'; ?>
122
  </div>
123
  </div>
124
 
Application/Backend/phtml/{post-metabox.phtml → metabox/post-metabox.phtml} RENAMED
File without changes
Application/Backend/phtml/{term-metabox.phtml → metabox/term-metabox.phtml} RENAMED
@@ -8,7 +8,7 @@
8
  </div>
9
  <?php } else { ?>
10
  <div style="border-left: 4px solid #ffb900; background-color: #FFF1CC; padding: 10px; font-size: 1em; margin: 10px 0px;">
11
- In order to manage access to this category for any user, role or visitors please consider to purchase <strong><a href="<?php echo admin_url('admin.php?page=aam#extension'); ?>" target="_blank">AAM Plus Package</a></strong> extension.
12
  </div>
13
  <?php } ?>
14
  </td>
8
  </div>
9
  <?php } else { ?>
10
  <div style="border-left: 4px solid #ffb900; background-color: #FFF1CC; padding: 10px; font-size: 1em; margin: 10px 0px;">
11
+ In order to manage access to this category for any user, role or visitors please consider to purchase <strong><a href="https://aamplugin.com/extension/plus-package" target="_blank">AAM Plus Package</a></strong> extension for <a href="https://wordpress.org/plugins/advanced-access-manager/" target="_blank">Advanced Access Manager</a> plugin.
12
  </div>
13
  <?php } ?>
14
  </td>
Application/Backend/phtml/partial/post-access-form.phtml ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php if (!defined('AAM_KEY')) { exit; } ?>
2
+
3
+ <?php $frontendOptions = AAM_Backend_Feature_Main_Post::getAccessOptionList('frontend'); ?>
4
+ <?php $backendOptions = AAM_Backend_Feature_Main_Post::getAccessOptionList('backend'); ?>
5
+ <?php $apiOptions = AAM_Backend_Feature_Main_Post::getAccessOptionList('api'); ?>
6
+
7
+ <div class="panel-group" id="post-access-accordion" role="tablist" aria-multiselectable="true">
8
+ <?php if (count($frontendOptions) && AAM_Core_Config::get('frontend-access-control', true)) { ?>
9
+ <div class="panel panel-success">
10
+ <div class="panel-heading" role="tab" id="heading-post-frontend-access-settings">
11
+ <h4 class="panel-title">
12
+ <a role="button" data-toggle="collapse" data-parent="#post-access-accordion" href="#post-frontend-access-settings" aria-expanded="true" aria-controls="post-frontend-access-settings">
13
+ <i class="icon-doc-text-inv"></i> <strong><?php echo __('Frontend Access Settings', AAM_KEY); ?></strong>
14
+ </a>
15
+ </h4>
16
+ </div>
17
+ <div id="post-frontend-access-settings" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="heading-post-frontend-access-settings">
18
+ <div class="panel-body">
19
+ <table class="table table-striped table-bordered">
20
+ <tbody>
21
+ <?php foreach ($frontendOptions as $option => $data) { ?>
22
+ <tr>
23
+ <td width="90%">
24
+ <strong class="aam-block aam-highlight text-uppercase"><?php echo $data['title']; ?></strong>
25
+ <?php if (!empty($data['sub'])) { ?>
26
+ <small><?php echo $data['sub']; ?>: <b id="<?php echo $data['preview']; ?>" data-ref="<?php echo $data['option']; ?>" class="option-preview">...</b> <a href="#<?php echo $data['modal']; ?>" data-toggle="modal" class="advanced-post-option" data-ref="<?php echo $data['option']; ?>" data-preview="#<?php echo $data['preview']; ?>"><?php echo __('change', AAM_KEY); ?></a></small>
27
+ <?php } ?>
28
+ <p class="aam-hint" data-dynamic-post-label="<?php echo $data['descr']; ?>"></p>
29
+ </td>
30
+ <td>
31
+ <div class="aam-row-actions">
32
+ <i class="aam-row-action text-muted icon-check-empty" data-property="frontend.<?php echo $option; ?>"></i>
33
+ </div>
34
+ </td>
35
+ </tr>
36
+ <?php } ?>
37
+ </tbody>
38
+ </table>
39
+ </div>
40
+ </div>
41
+ </div>
42
+ <?php } ?>
43
+
44
+ <?php if (count($backendOptions) && AAM_Core_Config::get('backend-access-control', true)) { ?>
45
+ <div class="panel panel-info">
46
+ <div class="panel-heading" role="tab" id="heading-post-backend-access-settings">
47
+ <h4 class="panel-title">
48
+ <a role="button" data-toggle="collapse" data-parent="#post-access-accordion" href="#post-backend-access-settings" aria-expanded="false" aria-controls="post-backend-access-settings">
49
+ <i class="icon-doc-text-inv"></i> <strong><?php echo __('Backend Access Settings', AAM_KEY); ?></strong>
50
+ </a>
51
+ </h4>
52
+ </div>
53
+ <div id="post-backend-access-settings" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading-post-backend-access-settings">
54
+ <div class="panel-body">
55
+ <table class="table table-striped table-bordered">
56
+ <tbody>
57
+ <?php foreach ($backendOptions as $option => $data) { ?>
58
+ <tr>
59
+ <td width="90%">
60
+ <strong class="aam-block aam-highlight text-uppercase"><?php echo $data['title']; ?></strong>
61
+ <?php if (!empty($data['sub'])) { ?>
62
+ <small><?php echo $data['sub']; ?>: <b id="<?php echo $data['preview']; ?>" data-ref="<?php echo $data['option']; ?>" class="option-preview">...</b> <a href="#modal-<?php echo str_replace('.', '-', $data['option']); ?>" data-toggle="modal" class="advanced-post-option" data-ref="<?php echo $data['option']; ?>" data-preview="#<?php echo $data['preview']; ?>"><?php echo __('change', AAM_KEY); ?></a></small>
63
+ <?php } ?>
64
+ <p class="aam-hint" data-dynamic-post-label="<?php echo $data['descr']; ?>"></p>
65
+ </td>
66
+ <td>
67
+ <div class="aam-row-actions">
68
+ <i class="aam-row-action text-muted icon-check-empty" data-property="backend.<?php echo $option; ?>"></i>
69
+ </div>
70
+ </td>
71
+ </tr>
72
+ <?php } ?>
73
+ </tbody>
74
+ </table>
75
+ </div>
76
+ </div>
77
+ </div>
78
+ <?php } ?>
79
+
80
+ <?php if (count($apiOptions) && AAM_Core_Config::get('api-access-control', true)) { ?>
81
+ <div class="panel panel-warning">
82
+ <div class="panel-heading" role="tab" id="heading-post-api-access-settings">
83
+ <h4 class="panel-title">
84
+ <a role="button" data-toggle="collapse" data-parent="#post-access-accordion" href="#post-api-access-settings" aria-expanded="false" aria-controls="post-backend-access-settings">
85
+ <i class="icon-doc-text-inv"></i> <strong><?php echo __('API Access Settings', AAM_KEY); ?></strong>
86
+ </a>
87
+ </h4>
88
+ </div>
89
+ <div id="post-api-access-settings" class="panel-collapse collapse" role="tabpanel" aria-labelledby="heading-post-api-access-settings">
90
+ <div class="panel-body">
91
+ <table class="table table-striped table-bordered">
92
+ <tbody>
93
+ <?php foreach ($apiOptions as $option => $data) { ?>
94
+ <tr>
95
+ <td width="90%">
96
+ <strong class="aam-block aam-highlight text-uppercase"><?php echo $data['title']; ?></strong>
97
+ <?php if (!empty($data['sub'])) { ?>
98
+ <small>
99
+ <?php echo $data['sub']; ?>: <b id="<?php echo $data['preview']; ?>" data-ref="<?php echo $data['option']; ?>" class="option-preview">...</b>
100
+ <a href="#<?php echo $data['modal']; ?>" data-toggle="modal" class="advanced-post-option" data-ref="<?php echo $data['option']; ?>" data-preview="#<?php echo $data['preview']; ?>"><?php echo __('change', AAM_KEY); ?></a>
101
+ </small>
102
+ <?php } ?>
103
+ <p class="aam-hint" data-dynamic-post-label="<?php echo $data['descr']; ?>"></p>
104
+ </td>
105
+ <td>
106
+ <div class="aam-row-actions">
107
+ <i class="aam-row-action text-muted icon-check-empty" data-property="api.<?php echo $option; ?>"></i>
108
+ </div>
109
+ </td>
110
+ </tr>
111
+ <?php } ?>
112
+ </tbody>
113
+ </table>
114
+ </div>
115
+ </div>
116
+ </div>
117
+ <?php } ?>
118
+ </div>
Application/Backend/phtml/partial/post-advanced-settings.phtml CHANGED
@@ -1,5 +1,26 @@
1
  <?php if (defined('AAM_KEY')) { ?>
2
- <div class="modal fade" id="modal-frontend-access_counter_limit" tabindex="-1" role="dialog">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  <div class="modal-dialog modal-sm" role="document">
4
  <div class="modal-content">
5
  <div class="modal-header">
@@ -13,14 +34,14 @@
13
  </div>
14
  </div>
15
  <div class="modal-footer">
16
- <button type="button" class="btn btn-success extended-post-access-btn" data-modal="#modal-frontend-access_counter_limit" data-field="#aam-read-counter"><?php echo __('Update', AAM_KEY); ?></button>
17
  <button type="button" class="btn btn-default" data-dismiss="modal"><?php echo __('Close', AAM_KEY); ?></button>
18
  </div>
19
  </div>
20
  </div>
21
  </div>
22
 
23
- <div class="modal fade" id="modal-frontend-password" tabindex="-1" role="dialog">
24
  <div class="modal-dialog modal-sm" role="document">
25
  <div class="modal-content">
26
  <div class="modal-header">
@@ -34,14 +55,14 @@
34
  </div>
35
  </div>
36
  <div class="modal-footer">
37
- <button type="button" class="btn btn-success extended-post-access-btn" data-modal="#modal-frontend-password" data-field="#aam-access-password"><?php echo __('Update', AAM_KEY); ?></button>
38
  <button type="button" class="btn btn-default" data-dismiss="modal"><?php echo __('Close', AAM_KEY); ?></button>
39
  </div>
40
  </div>
41
  </div>
42
  </div>
43
 
44
- <div class="modal fade" id="modal-frontend-location" tabindex="-1" role="dialog">
45
  <div class="modal-dialog" role="document">
46
  <div class="modal-content">
47
  <div class="modal-header">
@@ -56,14 +77,14 @@
56
  </div>
57
  </div>
58
  <div class="modal-footer">
59
- <button type="button" class="btn btn-success extended-post-access-btn" data-modal="#modal-frontend-location" data-field="#aam-access-redirect"><?php echo __('Update', AAM_KEY); ?></button>
60
  <button type="button" class="btn btn-default" data-dismiss="modal"><?php echo __('Close', AAM_KEY); ?></button>
61
  </div>
62
  </div>
63
  </div>
64
  </div>
65
 
66
- <div class="modal fade" id="modal-frontend-expire_datetime" tabindex="-1" role="dialog">
67
  <div class="modal-dialog" role="document">
68
  <div class="modal-content">
69
  <div class="modal-header">
@@ -83,35 +104,14 @@
83
  </div>
84
  </div>
85
  <div class="modal-footer">
86
- <button type="button" class="btn btn-success extended-post-access-btn" data-modal="#modal-frontend-expire_datetime" data-field="#aam-expire-datetime"><?php echo __('Update', AAM_KEY); ?></button>
87
- <button type="button" class="btn btn-default" data-dismiss="modal"><?php echo __('Close', AAM_KEY); ?></button>
88
- </div>
89
- </div>
90
- </div>
91
- </div>
92
-
93
- <div class="modal fade" id="modal-frontend-teaser" tabindex="-1" role="dialog">
94
- <div class="modal-dialog" role="document">
95
- <div class="modal-content">
96
- <div class="modal-header">
97
- <button type="button" class="close" data-dismiss="modal" aria-label="<?php echo __('Close', AAM_KEY); ?>"><span aria-hidden="true">&times;</span></button>
98
- <h4 class="modal-title"><?php echo __('Teaser Message', AAM_KEY); ?></h4>
99
- </div>
100
- <div class="modal-body">
101
- <div class="form-group">
102
- <label><?php echo __('Simple text or valid HTML', AAM_KEY); ?></label>
103
- <textarea class="form-control" placeholder="<?php echo __('Enter your teaser', AAM_KEY); ?>" rows="5" id="aam-teaser-message"></textarea>
104
- </div>
105
- </div>
106
- <div class="modal-footer">
107
- <button type="button" class="btn btn-success extended-post-access-btn" data-modal="#modal-frontend-teaser" data-field="#aam-teaser-message"><?php echo __('Save', AAM_KEY); ?></button>
108
  <button type="button" class="btn btn-default" data-dismiss="modal"><?php echo __('Close', AAM_KEY); ?></button>
109
  </div>
110
  </div>
111
  </div>
112
  </div>
113
 
114
- <div class="modal fade" id="modal-frontend-eproduct" tabindex="-1" role="dialog">
115
  <div class="modal-dialog" role="document">
116
  <div class="modal-content">
117
  <div class="modal-header">
@@ -122,12 +122,11 @@
122
  <?php
123
  echo apply_filters(
124
  'aam-frontend-eproduct-setup',
125
- '<p class="alert alert-warning text-center">' . AAM_Backend_View_Helper::preparePhrase('Monetization is the premium feature that is available with [Payment] extension.', 'b') . '</p>'
126
  );
127
  ?>
128
  </div>
129
  <div class="modal-footer">
130
- <button type="button" class="btn btn-success extended-post-access-btn" data-modal="#modal-frontend-eproduct" data-field="#aam-selected-eproduct"><?php echo __('Update', AAM_KEY); ?></button>
131
  <button type="button" class="btn btn-default" data-dismiss="modal"><?php echo __('Close', AAM_KEY); ?></button>
132
  </div>
133
  </div>
1
  <?php if (defined('AAM_KEY')) { ?>
2
+ <div class="modal fade" id="modal-teaser" tabindex="-1" role="dialog">
3
+ <div class="modal-dialog" role="document">
4
+ <div class="modal-content">
5
+ <div class="modal-header">
6
+ <button type="button" class="close" data-dismiss="modal" aria-label="<?php echo __('Close', AAM_KEY); ?>"><span aria-hidden="true">&times;</span></button>
7
+ <h4 class="modal-title"><?php echo __('Teaser Message', AAM_KEY); ?></h4>
8
+ </div>
9
+ <div class="modal-body">
10
+ <div class="form-group">
11
+ <label><?php echo __('Simple text or valid HTML', AAM_KEY); ?></label>
12
+ <textarea class="form-control" placeholder="<?php echo __('Enter your teaser', AAM_KEY); ?>" rows="5" id="aam-teaser-message"></textarea>
13
+ </div>
14
+ </div>
15
+ <div class="modal-footer">
16
+ <button type="button" class="btn btn-success extended-post-access-btn" data-modal="#modal-teaser" data-field="#aam-teaser-message"><?php echo __('Save', AAM_KEY); ?></button>
17
+ <button type="button" class="btn btn-default" data-dismiss="modal"><?php echo __('Close', AAM_KEY); ?></button>
18
+ </div>
19
+ </div>
20
+ </div>
21
+ </div>
22
+
23
+ <div class="modal fade" id="modal-access-counter" tabindex="-1" role="dialog">
24
  <div class="modal-dialog modal-sm" role="document">
25
  <div class="modal-content">
26
  <div class="modal-header">
34
  </div>
35
  </div>
36
  <div class="modal-footer">
37
+ <button type="button" class="btn btn-success extended-post-access-btn" data-modal="#modal-access-counter" data-field="#aam-read-counter"><?php echo __('Update', AAM_KEY); ?></button>
38
  <button type="button" class="btn btn-default" data-dismiss="modal"><?php echo __('Close', AAM_KEY); ?></button>
39
  </div>
40
  </div>
41
  </div>
42
  </div>
43
 
44
+ <div class="modal fade" id="modal-password" tabindex="-1" role="dialog">
45
  <div class="modal-dialog modal-sm" role="document">
46
  <div class="modal-content">
47
  <div class="modal-header">
55
  </div>
56
  </div>
57
  <div class="modal-footer">
58
+ <button type="button" class="btn btn-success extended-post-access-btn" data-modal="#modal-password" data-field="#aam-access-password"><?php echo __('Update', AAM_KEY); ?></button>
59
  <button type="button" class="btn btn-default" data-dismiss="modal"><?php echo __('Close', AAM_KEY); ?></button>
60
  </div>
61
  </div>
62
  </div>
63
  </div>
64
 
65
+ <div class="modal fade" id="modal-redirect" tabindex="-1" role="dialog">
66
  <div class="modal-dialog" role="document">
67
  <div class="modal-content">
68
  <div class="modal-header">
77
  </div>
78
  </div>
79
  <div class="modal-footer">
80
+ <button type="button" class="btn btn-success extended-post-access-btn" data-modal="#modal-redirect" data-field="#aam-access-redirect"><?php echo __('Update', AAM_KEY); ?></button>
81
  <button type="button" class="btn btn-default" data-dismiss="modal"><?php echo __('Close', AAM_KEY); ?></button>
82
  </div>
83
  </div>
84
  </div>
85
  </div>
86
 
87
+ <div class="modal fade" id="modal-access-expires" tabindex="-1" role="dialog">
88
  <div class="modal-dialog" role="document">
89
  <div class="modal-content">
90
  <div class="modal-header">
104
  </div>
105
  </div>
106
  <div class="modal-footer">
107
+ <button type="button" class="btn btn-success extended-post-access-btn" data-modal="#modal-access-expires" data-field="#aam-expire-datetime"><?php echo __('Update', AAM_KEY); ?></button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  <button type="button" class="btn btn-default" data-dismiss="modal"><?php echo __('Close', AAM_KEY); ?></button>
109
  </div>
110
  </div>
111
  </div>
112
  </div>
113
 
114
+ <div class="modal fade" id="modal-eproduct" tabindex="-1" role="dialog">
115
  <div class="modal-dialog" role="document">
116
  <div class="modal-content">
117
  <div class="modal-header">
122
  <?php
123
  echo apply_filters(
124
  'aam-frontend-eproduct-setup',
125
+ '<p class="alert alert-warning text-center">' . sprintf(AAM_Backend_View_Helper::preparePhrase('Monetization is the premium feature that is available with %s[E-Commerce]%s extension.', 'b'), '<a href="https://aamplugin.com/extension/ecommerce" target="_blank">', '</a>') . '</p>'
126
  );
127
  ?>
128
  </div>
129
  <div class="modal-footer">
 
130
  <button type="button" class="btn btn-default" data-dismiss="modal"><?php echo __('Close', AAM_KEY); ?></button>
131
  </div>
132
  </div>
Application/Backend/phtml/partial/role-inheritance.phtml CHANGED
@@ -8,7 +8,7 @@
8
  <div class="checkbox">
9
  <label for="clone">
10
  <input type="checkbox" value="1" id="clone-role" name="clone" />
11
- Also clone all access settings
12
  </label>
13
  </div>
14
  <?php }
8
  <div class="checkbox">
9
  <label for="clone">
10
  <input type="checkbox" value="1" id="clone-role" name="clone" />
11
+ <?php echo __('Also clone all AAM access settings (admin menu, metaboxes, redirects etc)', AAM_KEY); ?>
12
  </label>
13
  </div>
14
  <?php }
Application/Backend/phtml/partial/term-type.phtml CHANGED
@@ -1,7 +1,7 @@
1
  <?php if (defined('AAM_KEY')) { ?>
2
  <div class="row">
3
  <div class="col-xs-12">
4
- <p class="aam-notification" data-dynamic-post-label="<?php echo AAM_Backend_View_Helper::preparePhrase('Manage access to %s is available with [AAM Plus Package] extension only. With this feature you can define default access to all child posts that belong to %s. Consider to purchase [AAM Plus Package] extension.', 'b', 'b'); ?>"></p>
5
  </div>
6
  </div>
7
  <?php }
1
  <?php if (defined('AAM_KEY')) { ?>
2
  <div class="row">
3
  <div class="col-xs-12">
4
+ <p class="aam-notification" data-dynamic-post-label="<?php echo AAM_Backend_View_Helper::preparePhrase('Manage access to %s is available with [AAM Plus Package] extension only. With this feature you can also define default access to all child posts that belong to %s. Consider to purchase [AAM Plus Package] extension.', 'b', 'b'); ?>"></p>
5
  </div>
6
  </div>
7
  <?php }
Application/Core/API.php CHANGED
@@ -29,20 +29,40 @@ final class AAM_Core_API {
29
  */
30
  public static function getOption($option, $default = FALSE, $blog_id = null) {
31
  if (is_multisite()) {
32
- if (is_null($blog_id)) {
33
- $blog = get_current_blog_id();
34
- } elseif ($blog_id == 'site') {
35
- $blog = (defined('SITE_ID_CURRENT_SITE') ? SITE_ID_CURRENT_SITE : 1);
36
  } else {
37
- $blog = $blog_id;
 
 
 
 
 
38
  }
39
- $response = get_blog_option($blog, $option, $default);
40
  } else {
41
- $response = get_option($option, $default);
42
  }
43
 
44
  return $response;
45
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
 
47
  /**
48
  * Update option
@@ -111,7 +131,7 @@ final class AAM_Core_API {
111
  *
112
  * @access public
113
  */
114
- public static function cURL($url, $send_cookies = TRUE, $params = array(), $timeout = 20) {
115
  $header = array('User-Agent' => AAM_Core_Request::server('HTTP_USER_AGENT'));
116
 
117
  $cookies = AAM_Core_Request::cookie(null, array());
@@ -218,6 +238,31 @@ final class AAM_Core_API {
218
  return (is_string($cap) && array_key_exists($cap, $caps) ? true : false);
219
  }
220
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
  /**
222
  * Reject the request
223
  *
@@ -244,7 +289,7 @@ final class AAM_Core_API {
244
  $redirect = $object->get("{$area}.redirect.{$type}");
245
  } else { //ConfigPress setup
246
  $redirect = AAM_Core_Config::get(
247
- "{$area}.access.deny.redirect", __('Access Denied', AAM_KEY)
248
  );
249
  }
250
 
@@ -336,24 +381,20 @@ final class AAM_Core_API {
336
  *
337
  * @access public
338
  */
339
- public static function getFilteredPostList($query, $area = 'frontend') {
340
  $filtered = array();
341
- $type = self::getQueryPostType($query);
342
 
343
- if ($type) {
344
- if (AAM_Core_Cache::has("{$type}__not_in_{$area}")) {
345
- $filtered = AAM_Core_Cache::get("{$type}__not_in_{$area}");
346
- } else { //first initial build
347
- $posts = get_posts(array(
348
- 'post_type' => $type,
349
- 'numberposts' => AAM_Core_Config::get('get_post_limit', 500),
350
- 'post_status' => 'any'
351
- ));
352
-
353
- foreach ($posts as $post) {
354
- if (self::isHiddenPost($post, $type, $area)) {
355
- $filtered[] = $post->ID;
356
- }
357
  }
358
  }
359
  }
@@ -370,51 +411,6 @@ final class AAM_Core_API {
370
  return (is_array($filtered) ? $filtered : array());
371
  }
372
 
373
- /**
374
- * Check if post is hidden
375
- *
376
- * @param mixed $post
377
- * @param string $area
378
- *
379
- * @return boolean
380
- *
381
- * @access public
382
- */
383
- public static function isHiddenPost($post, $type, $area = 'frontend') {
384
- static $counter = 0;
385
-
386
- $hidden = false;
387
-
388
- if ($counter <= AAM_Core_Config::get('get_post_limit', 500)) { //avoid server crash
389
- $user = get_current_user_id();
390
- $key = "{$type}__not_in_{$area}";
391
- $cache = AAM_Core_Cache::get($key, array());
392
- $checked = AAM_Core_Cache::get($key . '_checked', array());
393
-
394
- if (!in_array($post->ID, $cache)) {
395
- if (!in_array($post->ID, $checked)) {
396
- $object = AAM::getUser()->getObject('post', $post->ID, $post);
397
- $list = $object->has("{$area}.list");
398
- $others = $object->has("{$area}.list_others");
399
- $checked[] = $post->ID;
400
-
401
- if ($list || ($others && ($post->post_author != $user))) {
402
- $hidden = true;
403
- $cache[] = $post->ID;
404
- }
405
-
406
- AAM_Core_Cache::set($key . '_checked', $checked);
407
- AAM_Core_Cache::set($key, $cache);
408
- $counter++;
409
- }
410
- } else {
411
- $hidden = true;
412
- }
413
- }
414
-
415
- return $hidden;
416
- }
417
-
418
  /**
419
  * Get Query post type
420
  *
@@ -449,7 +445,7 @@ final class AAM_Core_API {
449
  public static function getCurrentPost() {
450
  global $wp_query, $post;
451
 
452
- $res = null;
453
 
454
  if (!empty($wp_query->queried_object)) {
455
  $res = $wp_query->queried_object;
29
  */
30
  public static function getOption($option, $default = FALSE, $blog_id = null) {
31
  if (is_multisite()) {
32
+ if (is_null($blog_id) || get_current_blog_id() == $blog_id) {
33
+ $response = self::getCachedOption($option, $default);
 
 
34
  } else {
35
+ if ($blog_id == 'site') {
36
+ $blog = (defined('SITE_ID_CURRENT_SITE') ? SITE_ID_CURRENT_SITE : 1);
37
+ } else {
38
+ $blog = $blog_id;
39
+ }
40
+ $response = get_blog_option($blog, $option, $default);
41
  }
 
42
  } else {
43
+ $response = self::getCachedOption($option, $default);
44
  }
45
 
46
  return $response;
47
  }
48
+
49
+ /**
50
+ *
51
+ * @param type $option
52
+ * @param type $default
53
+ * @return type
54
+ */
55
+ protected static function getCachedOption($option, $default) {
56
+ $cache = wp_cache_get('alloptions', 'options');
57
+
58
+ if (empty($cache)) {
59
+ $response = get_option($option, $default);
60
+ } else {
61
+ $response = isset($cache[$option]) ? maybe_unserialize($cache[$option]) : $default;
62
+ }
63
+
64
+ return $response;
65
+ }
66
 
67
  /**
68
  * Update option
131
  *
132
  * @access public
133
  */
134
+ public static function cURL($url, $send_cookies = true, $params = array(), $timeout = 20) {
135
  $header = array('User-Agent' => AAM_Core_Request::server('HTTP_USER_AGENT'));
136
 
137
  $cookies = AAM_Core_Request::cookie(null, array());
238
  return (is_string($cap) && array_key_exists($cap, $caps) ? true : false);
239
  }
240
 
241
+ /**
242
+ *
243
+ * @param AAM_Core_Subject $subject
244
+ */
245
+ public static function clearCache($subject = null) {
246
+ global $wpdb;
247
+
248
+ if (empty($subject)) { // clear all cache
249
+ // visitors, default and role cache
250
+ $query = "DELETE FROM {$wpdb->options} WHERE `option_name` LIKE %s";
251
+ $wpdb->query($wpdb->prepare($query, '%aam_cache%' ));
252
+
253
+ // TODO: aam_visitor_cache does not follow the option naming pattern
254
+ $query = "DELETE FROM {$wpdb->options} WHERE `option_name` = %s";
255
+ $wpdb->query($wpdb->prepare($query, 'aam_visitor_cache' ));
256
+
257
+ // user cache
258
+ $query = "DELETE FROM {$wpdb->usermeta} WHERE `meta_key` LIKE %s";
259
+ $wpdb->query($wpdb->prepare($query, '%aam_cache%' ));
260
+ } else {
261
+ //clear visitor cache
262
+ $subject->getObject('cache')->reset();
263
+ }
264
+ }
265
+
266
  /**
267
  * Reject the request
268
  *
289
  $redirect = $object->get("{$area}.redirect.{$type}");
290
  } else { //ConfigPress setup
291
  $redirect = AAM_Core_Config::get(
292
+ "{$area}.access.deny.redirect", __('Access Denied', AAM_KEY)
293
  );
294
  }
295
 
381
  *
382
  * @access public
383
  */
384
+ public static function getFilteredPostList($query) {
385
  $filtered = array();
 
386
 
387
+ $type = self::getQueryPostType($query);
388
+ $area = AAM_Core_Api_Area::get();
389
+
390
+ if ($type) {
391
+ $cache = AAM::getUser()->getObject('cache')->getMergedOption();
392
+ $posts = (isset($cache['post']) ? $cache['post'] : array());
393
+
394
+ foreach($posts as $id => $option) {
395
+ if (!empty($option["{$area}.list"])
396
+ || !empty($option["{$area}.hidden"])) {
397
+ $filtered[] = $id;
 
 
 
398
  }
399
  }
400
  }
411
  return (is_array($filtered) ? $filtered : array());
412
  }
413
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
414
  /**
415
  * Get Query post type
416
  *
445
  public static function getCurrentPost() {
446
  global $wp_query, $post;
447
 
448
+ $res = $post;
449
 
450
  if (!empty($wp_query->queried_object)) {
451
  $res = $wp_query->queried_object;
Application/Core/Api/Area.php ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
10
+ /**
11
+ * AAM core API Area class
12
+ *
13
+ * This class defines what area AAM is operating on. Can be backend, frontend, rest
14
+ * etc.
15
+ *
16
+ * @package AAM
17
+ * @author Vasyl Martyniuk <vasyl@vasyltech.com>
18
+ */
19
+ final class AAM_Core_Api_Area {
20
+
21
+ /**
22
+ *
23
+ */
24
+ const BACKEND = "backend";
25
+
26
+ /**
27
+ *
28
+ */
29
+ const FRONTEND = "frontend";
30
+
31
+ /**
32
+ *
33
+ */
34
+ const API = "api";
35
+
36
+ /**
37
+ * Get operating area
38
+ *
39
+ * @return string
40
+ *
41
+ * @access public
42
+ * @static
43
+ */
44
+ public static function get() {
45
+ if (defined('REST_REQUEST') && REST_REQUEST) {
46
+ $area = self::API;
47
+ } elseif (is_admin()) {
48
+ $area = self::BACKEND;
49
+ } else {
50
+ $area = self::FRONTEND;
51
+ }
52
+
53
+ return $area;
54
+ }
55
+
56
+ /**
57
+ *
58
+ * @return type
59
+ */
60
+ public static function isBackend() {
61
+ return self::get() == self::BACKEND;
62
+ }
63
+
64
+ /**
65
+ *
66
+ * @return type
67
+ */
68
+ public static function isFrontend() {
69
+ return self::get() == self::FRONTEND;
70
+ }
71
+
72
+ /**
73
+ *
74
+ * @return type
75
+ */
76
+ public static function isAPI() {
77
+ return self::get() == self::API;
78
+ }
79
+ }
Application/Core/Cache.php CHANGED
@@ -12,32 +12,10 @@
12
  *
13
  * @package AAM
14
  * @author Vasyl Martyniuk <vasyl@vasyltech.com>
 
15
  */
16
  class AAM_Core_Cache {
17
 
18
- /**
19
- * DB post cache option
20
- */
21
- const POST_CACHE= 'aam_post_cache_user';
22
-
23
- /**
24
- * Core config
25
- *
26
- * @var array
27
- *
28
- * @access protected
29
- */
30
- protected static $cache = array();
31
-
32
- /**
33
- * Update cache flag
34
- *
35
- * @var boolean
36
- *
37
- * @access protected
38
- */
39
- protected static $updated = false;
40
-
41
  /**
42
  * Get cached option
43
  *
@@ -47,8 +25,8 @@ class AAM_Core_Cache {
47
  *
48
  * @access public
49
  */
50
- public static function get($option, $default = null) {
51
- return (self::has($option) ? self::$cache[$option] : $default);
52
  }
53
 
54
  /**
@@ -62,15 +40,7 @@ class AAM_Core_Cache {
62
  *
63
  * @access public
64
  */
65
- public static function set($option, $data, $legacy = null) {
66
- // TODO - Compatibility. Remove Apr 2019
67
- $key = (is_scalar($option) ? $option : $data);
68
- $val = (is_scalar($option) ? $data : $legacy);
69
-
70
- if (!self::has($key) || (self::$cache[$key] != $val)) {
71
- self::$cache[$key] = $val;
72
- self::$updated = true;
73
- }
74
  }
75
 
76
  /**
@@ -82,84 +52,8 @@ class AAM_Core_Cache {
82
  *
83
  * @access public
84
  */
85
- public static function has($option) {
86
- return is_array(self::$cache) && array_key_exists($option, self::$cache);
87
- }
88
-
89
- /**
90
- * Clear cache
91
- *
92
- * @return void
93
- *
94
- * @access public
95
- * @global WPDB $wpdb
96
- */
97
- public static function clear($user = null) {
98
- global $wpdb;
99
-
100
- if (empty($user)) {
101
- //clear visitor cache
102
- $query = "DELETE FROM {$wpdb->options} WHERE `option_name` LIKE %s";
103
- $wpdb->query($wpdb->prepare($query, '_transient_aam_%' ));
104
- } else {
105
- delete_transient(self::getCacheOption($user));
106
- }
107
-
108
- //reset cache
109
- self::$cache = array();
110
- self::$updated = false;
111
- }
112
-
113
- /**
114
- * Save cache
115
- *
116
- * Save aam cache but only if changes deleted
117
- *
118
- * @return void
119
- *
120
- * @access public
121
- */
122
- public static function save() {
123
- if (self::$updated === true) {
124
- set_transient(self::getCacheOption(), self::$cache);
125
- }
126
- }
127
-
128
- /**
129
- *
130
- * @return type
131
- */
132
- protected static function getCacheOption($id = null) {
133
- $option = self::POST_CACHE . '_';
134
-
135
- if (empty($id)) {
136
- $option .= AAM::getUser()->isVisitor() ? 'visitor' : AAM::getUser()->ID;
137
- } else {
138
- $option .= $id;
139
- }
140
-
141
- return $option;
142
- }
143
-
144
- /**
145
- * Bootstrap cache
146
- *
147
- * Do not load cache if user is on AAM page
148
- *
149
- * @return void
150
- *
151
- * @access public
152
- */
153
- public static function bootstrap() {
154
- if (!AAM::isAAM()) {
155
- $cache = get_transient(self::getCacheOption());
156
- self::$cache = (is_array($cache) ? $cache : array());
157
-
158
- add_action('shutdown', 'AAM_Core_Cache::save');
159
- add_filter('aam-get-cache-filter', 'AAM_Core_Cache::get', 10, 2);
160
- add_action('aam-set-cache-action', 'AAM_Core_Cache::set', 10, 2);
161
- add_action('aam-clear-cache-action', 'AAM_Core_Cache::clear');
162
- }
163
  }
164
 
165
  }
12
  *
13
  * @package AAM
14
  * @author Vasyl Martyniuk <vasyl@vasyltech.com>
15
+ * @todo - Remove May 2019
16
  */
17
  class AAM_Core_Cache {
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  /**
20
  * Get cached option
21
  *
25
  *
26
  * @access public
27
  */
28
+ public static function get() {
29
+ return null;
30
  }
31
 
32
  /**
40
  *
41
  * @access public
42
  */
43
+ public static function set() {
 
 
 
 
 
 
 
 
44
  }
45
 
46
  /**
52
  *
53
  * @access public
54
  */
55
+ public static function has() {
56
+ return null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  }
58
 
59
  }
Application/Core/Compatibility.php CHANGED
@@ -28,27 +28,12 @@ class AAM_Core_Compatibility {
28
  define('AAM_CONTENT_TEASER', '99');
29
  define('AAM_LOGIN_REDIRECT', '99');
30
  define('AAM_CONFIGPRESS', '99');
31
- //TODO - Remove this in Jul 2018
32
-
33
- //caching filter & action
34
- add_filter(
35
- 'aam-read-cache-filter', 'AAM_Core_Compatibility::readCache', 10, 2
36
- );
37
 
38
  //utilities option
39
  add_filter('aam-utility-property', 'AAM_Core_Config::get', 10, 2);
40
  }
41
 
42
- /**
43
- *
44
- * @param type $value
45
- * @param type $option
46
- * @return type
47
- */
48
- public static function readCache($value, $option) {
49
- return AAM_Core_Cache::get($option, $value);
50
- }
51
-
52
  /**
53
  *
54
  * @return type
28
  define('AAM_CONTENT_TEASER', '99');
29
  define('AAM_LOGIN_REDIRECT', '99');
30
  define('AAM_CONFIGPRESS', '99');
31
+ //TODO - Remove this in Jul 2019
 
 
 
 
 
32
 
33
  //utilities option
34
  add_filter('aam-utility-property', 'AAM_Core_Config::get', 10, 2);
35
  }
36
 
 
 
 
 
 
 
 
 
 
 
37
  /**
38
  *
39
  * @return type
Application/Core/ConfigPress/Reader.php CHANGED
@@ -142,7 +142,7 @@ class AAM_Core_ConfigPress_Reader {
142
  * @return type
143
  */
144
  protected function parseValue($value) {
145
- return trim($value);
146
  }
147
 
148
  }
142
  * @return type
143
  */
144
  protected function parseValue($value) {
145
+ return is_string($value) ? trim($value) : $value;
146
  }
147
 
148
  }
Application/Core/JwtAuth.php CHANGED
@@ -55,7 +55,7 @@ class AAM_Core_JwtAuth {
55
 
56
  if (empty($secret)) {
57
  AAM_Core_Console::add(
58
- __('JWT Authentication is enabled but secret key is not defined', AAM_KEY)
59
  );
60
  }
61
  }
@@ -109,20 +109,28 @@ class AAM_Core_JwtAuth {
109
  $key = AAM_Core_Config::get('authentication.jwt.secret');
110
  $expire = AAM_Core_Config::get('authentication.jwt.expires', 86400);
111
 
112
- $claims = array(
113
- "iat" => time(),
114
- 'exp' => time() + $expire, // by default expires in 1 day
115
- 'userId' => $result['user']->ID,
116
- );
117
-
118
- $response->data = array(
119
- 'token' => Firebase\JWT\JWT::encode(
120
- apply_filters('aam-jwt-claims-filter', $claims), $key
121
- ),
122
- 'token_expires' => $claims['exp'],
123
- 'user' => $result['user']
124
- );
125
- $response->status = 200;
 
 
 
 
 
 
 
 
126
  } else {
127
  $response->data = $result['error'];
128
  $response->status = 403;
55
 
56
  if (empty($secret)) {
57
  AAM_Core_Console::add(
58
+ __('JWT Authentication is enabled but authentication.jwt.secret is not defined', AAM_KEY)
59
  );
60
  }
61
  }
109
  $key = AAM_Core_Config::get('authentication.jwt.secret');
110
  $expire = AAM_Core_Config::get('authentication.jwt.expires', 86400);
111
 
112
+ if ($key) {
113
+ $claims = array(
114
+ "iat" => time(),
115
+ 'exp' => time() + $expire, // by default expires in 1 day
116
+ 'userId' => $result['user']->ID,
117
+ );
118
+
119
+ $response->data = array(
120
+ 'token' => Firebase\JWT\JWT::encode(
121
+ apply_filters('aam-jwt-claims-filter', $claims), $key
122
+ ),
123
+ 'token_expires' => $claims['exp'],
124
+ 'user' => $result['user']
125
+ );
126
+ $response->status = 200;
127
+ } else {
128
+ $response->status = 400;
129
+ $response->data = new WP_Error(
130
+ 'jwt_empty_secret_key',
131
+ __('JWT Authentication is enabled but secret key is not defined', AAM_KEY)
132
+ );
133
+ }
134
  } else {
135
  $response->data = $result['error'];
136
  $response->status = 403;
Application/Core/Media.php CHANGED
@@ -48,7 +48,7 @@ class AAM_Core_Media {
48
  $this->initialize();
49
 
50
  if (AAM_Core_Config::get('media-access-control', false)) {
51
- $area = (is_admin() ? 'backend' : 'frontend');
52
  if (AAM_Core_Config::get("{$area}-access-control", true)) {
53
  $this->checkMediaAccess();
54
  } else {
48
  $this->initialize();
49
 
50
  if (AAM_Core_Config::get('media-access-control', false)) {
51
+ $area = AAM_Core_Api_Area::get();
52
  if (AAM_Core_Config::get("{$area}-access-control", true)) {
53
  $this->checkMediaAccess();
54
  } else {
Application/Core/Object/Cache.php ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
10
+ /**
11
+ * AAM cache object
12
+ *
13
+ * @package AAM
14
+ * @author Vasyl Martyniuk <vasyl@vasyltech.com>
15
+ */
16
+ class AAM_Core_Object_Cache extends AAM_Core_Object {
17
+
18
+ /**
19
+ * Cache updated flag
20
+ *
21
+ * @var boolean
22
+ *
23
+ * @access protected
24
+ */
25
+ protected $updated = false;
26
+
27
+ /**
28
+ * Constructor
29
+ *
30
+ * @param AAM_Core_Subject $subject
31
+ *
32
+ * @return void
33
+ *
34
+ * @access public
35
+ */
36
+ public function __construct(AAM_Core_Subject $subject) {
37
+ parent::__construct($subject);
38
+
39
+ if (!AAM::isAAM()
40
+ && (AAM_Core_Config::get('core.cache.status', 'enabled') == 'enabled')) {
41
+ // Register shutdown hook
42
+ add_action('shutdown', array($this, 'save'));
43
+
44
+ // Just get the cache from current subject level. Do not trigger
45
+ // inheritance chain!
46
+ $this->setOption($this->getSubject()->readOption('cache'));
47
+ }
48
+ }
49
+
50
+ /**
51
+ *
52
+ * @param type $type
53
+ * @param type $id
54
+ * @param type $value
55
+ */
56
+ public function add($type, $id, $value) {
57
+ $option = $this->getOption();
58
+ $option[$type][$id] = $value;
59
+ $this->setOption($option);
60
+
61
+ $this->updated = true;
62
+ }
63
+
64
+ /**
65
+ * Get cache
66
+ *
67
+ * @param string $type
68
+ * @param string|int $id
69
+ * @param mixed $default
70
+ *
71
+ * @return mixed
72
+ *
73
+ * @access public
74
+ */
75
+ public function get($type, $id, $default = array()) {
76
+ $option = $this->getOption();
77
+
78
+ return (isset($option[$type][$id]) ? $option[$type][$id] : $default);
79
+ }
80
+
81
+ /**
82
+ * Save cache
83
+ *
84
+ * @return bool
85
+ *
86
+ * @access public
87
+ */
88
+ public function save() {
89
+ if ($this->updated) {
90
+ $this->getSubject()->updateOption($this->getOption(), 'cache');
91
+ }
92
+
93
+ return true;
94
+ }
95
+
96
+ /**
97
+ *
98
+ * @return type
99
+ */
100
+ public function reset() {
101
+ return $this->getSubject()->deleteOption('cache');
102
+ }
103
+
104
+ /**
105
+ *
106
+ * @return type
107
+ */
108
+ public function getMergedOption() {
109
+ $options = array($this->getOption());
110
+ $subject = $this->getSubject();
111
+
112
+ while($subject = $subject->getParent()) {
113
+ $options[] = $subject->getObject('cache')->getOption();
114
+ }
115
+
116
+ $merged = array();
117
+
118
+ // Important to reverse as lower subject level overrides higher. For example,
119
+ // Role level overrides Default level.
120
+ foreach(array_reverse($options) as $option) {
121
+ if (is_array($option)) {
122
+ $merged = array_replace_recursive($merged, $option);
123
+ }
124
+ }
125
+
126
+ return $merged;
127
+ }
128
+
129
+ /**
130
+ * Read object from parent subject
131
+ *
132
+ * @return mixed
133
+ *
134
+ * @access public
135
+ */
136
+ public function inheritFromParent(){
137
+ if ($subject = $this->getParent()){
138
+ $option = $subject->getObject('cache')->getOption();
139
+ } else {
140
+ $option = array();
141
+ }
142
+
143
+ return $option;
144
+ }
145
+
146
+ }
Application/Core/Object/Post.php CHANGED
@@ -50,9 +50,13 @@ class AAM_Core_Object_Post extends AAM_Core_Object {
50
  }
51
 
52
  /**
 
53
  *
54
- * @param type $name
55
- * @return type
 
 
 
56
  */
57
  public function __get($name) {
58
  $post = $this->getPost();
@@ -72,37 +76,103 @@ class AAM_Core_Object_Post extends AAM_Core_Object {
72
  public function read() {
73
  $subject = $this->getSubject();
74
  $post = $this->getPost();
75
- $opname = $this->getOptionName();
76
- $chname = $opname . '|' . $post->ID;
77
 
78
- //read cache first
79
- $option = AAM_Core_Cache::get($chname);
80
 
81
  if ($option === false) { //if false, then the cache is empty but exist
82
  $option = array();
83
- } else {
84
- //Cache is empty. Get post access for current subject (user or role)
85
- if (empty($option)) { //no cache for this element
86
- $option = get_post_meta($post->ID, $opname, true);
87
- $this->setOverwritten(!empty($option));
88
- }
89
 
90
- //try to inherit from terms or default settings - AAM Plus Package or any
91
- //other extension that use this filter
92
  if (empty($option)) {
93
  $option = apply_filters('aam-post-access-filter', $option, $this);
94
  }
95
 
96
- //No settings for a post. Try to inherit from the parent
97
- if (empty($option)) {
 
 
98
  $option = $subject->inheritFromParent('post', $post->ID, $post);
99
  }
 
 
 
 
 
 
 
100
  }
101
 
102
  $this->setOption($option);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
 
104
- //if result is empty, simply cache the false to speed-up
105
- AAM_Core_Cache::set($chname, (empty($option) ? false : $option));
 
 
 
 
106
  }
107
 
108
  /**
@@ -117,9 +187,17 @@ class AAM_Core_Object_Post extends AAM_Core_Object {
117
 
118
  $option[$property] = $checked;
119
 
120
- $result = update_post_meta(
121
- $this->getPost()->ID, $this->getOptionName(), $option
122
- );
 
 
 
 
 
 
 
 
123
 
124
  if ($result) {
125
  $this->setOption($option);
@@ -136,9 +214,19 @@ class AAM_Core_Object_Post extends AAM_Core_Object {
136
  * @access public
137
  */
138
  public function reset() {
139
- AAM_Core_Cache::clear();
 
 
 
 
 
 
 
 
 
 
140
 
141
- return delete_post_meta($this->getPost()->ID, $this->getOptionName());
142
  }
143
 
144
  /**
50
  }
51
 
52
  /**
53
+ * Get WP post property
54
  *
55
+ * @param string $name
56
+ *
57
+ * @return mixed
58
+ *
59
+ * @access public
60
  */
61
  public function __get($name) {
62
  $post = $this->getPost();
76
  public function read() {
77
  $subject = $this->getSubject();
78
  $post = $this->getPost();
 
 
79
 
80
+ // Read cache first
81
+ $option = $subject->getObject('cache')->get('post', $post->ID);
82
 
83
  if ($option === false) { //if false, then the cache is empty but exist
84
  $option = array();
85
+ } elseif (empty($option)) {
86
+ $option = get_post_meta($post->ID, $this->getOptionName(), true);
87
+ $this->setOverwritten(!empty($option));
 
 
 
88
 
89
+ // Inherit from terms or default settings - AAM Plus Package
 
90
  if (empty($option)) {
91
  $option = apply_filters('aam-post-access-filter', $option, $this);
92
  }
93
 
94
+ // Cache result but only if it is not empty
95
+ if (!empty($option)) {
96
+ $subject->getObject('cache')->add('post', $post->ID, $option);
97
+ } else { // No settings for a post. Try to inherit from the parent
98
  $option = $subject->inheritFromParent('post', $post->ID, $post);
99
  }
100
+
101
+ // Do not perform finalization if this is user level subject unless it
102
+ // is overriten. This is critical to avoid overloading database with too
103
+ // much cache
104
+ if ($this->allowCache($subject) || $this->isOverwritten()) {
105
+ $this->finalizeOption($post, $subject, $option);
106
+ }
107
  }
108
 
109
  $this->setOption($option);
110
+ }
111
+
112
+ /**
113
+ *
114
+ * @param type $subject
115
+ * @return type
116
+ * @todo This does not belong here
117
+ */
118
+ protected function allowCache($subject) {
119
+ $config = AAM_Core_Config::get(
120
+ 'core.cache.post.levels', array('role', 'visitor', 'user')
121
+ );
122
+
123
+ return is_array($config) && in_array($subject::UID, $config);
124
+ }
125
+
126
+ /**
127
+ * Finalize post options
128
+ *
129
+ * @param WP_Post $post
130
+ * @param AAM_Core_Subject $subject
131
+ * @param array &$option
132
+ *
133
+ * @return void
134
+ *
135
+ * @access protected
136
+ */
137
+ protected function finalizeOption($post, $subject, &$option) {
138
+ // If result is empty, simply cache the false to speed-up but do not
139
+ // do it on the use level to avoid overloading database with too much cache
140
+ if (empty($option)) {
141
+ $subject->getObject('cache')->add('post', $post->ID, false);
142
+ } else {
143
+ $subject->getObject('cache')->add('post', $post->ID, $option);
144
+
145
+ // Determine if post is hidden or not. This is more complex calculation
146
+ // as it is based on the combination of several options
147
+ // TODO: this check does not belong here
148
+ if (in_array($subject::UID, array('user'))) {
149
+ $this->determineVisibility($post, 'frontend', $option);
150
+ $this->determineVisibility($post, 'backend', $option);
151
+ $this->determineVisibility($post, 'api', $option);
152
+ }
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Determine if post is visible for current subject
158
+ *
159
+ * @param WP_Post $post
160
+ * @param string $area
161
+ *
162
+ * @param boolean $option
163
+ *
164
+ * @access protected
165
+ */
166
+ protected function determineVisibility($post, $area, &$option) {
167
+ $list = !empty($option["{$area}.list"]);
168
+ $others = !empty($option["{$area}.list_others"]);
169
 
170
+ if ($list || ($others && ($post->post_author != $this->getSubject()->ID))) {
171
+ $option["{$area}.hidden"] = true;
172
+
173
+ // Cache result but only if visibility is true!
174
+ $this->getSubject()->getObject('cache')->add('post', $post->ID, $option);
175
+ }
176
  }
177
 
178
  /**
187
 
188
  $option[$property] = $checked;
189
 
190
+ // Very specific WP case. According to the WP core, you are not allowed to
191
+ // set meta for revision, so let's bypass this constrain.
192
+ if ($this->getPost()->post_type == 'revision') {
193
+ $result = update_metadata(
194
+ 'post', $this->getPost()->ID, $this->getOptionName(), $option
195
+ );
196
+ } else {
197
+ $result = update_post_meta(
198
+ $this->getPost()->ID, $this->getOptionName(), $option
199
+ );
200
+ }
201
 
202
  if ($result) {
203
  $this->setOption($option);
214
  * @access public
215
  */
216
  public function reset() {
217
+ AAM_Core_API::clearCache();
218
+
219
+ // Very specific WP case. According to the WP core, you are not allowed to
220
+ // set meta for revision, so let's bypass this constrain.
221
+ if ($this->getPost()->post_type == 'revision') {
222
+ $result = delete_metadata(
223
+ 'post', $this->getPost()->ID, $this->getOptionName()
224
+ );
225
+ } else {
226
+ $result = delete_post_meta($this->getPost()->ID, $this->getOptionName());
227
+ }
228
 
229
+ return $result;
230
  }
231
 
232
  /**
Application/Core/Subject/Role.php CHANGED
@@ -202,12 +202,4 @@ class AAM_Core_Subject_Role extends AAM_Core_Subject {
202
  return AAM_Core_API::maxLevel($this->capabilities);
203
  }
204
 
205
- /**
206
- *
207
- * @return boolean
208
- */
209
- public function isRole() {
210
- return true;
211
- }
212
-
213
  }
202
  return AAM_Core_API::maxLevel($this->capabilities);
203
  }
204
 
 
 
 
 
 
 
 
 
205
  }
Application/Core/Subject/User.php CHANGED
@@ -19,6 +19,15 @@ class AAM_Core_Subject_User extends AAM_Core_Subject {
19
  * Subject UID: USER
20
  */
21
  const UID = 'user';
 
 
 
 
 
 
 
 
 
22
 
23
  /**
24
  * AAM Capability Key
@@ -42,19 +51,21 @@ class AAM_Core_Subject_User extends AAM_Core_Subject {
42
  public function __construct($id) {
43
  parent::__construct($id);
44
 
45
- if (get_current_user_id() == $id) {
46
  //check if user is expired
47
  $expired = get_user_option('aam_user_expiration');
48
  if (!empty($expired)) {
49
  $parts = explode('|', $expired);
50
  if ($parts[0] <= date('Y-m-d H:i:s')) {
51
- $this->expireUser($parts[1]);
52
  }
53
  }
54
 
55
  //check if user is locked
56
  if ($this->user_status == 1) {
 
57
  wp_logout();
 
58
  }
59
 
60
  //check if user's role expired
@@ -68,17 +79,24 @@ class AAM_Core_Subject_User extends AAM_Core_Subject {
68
  /**
69
  * Expire user
70
  *
71
- * @param string $action
72
  *
73
  * @return void
74
  *
75
  * @access
76
  */
77
- public function expireUser($action) {
78
- switch($action) {
79
  case 'lock':
80
  $this->block();
81
  break;
 
 
 
 
 
 
 
82
 
83
  case 'delete':
84
  require_once(ABSPATH . 'wp-admin/includes/user.php' );
@@ -368,12 +386,4 @@ class AAM_Core_Subject_User extends AAM_Core_Subject {
368
  return AAM_Core_API::maxLevel($this->allcaps);
369
  }
370
 
371
- /**
372
- *
373
- * @return boolean
374
- */
375
- public function isUser() {
376
- return true;
377
- }
378
-
379
  }
19
  * Subject UID: USER
20
  */
21
  const UID = 'user';
22
+
23
+ /**
24
+ * Skip initialization
25
+ *
26
+ * Avoid recurring loop when user is locked
27
+ *
28
+ * @var type
29
+ */
30
+ protected static $skipInit = false;
31
 
32
  /**
33
  * AAM Capability Key
51
  public function __construct($id) {
52
  parent::__construct($id);
53
 
54
+ if (get_current_user_id() == $id && !self::$skipInit) {
55
  //check if user is expired
56
  $expired = get_user_option('aam_user_expiration');
57
  if (!empty($expired)) {
58
  $parts = explode('|', $expired);
59
  if ($parts[0] <= date('Y-m-d H:i:s')) {
60
+ $this->triggerExpiredUserAction($parts);
61
  }
62
  }
63
 
64
  //check if user is locked
65
  if ($this->user_status == 1) {
66
+ self::$skipInit = true;
67
  wp_logout();
68
+ self::$skipInit = false;
69
  }
70
 
71
  //check if user's role expired
79
  /**
80
  * Expire user
81
  *
82
+ * @param array $config
83
  *
84
  * @return void
85
  *
86
  * @access
87
  */
88
+ public function triggerExpiredUserAction($config) {
89
+ switch($config[1]) {
90
  case 'lock':
91
  $this->block();
92
  break;
93
+
94
+ case 'change-role':
95
+ if (AAM_Core_API::getRoles()->is_role($config[2])) {
96
+ $this->getSubject()->set_role($config[2]);
97
+ delete_user_option($this->getSubject()->ID, 'aam_user_expiration');
98
+ }
99
+ break;
100
 
101
  case 'delete':
102
  require_once(ABSPATH . 'wp-admin/includes/user.php' );
386
  return AAM_Core_API::maxLevel($this->allcaps);
387
  }
388
 
 
 
 
 
 
 
 
 
389
  }
Application/Core/Wp.php DELETED
@@ -1,88 +0,0 @@
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
-
10
- /**
11
- * AAM WordPress core hooks
12
- *
13
- * @package AAM
14
- * @author Vasyl Martyniuk <vasyl@vasyltech.com>
15
- */
16
- class AAM_Core_Wp {
17
-
18
- /**
19
- * Initialize core hooks
20
- *
21
- * @return void
22
- *
23
- * @access public
24
- */
25
- public static function bootstrap() {
26
- // Disable XML-RPC if needed
27
- if (!AAM_Core_Config::get('core.xmlrpc', true)) {
28
- add_filter('xmlrpc_enabled', '__return_false');
29
- }
30
-
31
- // Disable RESTfull API if needed
32
- if (!AAM_Core_Config::get('core.restfull', true)) {
33
- add_filter(
34
- 'rest_authentication_errors', 'AAM_Core_Wp::disableRestful', 1
35
- );
36
- }
37
-
38
- // Manage access to the RESTful endpoints
39
- add_filter('rest_pre_dispatch', 'AAM_Core_Wp::restAuth', 1, 3);
40
- }
41
-
42
- /**
43
- *
44
- * @param WP_Error|null|bool $response
45
- *
46
- * @return \WP_Error
47
- */
48
- public static function disableRestful($response) {
49
- if (!is_wp_error($response)) {
50
- $response = new WP_Error(
51
- 'access_denied',
52
- __('RESTfull API is disabled', AAM_KEY),
53
- array('status' => 403)
54
- );
55
- }
56
-
57
- return $response;
58
- }
59
-
60
- /**
61
- *
62
- * @param WP_Error $response
63
- * @param type $server
64
- * @param type $request
65
- * @return \WP_Error
66
- */
67
- public static function restAuth($response, $server, $request) {
68
- $user = AAM::getUser();
69
- $object = $user->getObject('route');
70
- $matched = $request->get_route();
71
- $method = $request->get_method();
72
-
73
- foreach(array_keys($server->get_routes()) as $route) {
74
- if ($route == $matched || preg_match("#^{$route}$#i", $matched)) {
75
- if ($object->has('restful', $route, $method)) {
76
- $response = new WP_Error(
77
- 'access_denied',
78
- __('Access denied', AAM_KEY),
79
- array('status' => 401)
80
- );
81
- break;
82
- }
83
- }
84
- }
85
-
86
- return $response;
87
- }
88
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Application/Frontend/Filter.php CHANGED
@@ -42,30 +42,14 @@ class AAM_Frontend_Filter {
42
  //important to keep this option optional for optimization reasons
43
  if (AAM_Core_Config::get('check-post-visibility', true)) {
44
  //filter navigation pages & taxonomies
45
- add_filter('get_pages', array($this, 'filterPostList'), 999);
46
  add_filter('wp_get_nav_menu_items', array($this, 'getNavigationMenu'), 999);
47
-
48
- //add post filter for LIST restriction
49
- add_filter('the_posts', array($this, 'filterPostList'), 999);
50
- add_action('pre_get_posts', array($this, 'preparePostQuery'), 999);
51
  }
52
 
53
- //password protected filter
54
- add_filter('post_password_required', array($this, 'isPassProtected'), 10, 2);
55
- //manage password check expiration
56
- add_filter('post_password_expires', array($this, 'checkPassExpiration'));
57
-
58
  //widget filters
59
  add_filter('sidebars_widgets', array($this, 'filterWidgets'), 999);
60
 
61
  //get control over commenting stuff
62
  add_filter('comments_open', array($this, 'commentOpen'), 10, 2);
63
-
64
- //filter post content
65
- add_filter('the_content', array($this, 'filterPostContent'), 999);
66
-
67
- //REST API authorization
68
- add_filter('rest_request_before_callbacks', array($this, 'authRest'), 10, 3);
69
  }
70
 
71
  /**
@@ -101,34 +85,6 @@ class AAM_Frontend_Filter {
101
  }
102
  }
103
 
104
- /**
105
- *
106
- * @param type $response
107
- * @param type $handler
108
- * @param type $request
109
- * @return type
110
- */
111
- public function authRest($response, $handler, $request) {
112
- $auth = AAM_Frontend_Rest::bootstrap();
113
-
114
- foreach($auth->getRoutes() as $group => $routes) {
115
- foreach($routes as $regex) {
116
- // Route to work with single post
117
- if(preg_match('#^' . $regex . '$#i', $request->get_route())) {
118
- $response = apply_filters(
119
- 'aam-rest-auth-request-filter',
120
- $response,
121
- $group,
122
- $request,
123
- $handler
124
- );
125
- }
126
- }
127
- }
128
-
129
- return $response;
130
- }
131
-
132
  /**
133
  * Theme redirect
134
  *
@@ -154,33 +110,6 @@ class AAM_Frontend_Filter {
154
  return $template;
155
  }
156
 
157
- /**
158
- * Filter posts from the list
159
- *
160
- * @param array $posts
161
- *
162
- * @return array
163
- *
164
- * @access public
165
- */
166
- public function filterPostList($posts) {
167
- $current = AAM_Core_API::getCurrentPost();
168
-
169
- if (is_array($posts)) {
170
- foreach ($posts as $i => $post) {
171
- if ($current && ($current->ID == $post->ID)) { continue; }
172
-
173
- if (AAM_Core_API::isHiddenPost($post, $post->post_type)) {
174
- unset($posts[$i]);
175
- }
176
- }
177
-
178
- $posts = array_values($posts);
179
- }
180
-
181
- return $posts;
182
- }
183
-
184
  /**
185
  * Filter Navigation menu
186
  *
@@ -194,8 +123,11 @@ class AAM_Frontend_Filter {
194
  if (is_array($pages)) {
195
  foreach ($pages as $i => $page) {
196
  if (in_array($page->type, array('post_type', 'custom'))) {
197
- $post = get_post($page->object_id);
198
- if (AAM_Core_API::isHiddenPost($post, $post->post_type)) {
 
 
 
199
  unset($pages[$i]);
200
  }
201
  }
@@ -205,84 +137,6 @@ class AAM_Frontend_Filter {
205
  return $pages;
206
  }
207
 
208
- /**
209
- * Build pre-post query request
210
- *
211
- * This is used to solve the problem or pagination
212
- *
213
- * @param stdClass $query
214
- *
215
- * @return void
216
- *
217
- * @access public
218
- */
219
- public function preparePostQuery($query) {
220
- static $skip = false;
221
-
222
- if ($skip === false && !$this->isMainWP()) { // avoid loop
223
- $skip = true;
224
- $filtered = AAM_Core_API::getFilteredPostList($query);
225
- $skip = false;
226
-
227
- if (isset($query->query_vars['post__not_in'])
228
- && is_array($query->query_vars['post__not_in'])) {
229
- $query->query_vars['post__not_in'] = array_merge(
230
- $query->query_vars['post__not_in'], $filtered
231
- );
232
- } else {
233
- $query->query_vars['post__not_in'] = $filtered;
234
- }
235
- }
236
- }
237
-
238
- /**
239
- * Check if post is password protected
240
- *
241
- * @param boolean $res
242
- * @param WP_Post $post
243
- *
244
- * @return boolean
245
- *
246
- * @access public
247
- */
248
- public function isPassProtected($res, $post) {
249
- if (is_a($post, 'WP_Post')) {
250
- $object = AAM::getUser()->getObject('post', $post->ID);
251
-
252
- if ($object->has('frontend.protected')) {
253
- require_once( ABSPATH . 'wp-includes/class-phpass.php' );
254
- $hasher = new PasswordHash( 8, true );
255
- $pass = $object->get('frontend.password');
256
- $hash = wp_unslash(
257
- AAM_Core_Request::cookie('wp-postpass_' . COOKIEHASH)
258
- );
259
-
260
- $res = empty($hash) ? true : !$hasher->CheckPassword($pass, $hash);
261
- }
262
- }
263
-
264
- return $res;
265
- }
266
-
267
- /**
268
- * Get password expiration TTL
269
- *
270
- * @param int $expire
271
- *
272
- * @return int
273
- *
274
- * @access public
275
- */
276
- public function checkPassExpiration($expire) {
277
- $overwrite = AAM_Core_Config::get('post.password.expires', null);
278
-
279
- if ($overwrite !== null) {
280
- $expire = ($overwrite ? time() + strtotime($overwrite) : 0);
281
- }
282
-
283
- return $expire;
284
- }
285
-
286
  /**
287
  * Filter frontend widgets
288
  *
@@ -312,57 +166,6 @@ class AAM_Frontend_Filter {
312
  return ($object->has('frontend.comment') ? false : $open);
313
  }
314
 
315
- /**
316
- * Filter post content
317
- *
318
- * @param string $content
319
- *
320
- * @return string
321
- *
322
- * @access public
323
- * @global WP_Post $post
324
- */
325
- public function filterPostContent($content) {
326
- $post = AAM_Core_API::getCurrentPost();
327
-
328
- if ($post && $post->has('frontend.limit')) {
329
- if ($post->has('frontend.teaser')) {
330
- $message = $post->get('frontend.teaser');
331
- } else {
332
- $message = __('[No teaser message provided]', AAM_KEY);
333
- }
334
-
335
- $content = do_shortcode(stripslashes($message));
336
- }
337
-
338
- return $content;
339
- }
340
-
341
- /**
342
- * Check if request comes from wp()
343
- *
344
- * Super important method is used to solve the problem with hidden posts
345
- *
346
- * @return boolean
347
- *
348
- * @access protected
349
- */
350
- protected function isMainWP() {
351
- $result = false;
352
-
353
- foreach(debug_backtrace() as $level) {
354
- $class = (isset($level['class']) ? $level['class'] : null);
355
- $func = (isset($level['function']) ? $level['function'] : null);
356
-
357
- if ($class == 'WP' && $func == 'main') {
358
- $result = true;
359
- break;
360
- }
361
- }
362
-
363
- return $result;
364
- }
365
-
366
  /**
367
  * Register backend filters and actions
368
  *
42
  //important to keep this option optional for optimization reasons
43
  if (AAM_Core_Config::get('check-post-visibility', true)) {
44
  //filter navigation pages & taxonomies
 
45
  add_filter('wp_get_nav_menu_items', array($this, 'getNavigationMenu'), 999);
 
 
 
 
46
  }
47
 
 
 
 
 
 
48
  //widget filters
49
  add_filter('sidebars_widgets', array($this, 'filterWidgets'), 999);
50
 
51
  //get control over commenting stuff
52
  add_filter('comments_open', array($this, 'commentOpen'), 10, 2);
 
 
 
 
 
 
53
  }
54
 
55
  /**
85
  }
86
  }
87
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
  /**
89
  * Theme redirect
90
  *
110
  return $template;
111
  }
112
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
  /**
114
  * Filter Navigation menu
115
  *
123
  if (is_array($pages)) {
124
  foreach ($pages as $i => $page) {
125
  if (in_array($page->type, array('post_type', 'custom'))) {
126
+ $object = AAM::getUser()->getObject('post', $page->object_id);
127
+ $hidden = $object->get('frontend.hidden');
128
+ $list = $object->get('frontend.list');
129
+
130
+ if ($hidden || $list) {
131
  unset($pages[$i]);
132
  }
133
  }
137
  return $pages;
138
  }
139
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  /**
141
  * Filter frontend widgets
142
  *
166
  return ($object->has('frontend.comment') ? false : $open);
167
  }
168
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  /**
170
  * Register backend filters and actions
171
  *
Application/Frontend/Manager.php CHANGED
@@ -39,6 +39,9 @@ class AAM_Frontend_Manager {
39
  //manage AAM shortcode
40
  add_shortcode('aam', array($this, 'processShortcode'));
41
 
 
 
 
42
  //admin bar
43
  $this->checkAdminBar();
44
 
@@ -47,6 +50,11 @@ class AAM_Frontend_Manager {
47
  add_action('widgets_init', array($this, 'registerLoginWidget'));
48
  add_action('wp_enqueue_scripts', array($this, 'printJavascript'));
49
  }
 
 
 
 
 
50
  }
51
 
52
  /**
@@ -114,6 +122,54 @@ class AAM_Frontend_Manager {
114
  }
115
  }
116
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  /**
118
  * Bootstrap the manager
119
  *
39
  //manage AAM shortcode
40
  add_shortcode('aam', array($this, 'processShortcode'));
41
 
42
+ //cache clearing hook
43
+ add_action('aam-clear-cache-action', 'AAM_Core_API::clearCache');
44
+
45
  //admin bar
46
  $this->checkAdminBar();
47
 
50
  add_action('widgets_init', array($this, 'registerLoginWidget'));
51
  add_action('wp_enqueue_scripts', array($this, 'printJavascript'));
52
  }
53
+
54
+ //password protected filter
55
+ add_filter('post_password_required', array($this, 'isPassProtected'), 10, 2);
56
+ //manage password check expiration
57
+ add_filter('post_password_expires', array($this, 'checkPassExpiration'));
58
  }
59
 
60
  /**
122
  }
123
  }
124
 
125
+ /**
126
+ * Check if post is password protected
127
+ *
128
+ * @param boolean $res
129
+ * @param WP_Post $post
130
+ *
131
+ * @return boolean
132
+ *
133
+ * @access public
134
+ */
135
+ public function isPassProtected($res, $post) {
136
+ if (is_a($post, 'WP_Post')) {
137
+ $object = AAM::getUser()->getObject('post', $post->ID);
138
+
139
+ if ($object->has('frontend.protected')) {
140
+ require_once( ABSPATH . 'wp-includes/class-phpass.php' );
141
+ $hasher = new PasswordHash( 8, true );
142
+ $pass = $object->get('frontend.password');
143
+ $hash = wp_unslash(
144
+ AAM_Core_Request::cookie('wp-postpass_' . COOKIEHASH)
145
+ );
146
+
147
+ $res = empty($hash) ? true : !$hasher->CheckPassword($pass, $hash);
148
+ }
149
+ }
150
+
151
+ return $res;
152
+ }
153
+
154
+ /**
155
+ * Get password expiration TTL
156
+ *
157
+ * @param int $expire
158
+ *
159
+ * @return int
160
+ *
161
+ * @access public
162
+ */
163
+ public function checkPassExpiration($expire) {
164
+ $overwrite = AAM_Core_Config::get('post.password.expires', null);
165
+
166
+ if ($overwrite !== null) {
167
+ $expire = ($overwrite ? time() + strtotime($overwrite) : 0);
168
+ }
169
+
170
+ return $expire;
171
+ }
172
+
173
  /**
174
  * Bootstrap the manager
175
  *
Application/Shared/Manager.php ADDED
@@ -0,0 +1,424 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
10
+ /**
11
+ * AAM shared manager
12
+ *
13
+ * @package AAM
14
+ * @author Vasyl Martyniuk <vasyl@vasyltech.com>
15
+ */
16
+ class AAM_Shared_Manager {
17
+
18
+ /**
19
+ * Instance of itself
20
+ *
21
+ * @var AAM_Shared_Manager
22
+ *
23
+ * @access private
24
+ */
25
+ private static $_instance = null;
26
+
27
+ /**
28
+ * Constructor
29
+ *
30
+ * @access protected
31
+ *
32
+ * @return void
33
+ */
34
+ protected function __construct() {}
35
+
36
+ /**
37
+ * Initialize core hooks
38
+ *
39
+ * @return void
40
+ *
41
+ * @access public
42
+ */
43
+ public static function bootstrap() {
44
+ if (is_null(self::$_instance)) {
45
+ self::$_instance = new self;
46
+
47
+ // Disable XML-RPC if needed
48
+ if (!AAM_Core_Config::get('core.xmlrpc', true)) {
49
+ add_filter('xmlrpc_enabled', '__return_false');
50
+ }
51
+
52
+ // Disable RESTful API if needed
53
+ if (!AAM_Core_Config::get('core.restful', true)) {
54
+ add_filter(
55
+ 'rest_authentication_errors',
56
+ array(self::$_instance, 'disableRest'),
57
+ 1
58
+ );
59
+ }
60
+
61
+ // Control post visibility
62
+ //important to keep this option optional for optimization reasons
63
+ if (AAM_Core_Config::get('check-post-visibility', true)) {
64
+ // filter navigation pages & taxonomies
65
+ add_filter('get_pages', array(self::$_instance, 'filterPostList'), 999);
66
+ // add post filter for LIST restriction
67
+ add_filter('the_posts', array(self::$_instance, 'filterPostList'), 999);
68
+ // pre post query builder
69
+ add_action('pre_get_posts', array(self::$_instance, 'preparePostQuery'), 999);
70
+ }
71
+
72
+ //filter post content
73
+ add_filter('the_content', array(self::$_instance, 'filterPostContent'), 999);
74
+ }
75
+
76
+ return self::$_instance;
77
+ }
78
+
79
+ /**
80
+ * Disable REST API
81
+ *
82
+ * @param WP_Error|null|bool $response
83
+ *
84
+ * @return \WP_Error
85
+ *
86
+ * @access public
87
+ */
88
+ public function disableRest($response) {
89
+ if (!is_wp_error($response)) {
90
+ $response = new WP_Error(
91
+ 'rest_access_disabled',
92
+ __('RESTful API is disabled', AAM_KEY),
93
+ array('status' => 403)
94
+ );
95
+ }
96
+
97
+ return $response;
98
+ }
99
+
100
+ /**
101
+ * Check user capability
102
+ *
103
+ * This is a hack function that add additional layout on top of WordPress
104
+ * core functionality. Based on the capability passed in the $args array as
105
+ * "0" element, it performs additional check on user's capability to manage
106
+ * post, users etc.
107
+ *
108
+ * @param array $caps
109
+ * @param array $meta
110
+ * @param array $args
111
+ *
112
+ * @return array
113
+ *
114
+ * @access public
115
+ */
116
+ public function userHasCap($caps, $meta, $args) {
117
+ $capability = (isset($args[0]) && is_string($args[0]) ? $args[0] : '');
118
+ $uid = (isset($args[2]) && is_numeric($args[2]) ? $args[2] : 0);
119
+
120
+ switch($capability) {
121
+ case 'edit_user':
122
+ case 'delete_user':
123
+ $caps = $this->authorizeUserUpdate($uid, $caps, $meta);
124
+ break;
125
+
126
+ case 'edit_post':
127
+ $caps = $this->authorizePostEdit($uid, $caps, $meta);
128
+ break;
129
+
130
+ case 'delete_post':
131
+ $caps = $this->authorizePostDelete($uid, $caps, $meta);
132
+ break;
133
+
134
+ case 'publish_posts':
135
+ case 'publish_pages':
136
+ $caps = $this->authorizePublishPost($caps, $meta);
137
+ break;
138
+
139
+ default:
140
+ break;
141
+ }
142
+
143
+ return $caps;
144
+ }
145
+
146
+ /**
147
+ * Filter posts from the list
148
+ *
149
+ * @param array $posts
150
+ *
151
+ * @return array
152
+ *
153
+ * @access public
154
+ */
155
+ public function filterPostList($posts) {
156
+ $current = AAM_Core_API::getCurrentPost();
157
+
158
+ if (is_array($posts)) {
159
+ $area = AAM_Core_Api_Area::get();
160
+
161
+ foreach ($posts as $i => $post) {
162
+ if ($current && ($current->ID == $post->ID)) { continue; }
163
+
164
+ // TODO: refactor this to AAM API standalone
165
+ $object = AAM::getUser()->getObject('post', $post->ID);
166
+ $hidden = $object->get($area. '.hidden');
167
+ $list = $object->get($area. '.list');
168
+
169
+ if ($hidden || $list) {
170
+ unset($posts[$i]);
171
+ }
172
+ }
173
+
174
+ $posts = array_values($posts);
175
+ }
176
+
177
+ return $posts;
178
+ }
179
+
180
+ /**
181
+ * Build pre-post query request
182
+ *
183
+ * This is used to solve the problem or pagination
184
+ *
185
+ * @param stdClass $query
186
+ *
187
+ * @return void
188
+ *
189
+ * @access public
190
+ */
191
+ public function preparePostQuery($query) {
192
+ static $skip = false;
193
+
194
+ if ($skip === false) { // avoid loop
195
+ $skip = true;
196
+ // TODO: refactor this to AAM API standalone
197
+ $filtered = AAM_Core_API::getFilteredPostList($query);
198
+ $skip = false;
199
+
200
+ if (isset($query->query_vars['post__not_in'])
201
+ && is_array($query->query_vars['post__not_in'])) {
202
+ $query->query_vars['post__not_in'] = array_merge(
203
+ $query->query_vars['post__not_in'], $filtered
204
+ );
205
+ } else {
206
+ $query->query_vars['post__not_in'] = $filtered;
207
+ }
208
+ }
209
+ }
210
+
211
+ /**
212
+ * Filter pages fields
213
+ *
214
+ * @param string $fields
215
+ * @param WP_Query $query
216
+ *
217
+ * @return string
218
+ *
219
+ * @access public
220
+ * @global WPDB $wpdb
221
+ */
222
+ public function fieldsRequest($fields, $query) {
223
+ global $wpdb;
224
+
225
+ $qfields = (isset($query->query['fields']) ? $query->query['fields'] : '');
226
+
227
+ if ($qfields == 'id=>parent') {
228
+ $author = "{$wpdb->posts}.post_author";
229
+ if (strpos($fields, $author) === false) {
230
+ $fields .= ", $author";
231
+ }
232
+
233
+ $status = "{$wpdb->posts}.post_status";
234
+ if (strpos($fields, $status) === false) {
235
+ $fields .= ", $status";
236
+ }
237
+
238
+ $type = "{$wpdb->posts}.post_type";
239
+ if (strpos($fields, $type) === false) {
240
+ $fields .= ", $type";
241
+ }
242
+ }
243
+
244
+ return $fields;
245
+ }
246
+
247
+ /**
248
+ * Filter post content
249
+ *
250
+ * @param string $content
251
+ *
252
+ * @return string
253
+ *
254
+ * @access public
255
+ * @global WP_Post $post
256
+ */
257
+ public function filterPostContent($content) {
258
+ $post = AAM_Core_API::getCurrentPost();
259
+ $area = AAM_Core_Api_Area::get();
260
+
261
+ if ($post && $post->has($area . '.limit')) {
262
+ if ($post->has($area . '.teaser')) {
263
+ $message = $post->get($area . '.teaser');
264
+ } else {
265
+ $message = __('[No teaser message provided]', AAM_KEY);
266
+ }
267
+
268
+ $content = do_shortcode(stripslashes($message));
269
+ }
270
+
271
+ return $content;
272
+ }
273
+
274
+ /**
275
+ * Check if current user is allowed to manager specified user
276
+ *
277
+ * @param int $id
278
+ * @param array $allcaps
279
+ * @param array $metacaps
280
+ *
281
+ * @return array
282
+ *
283
+ * @access protected
284
+ */
285
+ protected function authorizeUserUpdate($id, $allcaps, $metacaps) {
286
+ $user = new WP_User($id);
287
+
288
+ //current user max level
289
+ $maxLevel = AAM_Core_API::maxLevel(AAM::getUser()->allcaps);
290
+ //userLevel
291
+ $userLevel = AAM_Core_API::maxLevel($user->allcaps);
292
+
293
+ if ($maxLevel < $userLevel) {
294
+ $allcaps = $this->restrictCapabilities($allcaps, $metacaps);
295
+ }
296
+
297
+ return $allcaps;
298
+ }
299
+
300
+ /**
301
+ * Check if current user is allowed to edit post
302
+ *
303
+ * @param int $id
304
+ * @param array $allcaps
305
+ * @param array $metacaps
306
+ *
307
+ * @return array
308
+ *
309
+ * @access protected
310
+ */
311
+ protected function authorizePostEdit($id, $allcaps, $metacaps) {
312
+ $object = AAM::getUser()->getObject('post', $id);
313
+ $draft = $object->post_status == 'auto-draft';
314
+ $area = AAM_Core_Api_Area::get();
315
+
316
+ if (!$draft && !$this->isActionAllowed($area . '.edit', $object)) {
317
+ $allcaps = $this->restrictCapabilities($allcaps, $metacaps);
318
+ }
319
+
320
+ return $allcaps;
321
+ }
322
+
323
+ /**
324
+ * Check if current user is allowed to delete post
325
+ *
326
+ * @param int $id
327
+ * @param array $allcaps
328
+ * @param array $metacaps
329
+ *
330
+ * @return array
331
+ *
332
+ * @access protected
333
+ */
334
+ protected function authorizePostDelete($id, $allcaps, $metacaps) {
335
+ $object = AAM::getUser()->getObject('post', $id);
336
+ $area = AAM_Core_Api_Area::get();
337
+
338
+ if (!$this->isActionAllowed($area . '.delete', $object)) {
339
+ $allcaps = $this->restrictCapabilities($allcaps, $metacaps);
340
+ }
341
+
342
+ return $allcaps;
343
+ }
344
+
345
+ /**
346
+ * Check if user is allowed to publish post
347
+ *
348
+ * @param array $allcaps
349
+ * @param array $metacaps
350
+ *
351
+ * @return array
352
+ *
353
+ * @access protected
354
+ * @global WP_Post $post
355
+ */
356
+ protected function authorizePublishPost($allcaps, $metacaps) {
357
+ global $post;
358
+
359
+ if (is_a($post, 'WP_Post')) {
360
+ $object = AAM::getUser()->getObject('post', $post->ID);
361
+ $area = AAM_Core_Api_Area::get();
362
+
363
+ if (!$this->isActionAllowed($area . '.publish', $object)) {
364
+ $allcaps = $this->restrictCapabilities($allcaps, $metacaps);
365
+ }
366
+ }
367
+
368
+ return $allcaps;
369
+ }
370
+
371
+ /**
372
+ * Check if action is allowed
373
+ *
374
+ * This method will take in consideration also *_others action
375
+ *
376
+ * @param string $action
377
+ * @param AAM_Core_Object_Post $object
378
+ *
379
+ * @return boolean
380
+ *
381
+ * @access protected
382
+ */
383
+ protected function isActionAllowed($action, $object) {
384
+ $edit = $object->has($action);
385
+ $others = $object->has("{$action}_others");
386
+ $author = ($object->post_author == get_current_user_id());
387
+
388
+ return ($edit || ($others && !$author)) ? false : true;
389
+ }
390
+
391
+ /**
392
+ * Restrict user capabilities
393
+ *
394
+ * Iterate through the list of meta capabilities and disable them in the
395
+ * list of all user capabilities. Keep in mind that this disable caps only
396
+ * for one time call.
397
+ *
398
+ * @param array $allCaps
399
+ * @param array $metaCaps
400
+ *
401
+ * @return array
402
+ *
403
+ * @access protected
404
+ */
405
+ protected function restrictCapabilities($allCaps, $metaCaps) {
406
+ foreach($metaCaps as $cap) {
407
+ $allCaps[$cap] = false;
408
+ }
409
+
410
+ return $allCaps;
411
+ }
412
+
413
+ /**
414
+ *
415
+ * @return type
416
+ */
417
+ public static function getInstance() {
418
+ if (is_null(self::$_instance)) {
419
+ self::$_instance = self::bootstrap();
420
+ }
421
+
422
+ return self::$_instance;
423
+ }
424
+ }
Lang/advanced-access-manager-en_US.po CHANGED
@@ -204,7 +204,7 @@ msgstr ""
204
  #, php-format
205
  msgid ""
206
  "[Note!] PHP 5.4 or higher is required for this feature. Enable the ability "
207
- "to authenticate user with WordPress RESTfull API and JWT token. For more "
208
  "information, check %sHow to authenticate WordPress user with JWT token%s "
209
  "article"
210
  msgstr ""
204
  #, php-format
205
  msgid ""
206
  "[Note!] PHP 5.4 or higher is required for this feature. Enable the ability "
207
+ "to authenticate user with WordPress RESTful API and JWT token. For more "
208
  "information, check %sHow to authenticate WordPress user with JWT token%s "
209
  "article"
210
  msgstr ""
Lang/advanced-access-manager.pot CHANGED
@@ -205,7 +205,7 @@ msgstr ""
205
  #, php-format
206
  msgid ""
207
  "[Note!] PHP 5.4 or higher is required for this feature. Enable the ability "
208
- "to authenticate user with WordPress RESTfull API and JWT token. For more "
209
  "information, check %sHow to authenticate WordPress user with JWT token%s "
210
  "article"
211
  msgstr ""
205
  #, php-format
206
  msgid ""
207
  "[Note!] PHP 5.4 or higher is required for this feature. Enable the ability "
208
+ "to authenticate user with WordPress RESTful API and JWT token. For more "
209
  "information, check %sHow to authenticate WordPress user with JWT token%s "
210
  "article"
211
  msgstr ""
aam.php CHANGED
@@ -3,7 +3,7 @@
3
  /**
4
  Plugin Name: Advanced Access Manager
5
  Description: All you need to manage access to your WordPress website
6
- Version: 5.2.7
7
  Author: Vasyl Martyniuk <vasyl@vasyltech.com>
8
  Author URI: https://vasyltech.com
9
 
@@ -109,7 +109,7 @@ class AAM {
109
  AAM_Core_Config::bootstrap();
110
 
111
  //load WP Core hooks
112
- AAM_Core_Wp::bootstrap();
113
 
114
  //login control
115
  if (AAM_Core_Config::get('secure-login', true)) {
@@ -138,9 +138,6 @@ class AAM {
138
  );
139
  self::$_instance = new self;
140
 
141
- //load AAM cache
142
- AAM_Core_Cache::bootstrap();
143
-
144
  //load all installed extension
145
  AAM_Extension_Repository::getInstance()->load();
146
 
@@ -148,9 +145,9 @@ class AAM {
148
  AAM_Core_Media::bootstrap();
149
 
150
  //bootstrap the correct interface
151
- if (is_admin()) {
152
  AAM_Backend_Manager::bootstrap();
153
- } else {
154
  AAM_Frontend_Manager::bootstrap();
155
  }
156
  }
@@ -241,6 +238,9 @@ if (defined('ABSPATH')) {
241
  //this is important to have to catch events like register core post types
242
  add_action('init', 'AAM::getInstance', -1);
243
 
 
 
 
244
  //schedule cron
245
  if (!wp_next_scheduled('aam-cron')) {
246
  wp_schedule_event(time(), 'daily', 'aam-cron');
3
  /**
4
  Plugin Name: Advanced Access Manager
5
  Description: All you need to manage access to your WordPress website
6
+ Version: 5.3
7
  Author: Vasyl Martyniuk <vasyl@vasyltech.com>
8
  Author URI: https://vasyltech.com
9
 
109
  AAM_Core_Config::bootstrap();
110
 
111
  //load WP Core hooks
112
+ AAM_Shared_Manager::bootstrap();
113
 
114
  //login control
115
  if (AAM_Core_Config::get('secure-login', true)) {
138
  );
139
  self::$_instance = new self;
140
 
 
 
 
141
  //load all installed extension
142
  AAM_Extension_Repository::getInstance()->load();
143
 
145
  AAM_Core_Media::bootstrap();
146
 
147
  //bootstrap the correct interface
148
+ if (AAM_Core_Api_Area::isBackend()) {
149
  AAM_Backend_Manager::bootstrap();
150
+ } elseif (AAM_Core_Api_Area::isFrontend()) {
151
  AAM_Frontend_Manager::bootstrap();
152
  }
153
  }
238
  //this is important to have to catch events like register core post types
239
  add_action('init', 'AAM::getInstance', -1);
240
 
241
+ //register API manager is applicable
242
+ add_action('parse_request', 'AAM_Api_Manager::bootstrap', 1);
243
+
244
  //schedule cron
245
  if (!wp_next_scheduled('aam-cron')) {
246
  wp_schedule_event(time(), 'daily', 'aam-cron');
media/css/aam.css CHANGED
@@ -361,6 +361,11 @@ a.btn:focus, a.btn:active {
361
  margin-bottom: 10px;
362
  }
363
 
 
 
 
 
 
364
  .btn-right::after {
365
  display: block;
366
  content: " ";
@@ -434,6 +439,7 @@ div.dataTables_wrapper div.dataTables_filter {
434
 
435
  #capability-list_wrapper div.dataTables_filter,
436
  #route-list_wrapper div.dataTables_filter,
 
437
  #post-list_wrapper div.dataTables_filter {
438
  text-align: right;
439
  }
361
  margin-bottom: 10px;
362
  }
363
 
364
+ .aam-clear {
365
+ clear: both !important;
366
+ display:block;
367
+ }
368
+
369
  .btn-right::after {
370
  display: block;
371
  content: " ";
439
 
440
  #capability-list_wrapper div.dataTables_filter,
441
  #route-list_wrapper div.dataTables_filter,
442
+ #eproduct-list_wrapper div.dataTables_filter,
443
  #post-list_wrapper div.dataTables_filter {
444
  text-align: right;
445
  }
media/js/aam.js CHANGED
@@ -185,7 +185,14 @@
185
  'class', 'aam-row-action icon-cog text-muted'
186
  );
187
  } else {
188
- $.aam.loadAccessForm($('#load-post-object-type').val(), $('#load-post-object').val(), $(this));
 
 
 
 
 
 
 
189
  }
190
  }
191
  }).attr({
@@ -485,6 +492,41 @@
485
 
486
  return (subject.type === 'user' && parseInt(subject.id) === id);
487
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
488
 
489
  /**
490
  *
@@ -645,7 +687,14 @@
645
  aam.fetchContent('main');
646
  $('i.icon-spin4', container).attr('class', 'aam-row-action icon-cog text-muted');
647
  } else {
648
- $.aam.loadAccessForm($('#load-post-object-type').val(), $('#load-post-object').val(), $(this));
 
 
 
 
 
 
 
649
  }
650
  }
651
  }).attr({
@@ -667,9 +716,18 @@
667
  var settings = data[5].split('|');
668
  $('#user-expires').val(settings[0]);
669
  $('#action-after-expiration').val(settings[1]);
 
 
 
 
 
 
 
 
670
  } else {
671
  $('#reset-user-expiration-btn').addClass('hidden');
672
  $('#user-expires, #action-after-expiration').val('');
 
673
  }
674
 
675
  $('#edit-user-expiration-modal').modal('show');
@@ -747,6 +805,14 @@
747
  }
748
  });
749
 
 
 
 
 
 
 
 
 
750
  //edit role button
751
  $('#edit-user-expiration-btn').bind('click', function () {
752
  var _this = this;
@@ -760,7 +826,8 @@
760
  _ajax_nonce: aamLocal.nonce,
761
  user: $(_this).attr('data-user-id'),
762
  expires: $('#user-expires').val(),
763
- after: $('#action-after-expiration').val()
 
764
  },
765
  beforeSend: function () {
766
  $(_this).text(aam.__('Saving...')).attr('disabled', true);
@@ -858,8 +925,16 @@
858
  aam.fetchContent('main');
859
  $('i.icon-spin4', $(this)).attr('class', 'icon-cog');
860
  } else {
861
- $.aam.loadAccessForm($('#load-post-object-type').val(), $('#load-post-object').val(), null, function () {
862
- $('i.icon-spin4', $(_this)).attr('class', 'icon-cog');
 
 
 
 
 
 
 
 
863
  });
864
  }
865
  //hide post & pages access control groups that belong to backend
@@ -888,8 +963,16 @@
888
  aam.fetchContent('main');
889
  $('i.icon-spin4', $(this)).attr('class', 'icon-cog');
890
  } else {
891
- $.aam.loadAccessForm($('#load-post-object-type').val(), $('#load-post-object').val(), null, function () {
892
- $('i.icon-spin4', $(_this)).attr('class', 'icon-cog');
 
 
 
 
 
 
 
 
893
  });
894
  }
895
  });
@@ -1551,7 +1634,7 @@
1551
 
1552
  //show overlay if present
1553
  $('.aam-overlay', container).show();
1554
-
1555
  //reset data preview elements
1556
  $('.option-preview', container).text('');
1557
 
@@ -2870,7 +2953,7 @@
2870
  *
2871
  * @returns {undefined}
2872
  */
2873
- AAM.prototype.fetchContent = function (uiType) {
2874
  var _this = this;
2875
 
2876
  //referred object ID like post, page or any custom post type
@@ -2883,7 +2966,7 @@
2883
  data: {
2884
  action: 'aamc',
2885
  _ajax_nonce: aamLocal.nonce,
2886
- uiType: uiType,
2887
  subject: this.getSubject().type,
2888
  subjectId: this.getSubject().id,
2889
  oid: object ? object[1] : null,
@@ -2917,13 +3000,47 @@
2917
 
2918
  $('.aam-sidebar .metabox-holder').hide();
2919
  $('.aam-sidebar .shared-metabox').show();
2920
- $('.aam-sidebar .' + uiType + '-metabox').show();
2921
 
2922
- if (uiType !== 'main') { //hide subject and user/role manager
2923
  $('#aam-subject-banner').hide();
2924
  } else {
2925
  $('#aam-subject-banner').show();
2926
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2927
  }
2928
  });
2929
  };
185
  'class', 'aam-row-action icon-cog text-muted'
186
  );
187
  } else {
188
+ aam.fetchPartial('postform', function(content) {
189
+ $('#metabox-post-access-form').html(content);
190
+ $.aam.loadAccessForm(
191
+ $('#load-post-object-type').val(),
192
+ $('#load-post-object').val(),
193
+ $(this)
194
+ );
195
+ });
196
  }
197
  }
198
  }).attr({
492
 
493
  return (subject.type === 'user' && parseInt(subject.id) === id);
494
  }
495
+
496
+ /**
497
+ *
498
+ * @param {type} selected
499
+ * @returns {undefined}
500
+ */
501
+ function loadRoleList(selected) {
502
+ console.log(selected);
503
+ $.ajax(aamLocal.ajaxurl, {
504
+ type: 'POST',
505
+ dataType: 'json',
506
+ data: {
507
+ action: 'aam',
508
+ sub_action: 'Subject_Role.getList',
509
+ _ajax_nonce: aamLocal.nonce
510
+ },
511
+ beforeSend: function () {
512
+ $('#expiration-change-role').html(
513
+ '<option value="">' + aam.__('Loading...') + '</option>'
514
+ );
515
+ },
516
+ success: function (response) {
517
+ $('#expiration-change-role').html(
518
+ '<option value="">' + aam.__('Select Role') + '</option>'
519
+ );
520
+ for (var i in response) {
521
+ $('#expiration-change-role').append(
522
+ '<option value="' + i + '">' + response[i].name + '</option>'
523
+ );
524
+ }
525
+
526
+ $('#expiration-change-role').val(selected);
527
+ }
528
+ });
529
+ }
530
 
531
  /**
532
  *
687
  aam.fetchContent('main');
688
  $('i.icon-spin4', container).attr('class', 'aam-row-action icon-cog text-muted');
689
  } else {
690
+ aam.fetchPartial('postform', function(content) {
691
+ $('#metabox-post-access-form').html(content);
692
+ $.aam.loadAccessForm(
693
+ $('#load-post-object-type').val(),
694
+ $('#load-post-object').val(),
695
+ $(this)
696
+ );
697
+ });
698
  }
699
  }
700
  }).attr({
716
  var settings = data[5].split('|');
717
  $('#user-expires').val(settings[0]);
718
  $('#action-after-expiration').val(settings[1]);
719
+
720
+ if (settings[1] === 'change-role') {
721
+ $('#expiration-change-role-holder').removeClass('hidden');
722
+ loadRoleList(settings[2]);
723
+ } else {
724
+ loadRoleList();
725
+ $('#expiration-change-role-holder').addClass('hidden');
726
+ }
727
  } else {
728
  $('#reset-user-expiration-btn').addClass('hidden');
729
  $('#user-expires, #action-after-expiration').val('');
730
+ loadRoleList();
731
  }
732
 
733
  $('#edit-user-expiration-modal').modal('show');
805
  }
806
  });
807
 
808
+ $('#action-after-expiration').bind('change', function() {
809
+ if ($(this).val() === 'change-role') {
810
+ $('#expiration-change-role-holder').removeClass('hidden');
811
+ } else {
812
+ $('#expiration-change-role-holder').addClass('hidden');
813
+ }
814
+ });
815
+
816
  //edit role button
817
  $('#edit-user-expiration-btn').bind('click', function () {
818
  var _this = this;
826
  _ajax_nonce: aamLocal.nonce,
827
  user: $(_this).attr('data-user-id'),
828
  expires: $('#user-expires').val(),
829
+ after: $('#action-after-expiration').val(),
830
+ role: $('#expiration-change-role').val()
831
  },
832
  beforeSend: function () {
833
  $(_this).text(aam.__('Saving...')).attr('disabled', true);
925
  aam.fetchContent('main');
926
  $('i.icon-spin4', $(this)).attr('class', 'icon-cog');
927
  } else {
928
+ aam.fetchPartial('postform', function(content) {
929
+ $('#metabox-post-access-form').html(content);
930
+ $.aam.loadAccessForm(
931
+ $('#load-post-object-type').val(),
932
+ $('#load-post-object').val(),
933
+ null,
934
+ function () {
935
+ $('i.icon-spin4', $(_this)).attr('class', 'icon-cog');
936
+ }
937
+ );
938
  });
939
  }
940
  //hide post & pages access control groups that belong to backend
963
  aam.fetchContent('main');
964
  $('i.icon-spin4', $(this)).attr('class', 'icon-cog');
965
  } else {
966
+ aam.fetchPartial('postform', function(content) {
967
+ $('#metabox-post-access-form').html(content);
968
+ $.aam.loadAccessForm(
969
+ $('#load-post-object-type').val(),
970
+ $('#load-post-object').val(),
971
+ null,
972
+ function () {
973
+ $('i.icon-spin4', $(_this)).attr('class', 'icon-cog');
974
+ }
975
+ );
976
  });
977
  }
978
  });
1634
 
1635
  //show overlay if present
1636
  $('.aam-overlay', container).show();
1637
+
1638
  //reset data preview elements
1639
  $('.option-preview', container).text('');
1640
 
2953
  *
2954
  * @returns {undefined}
2955
  */
2956
+ AAM.prototype.fetchContent = function (view, success) {
2957
  var _this = this;
2958
 
2959
  //referred object ID like post, page or any custom post type
2966
  data: {
2967
  action: 'aamc',
2968
  _ajax_nonce: aamLocal.nonce,
2969
+ uiType: view,
2970
  subject: this.getSubject().type,
2971
  subjectId: this.getSubject().id,
2972
  oid: object ? object[1] : null,
3000
 
3001
  $('.aam-sidebar .metabox-holder').hide();
3002
  $('.aam-sidebar .shared-metabox').show();
3003
+ $('.aam-sidebar .' + view + '-metabox').show();
3004
 
3005
+ if (view !== 'main') { //hide subject and user/role manager
3006
  $('#aam-subject-banner').hide();
3007
  } else {
3008
  $('#aam-subject-banner').show();
3009
  }
3010
+
3011
+ if (typeof success === 'function') {
3012
+ // success.call();
3013
+ }
3014
+ }
3015
+ });
3016
+ };
3017
+
3018
+
3019
+ /**
3020
+ *
3021
+ * @returns {undefined}
3022
+ */
3023
+ AAM.prototype.fetchPartial = function (view, success) {
3024
+ var _this = this;
3025
+
3026
+ //referred object ID like post, page or any custom post type
3027
+ var object = window.location.search.match(/&oid\=([^&]*)/);
3028
+ var type = window.location.search.match(/&otype\=([^&]*)/);
3029
+
3030
+ $.ajax(aamLocal.url.site, {
3031
+ type: 'POST',
3032
+ dataType: 'html',
3033
+ data: {
3034
+ action: 'aamc',
3035
+ _ajax_nonce: aamLocal.nonce,
3036
+ uiType: view,
3037
+ subject: this.getSubject().type,
3038
+ subjectId: this.getSubject().id,
3039
+ oid: object ? object[1] : null,
3040
+ otype: type ? type[1] : null
3041
+ },
3042
+ success: function (response) {
3043
+ success.call(_this, response);
3044
  }
3045
  });
3046
  };
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: vasyltech
3
  Tags: access, role, user, capability, page access, post access, content access, comments, security, login redirect, membership, backend lockdown, wp-admin, 404, rest api, xml rpc
4
  Requires at least: 4.0
5
- Tested up to: 4.9.5
6
- Stable tag: 5.2.7
7
 
8
  The most powerful access management plugin for WordPress websites.
9
 
@@ -66,6 +66,18 @@ https://www.youtube.com/watch?v=yiOhjaacNJc
66
 
67
  == Changelog ==
68
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  = 5.2.7 =
70
  * Fixed bug with REST API Routes list
71
  * Improved REST API response messages
2
  Contributors: vasyltech
3
  Tags: access, role, user, capability, page access, post access, content access, comments, security, login redirect, membership, backend lockdown, wp-admin, 404, rest api, xml rpc
4
  Requires at least: 4.0
5
+ Tested up to: 4.9.6
6
+ Stable tag: 5.3
7
 
8
  The most powerful access management plugin for WordPress websites.
9
 
66
 
67
  == Changelog ==
68
 
69
+ = 5.3 =
70
+ * Fixed the bug with ConfigPress settings when array is defined
71
+ * Fixed the bug with jwt authentication
72
+ * Fixed the bug with infinite logout loop when user is locked
73
+ * Refactored internal functionality to make it fully compatible with WP REST API
74
+ * Split Posts & Pages access control on Backend, Frontend and API sections
75
+ * Cleaned up posts and pages access settings
76
+ * Refactored internal AAM cache to make it more flexible and faster
77
+ * Added "API Access Control" option
78
+ * Added ability to change user role after certain period of time
79
+ * Removed ability to lock Dashboard menu
80
+
81
  = 5.2.7 =
82
  * Fixed bug with REST API Routes list
83
  * Improved REST API response messages