Advanced Access Manager - Version 4.8

Version Description

  • Fixed the bug with Media access control reported by Antonius Hegyes
  • Fixed the bug with post access properties preview
  • Fixed the bug with permanent redirects cached by some browsers
  • Fixed the bug with PasswordHash fatal error
  • Added ability to define teaser message for an individual post or category
  • Deprecated Content Teaser tab (will be removed in AAM 5.0)
  • Extended [aam context="content"] shortcode to filter content based on IP address
  • Added ability to set time expiration for roles
Download this release

Release Info

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

Code changes from version 4.7.6 to 4.8

Application/Backend/Feature/Post.php CHANGED
@@ -327,7 +327,7 @@ class AAM_Backend_Feature_Post extends AAM_Backend_Feature_Abstract {
327
  //prepare the response object
328
  if (is_a($object, 'AAM_Core_Object')) {
329
  foreach($object->getOption() as $key => $value) {
330
- if (is_numeric($value) || is_bool($value)) {
331
  $access[$key] = ($value ? 1 : 0); //TODO - to support legacy
332
  } else {
333
  $access[$key] = $value;
327
  //prepare the response object
328
  if (is_a($object, 'AAM_Core_Object')) {
329
  foreach($object->getOption() as $key => $value) {
330
+ if (is_bool($value) || in_array($value, array('0', '1'))) {
331
  $access[$key] = ($value ? 1 : 0); //TODO - to support legacy
332
  } else {
333
  $access[$key] = $value;
Application/Backend/Feature/Role.php CHANGED
@@ -51,7 +51,8 @@ class AAM_Backend_Feature_Role {
51
  implode(',', $this->prepareRowActions($uc)),
52
  $data
53
  ),
54
- AAM_Core_API::maxLevel($data['capabilities'])
 
55
  );
56
  }
57
  } else {
@@ -135,6 +136,7 @@ class AAM_Backend_Feature_Role {
135
 
136
  if (AAM_Backend_View::userCan('aam_create_roles')) {
137
  $name = sanitize_text_field(filter_input(INPUT_POST, 'name'));
 
138
  $roles = AAM_Core_API::getRoles();
139
  $role_id = strtolower($name);
140
 
@@ -151,9 +153,18 @@ class AAM_Backend_Feature_Role {
151
  'level' => AAM_Core_API::maxLevel($caps)
152
  )
153
  );
 
154
  if (AAM_Core_Request::post('clone')) {
155
  $this->cloneSettings($role, $parent);
156
  }
 
 
 
 
 
 
 
 
157
  do_action('aam-post-add-role-action', $role, $parent);
158
  }
159
  }
@@ -205,6 +216,16 @@ class AAM_Backend_Feature_Role {
205
  if (AAM_Backend_View::userCan('aam_edit_roles')) {
206
  $role = AAM_Backend_View::getSubject();
207
  $role->update(trim(filter_input(INPUT_POST, 'name')));
 
 
 
 
 
 
 
 
 
 
208
 
209
  do_action('aam-post-update-role-action', $role);
210
 
51
  implode(',', $this->prepareRowActions($uc)),
52
  $data
53
  ),
54
+ AAM_Core_API::maxLevel($data['capabilities']),
55
+ AAM_Core_API::getOption("aam-role-{$id}-expiration", '')
56
  );
57
  }
58
  } else {
136
 
137
  if (AAM_Backend_View::userCan('aam_create_roles')) {
138
  $name = sanitize_text_field(filter_input(INPUT_POST, 'name'));
139
+ $expire = filter_input(INPUT_POST, 'expire');
140
  $roles = AAM_Core_API::getRoles();
141
  $role_id = strtolower($name);
142
 
153
  'level' => AAM_Core_API::maxLevel($caps)
154
  )
155
  );
156
+ //clone settings if needed
157
  if (AAM_Core_Request::post('clone')) {
158
  $this->cloneSettings($role, $parent);
159
  }
160
+
161
+ //save expiration rule if set
162
+ if ($expire) {
163
+ AAM_Core_API::updateOption("aam-role-{$role_id}-expiration", $expire);
164
+ } else {
165
+ AAM_Core_API::deleteOption("aam-role-{$role_id}-expiration");
166
+ }
167
+
168
  do_action('aam-post-add-role-action', $role, $parent);
169
  }
170
  }
216
  if (AAM_Backend_View::userCan('aam_edit_roles')) {
217
  $role = AAM_Backend_View::getSubject();
218
  $role->update(trim(filter_input(INPUT_POST, 'name')));
219
+
220
+ $expire = filter_input(INPUT_POST, 'expire');
221
+ //save expiration rule if set
222
+ if ($expire) {
223
+ AAM_Core_API::updateOption(
224
+ 'aam-role-' . $role->getId() .'-expiration', $expire
225
+ );
226
+ } else {
227
+ AAM_Core_API::deleteOption('aam-role-' . $role->getId() .'-expiration');
228
+ }
229
 
230
  do_action('aam-post-update-role-action', $role);
231
 
Application/Backend/Filter.php CHANGED
@@ -102,6 +102,15 @@ class AAM_Backend_Filter {
102
  //role changed?
103
  if (implode('', $user->roles) != implode('', $old->roles)) {
104
  AAM_Core_Cache::clear($id);
 
 
 
 
 
 
 
 
 
105
  }
106
  }
107
 
102
  //role changed?
103
  if (implode('', $user->roles) != implode('', $old->roles)) {
104
  AAM_Core_Cache::clear($id);
105
+
106
+ //check if role has expiration data set
107
+ $role = (is_array($user->roles) ? $user->roles[0] : '');
108
+ $expire = AAM_Core_API::getOption("aam-role-{$role}-expiration", '');
109
+
110
+ if ($expire) {
111
+ update_user_option($id, "aam-original-roles", $old->roles);
112
+ update_user_option($id, "aam-role-expires", strtotime($expire));
113
+ }
114
  }
115
  }
116
 
Application/Backend/View/PostOptionList.php CHANGED
@@ -27,7 +27,8 @@ return array(
27
  ),
28
  'limit' => array(
29
  'title' => __('Limit', AAM_KEY),
30
- 'descr' => __('When checked, show defined on the Content Teaser tab teaser message instead of the %s content.', AAM_KEY)
 
31
  ),
32
  'comment' => array(
33
  'title' => __('Comment', AAM_KEY),
@@ -36,7 +37,7 @@ return array(
36
  'redirect' => array(
37
  'title' => __('Redirect', AAM_KEY),
38
  'sub' => '<small>' . sprintf(__('Redirect to: %s', AAM_KEY), '<b data-preview="frontend.location" id="post-location"></b>' ) . ' <a href="#" class="change-location" data-ref="frontend.location" data-preview-id="post-location">' . __('change', AAM_KEY) . '</a></small>',
39
- 'descr' => __('Redirect user to defined location when user tries to read the %s. Define either valid full URL or public page ID within the website.', AAM_KEY)
40
  ),
41
  'protected' => array(
42
  'title' => __('Password Protected', AAM_KEY),
27
  ),
28
  'limit' => array(
29
  'title' => __('Limit', AAM_KEY),
30
+ 'sub' => '<small>' . sprintf(__('Teaser message: %s', AAM_KEY), '<b data-preview="frontend.teaser" id="post-teaser"></b>' ) . ' <a href="#" class="change-teaser" data-ref="frontend.teaser" data-preview-id="post-teaser">' . __('change', AAM_KEY) . '</a></small>',
31
+ 'descr' => __('When checked, show defined teaser message instead of the %s content.', AAM_KEY)
32
  ),
33
  'comment' => array(
34
  'title' => __('Comment', AAM_KEY),
37
  'redirect' => array(
38
  'title' => __('Redirect', AAM_KEY),
39
  'sub' => '<small>' . sprintf(__('Redirect to: %s', AAM_KEY), '<b data-preview="frontend.location" id="post-location"></b>' ) . ' <a href="#" class="change-location" data-ref="frontend.location" data-preview-id="post-location">' . __('change', AAM_KEY) . '</a></small>',
40
+ 'descr' => __('Redirect user to defined location when user tries to read the %s. Define either valid full URL or public page ID within the website. The REDIRECT option will be ignored if READ option checked and user will be redirected based on the Access Denied Redirect rule.', AAM_KEY)
41
  ),
42
  'protected' => array(
43
  'title' => __('Password Protected', AAM_KEY),
Application/Backend/phtml/index.phtml CHANGED
@@ -99,6 +99,7 @@
99
  <th width="65%"><?php echo __('Role', AAM_KEY); ?></th>
100
  <th><?php echo __('Action', AAM_KEY); ?></th>
101
  <th>Level</th>
 
102
  </tr>
103
  </thead>
104
  <tbody></tbody>
@@ -116,6 +117,10 @@
116
  <label><?php echo __('Role Name', AAM_KEY); ?><span class="aam-asterix">*</span></label>
117
  <input type="text" class="form-control" name="name" placeholder="<?php echo __('Enter Role Name', AAM_KEY); ?>" />
118
  </div>
 
 
 
 
119
  <?php echo apply_filters('aam-add-role-ui-filter', AAM_Backend_View::getInstance()->loadPartial('role-inheritance.phtml')); ?>
120
  </div>
121
  <div class="modal-footer">
@@ -138,6 +143,10 @@
138
  <label for="new-role-name"><?php echo __('Role Name', AAM_KEY); ?></label>
139
  <input type="text" class="form-control" id="edit-role-name" placeholder="<?php echo __('Enter Role Name', AAM_KEY); ?>" name="name" />
140
  </div>
 
 
 
 
141
  <?php do_action('aam-edit-role-ui-action'); ?>
142
  </div>
143
  <div class="modal-footer">
99
  <th width="65%"><?php echo __('Role', AAM_KEY); ?></th>
100
  <th><?php echo __('Action', AAM_KEY); ?></th>
101
  <th>Level</th>
102
+ <th>Expiration</th>
103
  </tr>
104
  </thead>
105
  <tbody></tbody>
117
  <label><?php echo __('Role Name', AAM_KEY); ?><span class="aam-asterix">*</span></label>
118
  <input type="text" class="form-control" name="name" placeholder="<?php echo __('Enter Role Name', AAM_KEY); ?>" />
119
  </div>
120
+ <div class="form-group">
121
+ <label><?php echo __('Role Expiration', AAM_KEY); ?> <a href="https://aamplugin.com/help/how-to-manage-wordpress-roles" target="_blank" data-toggle="tooltip" title="For how long user can have this role. Click to learn more."><i class="icon-help-circled"></i></a></label>
122
+ <input type="text" class="form-control" name="expire" placeholder="<?php echo __('Enter Expiration Rule', AAM_KEY); ?>" />
123
+ </div>
124
  <?php echo apply_filters('aam-add-role-ui-filter', AAM_Backend_View::getInstance()->loadPartial('role-inheritance.phtml')); ?>
125
  </div>
126
  <div class="modal-footer">
143
  <label for="new-role-name"><?php echo __('Role Name', AAM_KEY); ?></label>
144
  <input type="text" class="form-control" id="edit-role-name" placeholder="<?php echo __('Enter Role Name', AAM_KEY); ?>" name="name" />
145
  </div>
146
+ <div class="form-group">
147
+ <label><?php echo __('Role Expiration', AAM_KEY); ?> <a href="https://aamplugin.com/help/how-to-manage-wordpress-roles" target="_blank" data-toggle="tooltip" title="For how long user can have this role. Click to learn more."><i class="icon-help-circled"></i></a></label>
148
+ <input type="text" class="form-control" name="expire" id="edit-role-expiration" placeholder="<?php echo __('Enter Expiration Rule', AAM_KEY); ?>" />
149
+ </div>
150
  <?php do_action('aam-edit-role-ui-action'); ?>
151
  </div>
152
  <div class="modal-footer">
Application/Backend/phtml/object/login-redirect.phtml CHANGED
@@ -4,11 +4,11 @@
4
  <div class="col-xs-12">
5
  <?php if ($this->isDefault()) { ?>
6
  <p class="aam-info">
7
- <?php echo AAM_Backend_View_Helper::preparePhrase('Define the [default] login redirect for all users, roles when the authentication completed successfully.', 'strong'); ?>
8
  </p>
9
  <?php } else { ?>
10
  <p class="aam-info">
11
- <?php echo sprintf(AAM_Backend_View_Helper::preparePhrase('Customize login redirect for this %s when the authentication completed successfully.'), AAM_Backend_View::getSubject()->getUID()); ?>
12
  </p>
13
  <?php } ?>
14
  <div class="aam-overwrite" id="aam-login-redirect-overwrite" style="display: <?php echo ($this->isOverwritten() ? 'block' : 'none'); ?>">
4
  <div class="col-xs-12">
5
  <?php if ($this->isDefault()) { ?>
6
  <p class="aam-info">
7
+ <?php echo AAM_Backend_View_Helper::preparePhrase('Define the [default] login redirect for all users, roles when the authentication completed successfully. [Please note!] The login redirect works only with the default WordPress login page.', 'strong', 'strong'); ?>
8
  </p>
9
  <?php } else { ?>
10
  <p class="aam-info">
11
+ <?php echo sprintf(AAM_Backend_View_Helper::preparePhrase('Customize login redirect for this %s when the authentication completed successfully. [Please note!] The login redirect works only with the default WordPress login page.', 'strong'), AAM_Backend_View::getSubject()->getUID()); ?>
12
  </p>
13
  <?php } ?>
14
  <div class="aam-overwrite" id="aam-login-redirect-overwrite" style="display: <?php echo ($this->isOverwritten() ? 'block' : 'none'); ?>">
Application/Backend/phtml/object/teaser.phtml CHANGED
@@ -2,6 +2,9 @@
2
  <div class="aam-feature" id="teaser-content">
3
  <div class="row">
4
  <div class="col-xs-12">
 
 
 
5
  <?php if ($this->isDefault()) { ?>
6
  <p class="aam-info">
7
  <?php echo AAM_Backend_View_Helper::preparePhrase('Define the [default] teaser message for all users, roles and visitors when access is limited to any post on your website.', 'strong'); ?>
2
  <div class="aam-feature" id="teaser-content">
3
  <div class="row">
4
  <div class="col-xs-12">
5
+ <p class="aam-notification">
6
+ <?php echo AAM_Backend_View_Helper::preparePhrase('[Warning!] The Content Teaser tab is deprecated and has been moved to the [Posts & Pages tab]. Now you can define teaser message for an individual post, category or all posts for any user, role or visitors. Please adjust your AAM settings because Content Teaser tab will be removed in AAM 5.0. For any feedback of questions, do not hesistate to contact us directly.', 'strong', 'strong'); ?>
7
+ </p>
8
  <?php if ($this->isDefault()) { ?>
9
  <p class="aam-info">
10
  <?php echo AAM_Backend_View_Helper::preparePhrase('Define the [default] teaser message for all users, roles and visitors when access is limited to any post on your website.', 'strong'); ?>
Application/Backend/phtml/partial/post-advanced-settings.phtml CHANGED
@@ -67,4 +67,31 @@
67
  </div>
68
  </div>
69
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  <?php }
67
  </div>
68
  </div>
69
  </div>
70
+
71
+ <div class="modal fade" id="teaser-modal" tabindex="-1" role="dialog">
72
+ <div class="modal-dialog" role="document">
73
+ <div class="modal-content">
74
+ <div class="modal-header">
75
+ <button type="button" class="close" data-dismiss="modal" aria-label="<?php echo __('Close', AAM_KEY); ?>"><span aria-hidden="true">&times;</span></button>
76
+ <h4 class="modal-title"><?php echo __('Teaser Message', AAM_KEY); ?></h4>
77
+ </div>
78
+ <div class="modal-body">
79
+ <div class="form-group">
80
+ <label><?php echo __('Simple text or valid HTML', AAM_KEY); ?></label>
81
+ <textarea class="form-control" id="teaser-value" placeholder="<?php echo __('Enter your teaser', AAM_KEY); ?>" rows="5"></textarea>
82
+ </div>
83
+ <div class="checkbox">
84
+ <label>
85
+ <input value="1" type="checkbox" id="add-excerpt" />
86
+ Add excerpt before teaser message
87
+ </label>
88
+ </div>
89
+ </div>
90
+ <div class="modal-footer">
91
+ <button type="button" class="btn btn-success extended-post-access-btn" id="change-teaser-btn"><?php echo __('Save', AAM_KEY); ?></button>
92
+ <button type="button" class="btn btn-default" data-dismiss="modal"><?php echo __('Close', AAM_KEY); ?></button>
93
+ </div>
94
+ </div>
95
+ </div>
96
+ </div>
97
  <?php }
Application/Core/API.php CHANGED
@@ -264,9 +264,9 @@ final class AAM_Core_API {
264
  */
265
  public static function redirect($rule, $args = null) {
266
  if (filter_var($rule, FILTER_VALIDATE_URL)) {
267
- wp_redirect($rule, 301);
268
  } elseif (preg_match('/^[\d]+$/', $rule)) {
269
- wp_safe_redirect(get_page_link($rule), 301);
270
  } elseif (is_callable($rule)) {
271
  call_user_func($rule, $args);
272
  } elseif (!empty($args['callback']) && is_callable($args['callback'])) {
264
  */
265
  public static function redirect($rule, $args = null) {
266
  if (filter_var($rule, FILTER_VALIDATE_URL)) {
267
+ wp_redirect($rule, 307);
268
  } elseif (preg_match('/^[\d]+$/', $rule)) {
269
+ wp_safe_redirect(get_page_link($rule), 307);
270
  } elseif (is_callable($rule)) {
271
  call_user_func($rule, $args);
272
  } elseif (!empty($args['callback']) && is_callable($args['callback'])) {
Application/Core/Media.php CHANGED
@@ -131,6 +131,9 @@ class AAM_Core_Media {
131
  $path = ABSPATH . $this->request_uri;
132
  }
133
 
 
 
 
134
  if (empty($mime)) {
135
  if (function_exists('mime_content_type')) {
136
  $mime = mime_content_type($path);
131
  $path = ABSPATH . $this->request_uri;
132
  }
133
 
134
+ //normalize path and strip all unexpected trails. Thanks to Antonius Hegyes
135
+ $path = preg_replace('/\?.*$/', '', $path);
136
+
137
  if (empty($mime)) {
138
  if (function_exists('mime_content_type')) {
139
  $mime = mime_content_type($path);
Application/Core/Subject/User.php CHANGED
@@ -63,6 +63,27 @@ class AAM_Core_Subject_User extends AAM_Core_Subject {
63
 
64
  return $response;
65
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
  /**
68
  * Retrieve User based on ID
63
 
64
  return $response;
65
  }
66
+
67
+ /**
68
+ *
69
+ */
70
+ public function restoreRoles() {
71
+ $roles = get_user_option('aam-original-roles');
72
+
73
+ //remove curren roles
74
+ foreach((array) $this->roles as $role) {
75
+ $this->remove_role($role);
76
+ }
77
+
78
+ //add original roles
79
+ foreach(($roles ? $roles : array('subscriber')) as $role) {
80
+ $this->add_role($role);
81
+ }
82
+
83
+ //delete options
84
+ delete_user_option($this->getId(), 'aam-role-expires');
85
+ delete_user_option($this->getId(), 'aam-original-roles');
86
+ }
87
 
88
  /**
89
  * Retrieve User based on ID
Application/Frontend/Manager.php CHANGED
@@ -318,6 +318,7 @@ class AAM_Frontend_Manager {
318
  $object = AAM::getUser()->getObject('post', $post->ID);
319
 
320
  if ($object->has('frontend.protected')) {
 
321
  $hasher = new PasswordHash( 8, true );
322
  $hash = wp_unslash(AAM_Core_Request::cookie('wp-postpass_' . COOKIEHASH));
323
 
@@ -596,9 +597,14 @@ class AAM_Frontend_Manager {
596
  if (is_a($post, 'WP_Post')) {
597
  $object = AAM::getUser()->getObject('post', $post->ID);
598
  if ($object->has('frontend.limit')) {
599
- $teaser = AAM::getUser()->getObject('teaser');
600
- $message = $teaser->get('frontend.teaser.message');
601
- $excerpt = $teaser->get('frontend.teaser.excerpt');
 
 
 
 
 
602
 
603
  $html = (intval($excerpt) ? $post->post_excerpt : '');
604
  $html .= stripslashes($message);
318
  $object = AAM::getUser()->getObject('post', $post->ID);
319
 
320
  if ($object->has('frontend.protected')) {
321
+ require_once( ABSPATH . 'wp-includes/class-phpass.php' );
322
  $hasher = new PasswordHash( 8, true );
323
  $hash = wp_unslash(AAM_Core_Request::cookie('wp-postpass_' . COOKIEHASH));
324
 
597
  if (is_a($post, 'WP_Post')) {
598
  $object = AAM::getUser()->getObject('post', $post->ID);
599
  if ($object->has('frontend.limit')) {
600
+ if ($object->has('frontend.teaser')) {
601
+ $message = $object->get('frontend.teaser');
602
+ $excerpt = false;
603
+ } else {
604
+ $teaser = AAM::getUser()->getObject('teaser');
605
+ $message = $teaser->get('frontend.teaser.message');
606
+ $excerpt = $teaser->get('frontend.teaser.excerpt');
607
+ }
608
 
609
  $html = (intval($excerpt) ? $post->post_excerpt : '');
610
  $html .= stripslashes($message);
Application/Shortcode/Strategy/Content.php CHANGED
@@ -48,8 +48,11 @@ class AAM_Shortcode_Strategy_Content implements AAM_Shortcode_Strategy_Interface
48
  }
49
 
50
  /**
51
- * Process shortcode
52
  *
 
 
 
53
  */
54
  public function run() {
55
  //prepare user
@@ -70,17 +73,17 @@ class AAM_Shortcode_Strategy_Content implements AAM_Shortcode_Strategy_Interface
70
  $content = $this->content;
71
 
72
  //#1. Check if content is restricted for current user
73
- if (in_array('all', $hide) || count(array_intersect($user, $hide))) {
74
  $content = '';
75
  }
76
 
77
  //#2. Check if content is limited for current user
78
- if (in_array('all', $limit) || count(array_intersect($user, $limit))) {
79
  $content = do_shortcode($msg);
80
  }
81
 
82
  //#3. Check if content is allosed for current user
83
- if (count(array_intersect($user, $show))) {
84
  $content = $this->content;
85
  }
86
  }
@@ -88,6 +91,61 @@ class AAM_Shortcode_Strategy_Content implements AAM_Shortcode_Strategy_Interface
88
  return $content;
89
  }
90
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  /**
92
  *
93
  * @return type
48
  }
49
 
50
  /**
51
+ * Process short-code
52
  *
53
+ * @return string
54
+ *
55
+ * @access public
56
  */
57
  public function run() {
58
  //prepare user
73
  $content = $this->content;
74
 
75
  //#1. Check if content is restricted for current user
76
+ if (in_array('all', $hide) || $this->check($user, $hide)) {
77
  $content = '';
78
  }
79
 
80
  //#2. Check if content is limited for current user
81
+ if (in_array('all', $limit) || $this->check($user, $limit)) {
82
  $content = do_shortcode($msg);
83
  }
84
 
85
  //#3. Check if content is allosed for current user
86
+ if ($this->check($user, $show)) {
87
  $content = $this->content;
88
  }
89
  }
91
  return $content;
92
  }
93
 
94
+ /**
95
+ *
96
+ * @param type $user
97
+ * @param type $conditions
98
+ * @return type
99
+ */
100
+ protected function check($user, $conditions) {
101
+ $match = false;
102
+
103
+ foreach($conditions as $condition) {
104
+ if (preg_match('/^[\d\.*\-]+$/', $condition)) {
105
+ $match = $this->checkIP(
106
+ $condition, AAM_Core_Request::server('REMOTE_ADDR')
107
+ );
108
+ } else {
109
+ $match = in_array($condition, $user);
110
+ }
111
+ if ($match) {
112
+ break;
113
+ }
114
+ }
115
+
116
+ return $match;
117
+ }
118
+
119
+ /**
120
+ *
121
+ * @param type $ip
122
+ * @param type $userIp
123
+ * @return boolean
124
+ */
125
+ protected function checkIP($ip, $userIp) {
126
+ $match = true;
127
+
128
+ $ipSplit = preg_split('/[\.:]/', $ip);
129
+ $uipSplit = preg_split('/[\.:]/', $userIp);
130
+
131
+ foreach($ipSplit as $i => $group) {
132
+ if (strpos($group, '-') !== false) { //range
133
+ list($start, $end) = explode('-', $group);
134
+ if ($uipSplit[$i] < $start || $uipSplit[$i] > $end) {
135
+ $match = false;
136
+ break;
137
+ }
138
+ } elseif ($group !== '*') {
139
+ if ($group != $uipSplit[$i]) {
140
+ $match = false;
141
+ break;
142
+ }
143
+ }
144
+ }
145
+
146
+ return $match;
147
+ }
148
+
149
  /**
150
  *
151
  * @return type
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: 4.7.6
7
  Author: Vasyl Martyniuk <vasyl@vasyltech.com>
8
  Author URI: https://vasyltech.com
9
 
@@ -119,13 +119,18 @@ class AAM {
119
  AAM_Core_Cache::bootstrap();
120
 
121
  //load all installed extension
122
- //TODO - Remove in Aug 2017
123
  AAM_Extension_Repository::getInstance()->load();
124
 
125
  //check if user is locked
126
  if (get_current_user_id() && AAM::getUser()->user_status == 1) {
127
  wp_logout();
128
  }
 
 
 
 
 
 
129
 
130
  //bootstrap the correct interface
131
  if (is_admin()) {
3
  /**
4
  Plugin Name: Advanced Access Manager
5
  Description: All you need to manage access to your WordPress website
6
+ Version: 4.8
7
  Author: Vasyl Martyniuk <vasyl@vasyltech.com>
8
  Author URI: https://vasyltech.com
9
 
119
  AAM_Core_Cache::bootstrap();
120
 
121
  //load all installed extension
 
122
  AAM_Extension_Repository::getInstance()->load();
123
 
124
  //check if user is locked
125
  if (get_current_user_id() && AAM::getUser()->user_status == 1) {
126
  wp_logout();
127
  }
128
+
129
+ //check if user's role expired
130
+ $expire = get_user_option('aam-role-expires');
131
+ if ($expire && ($expire <= time())) {
132
+ AAM::getUser()->restoreRoles();
133
+ }
134
 
135
  //bootstrap the correct interface
136
  if (is_admin()) {
media/css/aam.css CHANGED
@@ -52,6 +52,7 @@
52
  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
53
  }
54
 
 
55
  .icon-asterisk:before { content: '\e801' !important; } /* '' */
56
  .icon-spin4:before { content: '\e802' !important; } /* '' */
57
  .icon-user-secret:before { content: '\e803' !important; } /* '' */
52
  /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
53
  }
54
 
55
+ .icon-clock:before { content: '\e800' !important; } /* '' */
56
  .icon-asterisk:before { content: '\e801' !important; } /* '' */
57
  .icon-spin4:before { content: '\e802' !important; } /* '' */
58
  .icon-user-secret:before { content: '\e803' !important; } /* '' */
media/font/fontello.eot CHANGED
Binary file
media/font/fontello.svg CHANGED
@@ -6,6 +6,8 @@
6
  <font id="fontello" horiz-adv-x="1000" >
7
  <font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
8
  <missing-glyph horiz-adv-x="1000" />
 
 
9
  <glyph glyph-name="asterisk" unicode="&#xe801;" d="M827 264q26-14 33-43t-7-55l-35-61q-15-26-44-33t-54 7l-149 85v-171q0-29-21-50t-50-22h-71q-29 0-51 22t-21 50v171l-148-85q-26-15-55-7t-43 33l-36 61q-14 26-7 55t34 43l148 86-148 86q-26 14-34 43t7 55l36 61q15 26 43 33t55-7l148-85v171q0 29 21 50t51 22h71q29 0 50-22t21-50v-171l149 85q26 15 54 7t44-33l35-61q15-26 7-55t-33-43l-148-86z" horiz-adv-x="928.6" />
10
 
11
  <glyph glyph-name="spin4" unicode="&#xe802;" d="M498 850c-114 0-228-39-320-116l0 0c173 140 428 130 588-31 134-134 164-332 89-495-10-29-5-50 12-68 21-20 61-23 84 0 3 3 12 15 15 24 71 180 33 393-112 539-99 98-228 147-356 147z m-409-274c-14 0-29-5-39-16-3-3-13-15-15-24-71-180-34-393 112-539 185-185 479-195 676-31l0 0c-173-140-428-130-589 31-134 134-163 333-89 495 11 29 6 50-12 68-11 11-27 17-44 16z" horiz-adv-x="1001" />
6
  <font id="fontello" horiz-adv-x="1000" >
7
  <font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
8
  <missing-glyph horiz-adv-x="1000" />
9
+ <glyph glyph-name="clock" unicode="&#xe800;" d="M500 546v-250q0-7-5-12t-13-5h-178q-8 0-13 5t-5 12v36q0 8 5 13t13 5h125v196q0 8 5 13t12 5h36q8 0 13-5t5-13z m232-196q0 83-41 152t-110 111-152 41-153-41-110-111-41-152 41-152 110-111 153-41 152 41 110 111 41 152z m125 0q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
10
+
11
  <glyph glyph-name="asterisk" unicode="&#xe801;" d="M827 264q26-14 33-43t-7-55l-35-61q-15-26-44-33t-54 7l-149 85v-171q0-29-21-50t-50-22h-71q-29 0-51 22t-21 50v171l-148-85q-26-15-55-7t-43 33l-36 61q-14 26-7 55t34 43l148 86-148 86q-26 14-34 43t7 55l36 61q15 26 43 33t55-7l148-85v171q0 29 21 50t51 22h71q29 0 50-22t21-50v-171l149 85q26 15 54 7t44-33l35-61q15-26 7-55t-33-43l-148-86z" horiz-adv-x="928.6" />
12
 
13
  <glyph glyph-name="spin4" unicode="&#xe802;" d="M498 850c-114 0-228-39-320-116l0 0c173 140 428 130 588-31 134-134 164-332 89-495-10-29-5-50 12-68 21-20 61-23 84 0 3 3 12 15 15 24 71 180 33 393-112 539-99 98-228 147-356 147z m-409-274c-14 0-29-5-39-16-3-3-13-15-15-24-71-180-34-393 112-539 185-185 479-195 676-31l0 0c-173-140-428-130-589 31-134 134-163 333-89 495 11 29 6 50-12 68-11 11-27 17-44 16z" horiz-adv-x="1001" />
media/font/fontello.ttf CHANGED
Binary file
media/font/fontello.woff CHANGED
Binary file
media/font/fontello.woff2 CHANGED
Binary file
media/js/aam-interface.js CHANGED
@@ -83,7 +83,7 @@
83
  }
84
  },
85
  columnDefs: [
86
- {visible: false, targets: [0, 1, 4]}
87
  ],
88
  language: {
89
  search: '_INPUT_',
@@ -115,9 +115,10 @@
115
  $(row).attr('data-id', data[0]);
116
 
117
  //add subtitle
 
118
  $('td:eq(0)', row).append(
119
  $('<i/>', {'class': 'aam-row-subtitle'}).html(
120
- aam.__('Users') + ': <b>' + parseInt(data[1]) + '</b>; ID: <b>' + data[0] + '</b>'
121
  )
122
  );
123
 
@@ -160,67 +161,68 @@
160
 
161
  case 'edit':
162
  if (!aam.isUI()) {
163
- $(container).append($('<i/>', {
164
- 'class': 'aam-row-action icon-pencil text-warning'
165
- }).bind('click', function () {
166
- $('#edit-role-btn').data('role', data[0]);
167
- $('#edit-role-name').val(data[2]);
168
- $('#edit-role-modal').modal('show');
169
- fetchRoleList(data[0]);
170
- //TODO - Rerwite JavaScript to support $.aam
171
- $.aamEditRole = data;
172
- }).attr({
173
- 'data-toggle': "tooltip",
174
- 'title': aam.__('Edit Role Name')
175
- }));
176
- }
 
177
  break;
178
 
179
  case 'clone':
180
  if (!aam.isUI()) {
181
- $(container).append($('<i/>', {
182
- 'class': 'aam-row-action icon-clone text-success'
183
- }).bind('click', function () {
184
- //TODO - Rerwite JavaScript to support $.aam
185
- $.aamEditRole = data;
186
- $('#clone-role').prop('checked', true);
187
- $('#add-role-modal').modal('show');
188
- }).attr({
189
- 'data-toggle': "tooltip",
190
- 'title': aam.__('Clone Role')
191
- }));
192
- }
193
  break;
194
 
195
  case 'delete':
196
  if (!aam.isUI()) {
197
- $(container).append($('<i/>', {
198
- 'class': 'aam-row-action icon-trash-empty text-danger'
199
- }).bind('click', {role: data}, function (event) {
200
- $('#delete-role-btn').data('role', data[0]);
201
- var message = $('#delete-role-modal .aam-confirm-message').data('message');
202
- $('#delete-role-modal .aam-confirm-message').html(
203
- message.replace(
204
- '%s', '<strong>' + event.data.role[2] + '</strong>'
205
- )
206
- );
207
 
208
- $('#delete-role-modal').modal('show');
209
- }).attr({
210
- 'data-toggle': "tooltip",
211
- 'title': aam.__('Delete Role')
212
- }));
213
- }
214
  break;
215
 
216
  default:
217
  if (!aam.isUI()) {
218
- aam.triggerHook('role-action', {
219
- container: container,
220
- action : action,
221
- data : data
222
- });
223
- }
224
  break;
225
  }
226
  });
@@ -1331,7 +1333,7 @@
1331
  var filter = {
1332
  type: null
1333
  };
1334
-
1335
  /**
1336
  *
1337
  * @param {type} type
@@ -1429,8 +1431,9 @@
1429
  'class': 'aam-row-action ' + checked
1430
  });
1431
  } else {
1432
- $('[data-preview="' + property + '"]', container).text(
1433
- response.access[property]
 
1434
  );
1435
  }
1436
  }
@@ -1527,6 +1530,23 @@
1527
  return result;
1528
  }
1529
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1530
  /**
1531
  *
1532
  * @returns {undefined}
@@ -1872,6 +1892,48 @@
1872
  $('#expiration-modal').modal('hide');
1873
  $(this).text(aam.__('Set'));
1874
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1875
  }
1876
 
1877
  aam.addHook('init', initialize);
@@ -2623,7 +2685,6 @@
2623
  $.ajax(aamLocal.url.site, {
2624
  type: 'POST',
2625
  dataType: 'html',
2626
- async: false,
2627
  data: {
2628
  action: 'aamc',
2629
  _ajax_nonce: aamLocal.nonce,
@@ -2675,7 +2736,6 @@
2675
  $.ajax(aamLocal.ajaxurl, {
2676
  type: 'POST',
2677
  dataType: 'json',
2678
- async: false,
2679
  data: {
2680
  action: 'aam',
2681
  sub_action: 'subscribe',
83
  }
84
  },
85
  columnDefs: [
86
+ {visible: false, targets: [0, 1, 4, 5]}
87
  ],
88
  language: {
89
  search: '_INPUT_',
115
  $(row).attr('data-id', data[0]);
116
 
117
  //add subtitle
118
+ var expire = (data[5] ? '; <i class="icon-clock"></i>' : '');
119
  $('td:eq(0)', row).append(
120
  $('<i/>', {'class': 'aam-row-subtitle'}).html(
121
+ aam.__('Users') + ': <b>' + parseInt(data[1]) + '</b>; ID: <b>' + data[0] + '</b>' + expire
122
  )
123
  );
124
 
161
 
162
  case 'edit':
163
  if (!aam.isUI()) {
164
+ $(container).append($('<i/>', {
165
+ 'class': 'aam-row-action icon-pencil text-warning'
166
+ }).bind('click', function () {
167
+ $('#edit-role-btn').data('role', data[0]);
168
+ $('#edit-role-name').val(data[2]);
169
+ $('#edit-role-expiration').val(data[5]);
170
+ $('#edit-role-modal').modal('show');
171
+ fetchRoleList(data[0]);
172
+ //TODO - Rerwite JavaScript to support $.aam
173
+ $.aamEditRole = data;
174
+ }).attr({
175
+ 'data-toggle': "tooltip",
176
+ 'title': aam.__('Edit Role Name')
177
+ }));
178
+ }
179
  break;
180
 
181
  case 'clone':
182
  if (!aam.isUI()) {
183
+ $(container).append($('<i/>', {
184
+ 'class': 'aam-row-action icon-clone text-success'
185
+ }).bind('click', function () {
186
+ //TODO - Rerwite JavaScript to support $.aam
187
+ $.aamEditRole = data;
188
+ $('#clone-role').prop('checked', true);
189
+ $('#add-role-modal').modal('show');
190
+ }).attr({
191
+ 'data-toggle': "tooltip",
192
+ 'title': aam.__('Clone Role')
193
+ }));
194
+ }
195
  break;
196
 
197
  case 'delete':
198
  if (!aam.isUI()) {
199
+ $(container).append($('<i/>', {
200
+ 'class': 'aam-row-action icon-trash-empty text-danger'
201
+ }).bind('click', {role: data}, function (event) {
202
+ $('#delete-role-btn').data('role', data[0]);
203
+ var message = $('#delete-role-modal .aam-confirm-message').data('message');
204
+ $('#delete-role-modal .aam-confirm-message').html(
205
+ message.replace(
206
+ '%s', '<strong>' + event.data.role[2] + '</strong>'
207
+ )
208
+ );
209
 
210
+ $('#delete-role-modal').modal('show');
211
+ }).attr({
212
+ 'data-toggle': "tooltip",
213
+ 'title': aam.__('Delete Role')
214
+ }));
215
+ }
216
  break;
217
 
218
  default:
219
  if (!aam.isUI()) {
220
+ aam.triggerHook('role-action', {
221
+ container: container,
222
+ action : action,
223
+ data : data
224
+ });
225
+ }
226
  break;
227
  }
228
  });
1333
  var filter = {
1334
  type: null
1335
  };
1336
+
1337
  /**
1338
  *
1339
  * @param {type} type
1431
  'class': 'aam-row-action ' + checked
1432
  });
1433
  } else {
1434
+ $('[data-preview="' + property + '"]', container).prop('data-original-value', response.access[property]);
1435
+ $('[data-preview="' + property + '"]', container).html(
1436
+ preparePreview(response.access[property])
1437
  );
1438
  }
1439
  }
1530
  return result;
1531
  }
1532
 
1533
+ /**
1534
+ *
1535
+ * @param {type} text
1536
+ * @returns {String}
1537
+ */
1538
+ function preparePreview(preview) {
1539
+ if (typeof preview === 'string') {
1540
+ preview = preview.replace(/<\/?[^>]+(>|$)/g, "");
1541
+
1542
+ if (preview.length > 25) {
1543
+ preview = preview.substring(0, 22) + '...';
1544
+ }
1545
+ }
1546
+
1547
+ return preview;
1548
+ }
1549
+
1550
  /**
1551
  *
1552
  * @returns {undefined}
1892
  $('#expiration-modal').modal('hide');
1893
  $(this).text(aam.__('Set'));
1894
  });
1895
+
1896
+ $('.change-teaser').each(function() {
1897
+ $(this).bind('click', function(event) {
1898
+ event.preventDefault();
1899
+
1900
+ var teaser = $('#' + $(this).attr('data-preview-id')).prop('data-original-value');
1901
+ $('#teaser-value').val(teaser);
1902
+
1903
+ $('#change-teaser-btn').attr({
1904
+ 'data-ref': $(this).attr('data-ref'),
1905
+ 'data-preview-id': $(this).attr('data-preview-id')
1906
+ });
1907
+
1908
+ $('#teaser-modal').modal('show');
1909
+ });
1910
+ });
1911
+
1912
+ $('#change-teaser-btn').bind('click', function() {
1913
+ $(this).text(aam.__('Saving...'));
1914
+
1915
+ var teaser = $('#teaser-value').val();
1916
+ var response = save(
1917
+ $(this).attr('data-ref'),
1918
+ teaser,
1919
+ $(this).attr('data-type'),
1920
+ $(this).attr('data-id')
1921
+ );
1922
+
1923
+ if (response.status === 'success') {
1924
+ var preview = $('#' + $(this).attr('data-preview-id'));
1925
+ var action = $('.aam-row-action', preview.parent().parent().parent());
1926
+
1927
+ preview.prop('data-original-value', teaser);
1928
+ preview.html(preparePreview(teaser));
1929
+
1930
+ if ($(action).hasClass('icon-check-empty')) {
1931
+ action.trigger('click');
1932
+ }
1933
+ }
1934
+ $('#teaser-modal').modal('hide');
1935
+ $(this).text(aam.__('Save'));
1936
+ });
1937
  }
1938
 
1939
  aam.addHook('init', initialize);
2685
  $.ajax(aamLocal.url.site, {
2686
  type: 'POST',
2687
  dataType: 'html',
 
2688
  data: {
2689
  action: 'aamc',
2690
  _ajax_nonce: aamLocal.nonce,
2736
  $.ajax(aamLocal.ajaxurl, {
2737
  type: 'POST',
2738
  dataType: 'json',
 
2739
  data: {
2740
  action: 'aam',
2741
  sub_action: 'subscribe',
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: vasyltech
3
  Tags: access, role, user, capability, page access, post access, security, login redirect, brute force attack, double authentication, membership, backend lockdown, wp-admin, 404, activity tracking
4
  Requires at least: 3.8
5
  Tested up to: 4.8
6
- Stable tag: 4.7.6
7
 
8
  Manage access to your website for any user, role or visitors for both frontend and backend.
9
 
@@ -68,7 +68,7 @@ Protect your website from brute force and dictionary attacks or activate double
68
  when user credentials are used from unexpected location.
69
 
70
  = Manage Roles =
71
- Create, edit, clone, delete any role. With AAM Role Hierarchy extension define complex
72
  role hierarchy tree.
73
 
74
  = Single point API =
@@ -111,7 +111,14 @@ Check our [help page](https://aamplugin.com/help) to find out more about AAM.
111
  == Changelog ==
112
 
113
  = 4.8 =
114
- * Fix the bug with Media access control reported by Antonius Hegyes
 
 
 
 
 
 
 
115
 
116
  = 4.7.6 =
117
  * Added ability to hide admin notification with show_admin_notices capability
3
  Tags: access, role, user, capability, page access, post access, security, login redirect, brute force attack, double authentication, membership, backend lockdown, wp-admin, 404, activity tracking
4
  Requires at least: 3.8
5
  Tested up to: 4.8
6
+ Stable tag: 4.8
7
 
8
  Manage access to your website for any user, role or visitors for both frontend and backend.
9
 
68
  when user credentials are used from unexpected location.
69
 
70
  = Manage Roles =
71
+ Create, edit, clone, delete any role. Set expiration time to any role. With AAM Role Hierarchy extension define complex
72
  role hierarchy tree.
73
 
74
  = Single point API =
111
  == Changelog ==
112
 
113
  = 4.8 =
114
+ * Fixed the bug with Media access control reported by Antonius Hegyes
115
+ * Fixed the bug with post access properties preview
116
+ * Fixed the bug with permanent redirects cached by some browsers
117
+ * Fixed the bug with PasswordHash fatal error
118
+ * Added ability to define teaser message for an individual post or category
119
+ * Deprecated Content Teaser tab (will be removed in AAM 5.0)
120
+ * Extended [aam context="content"] shortcode to filter content based on IP address
121
+ * Added ability to set time expiration for roles
122
 
123
  = 4.7.6 =
124
  * Added ability to hide admin notification with show_admin_notices capability