PluginProbe
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions / 261011
s2Member – Excellent for All Kinds of Memberships, Content Restriction Paywalls & Member Access Subscriptions v261011
261011 261001 260927 260917 260913 260909 260829 260814 260805 110710 110731 110812 110815 110912 110913 110915 110926 110927 111002 111003 111011 111017 111029 111105 111206 All 192 releases
← All changes | src/includes/classes/security-rest.inc.php +347 -64 260829 → 261011 View file →
@@ -28,28 +28,308 @@
28 28 */
29 29 class c_ws_plugin__s2member_security_rest
30 30 {
31 31 /**
32 - * s2Member's Security Gate (protects WordPress content).
32 + * Protects the resource selected by WordPress after route matching and validation.
33 33 *
34 34 * @package s2Member\Security
35 35 * @since 240312
36 36 *
37 - * @attaches-to ``add_filter('rest_pre_dispatch');``
37 + * @attaches-to ``add_filter('rest_request_before_callbacks');``
38 38 *
39 - * @return null May give a 403 error *(exiting script execution)*, when/if content is NOT available to the current User/Member.
39 + * @param mixed $response Original response from earlier filters.
40 + * @param array $handler Matched WordPress REST endpoint handler.
41 + * @param WP_REST_Request $request Validated REST request.
42 + *
43 + * @return mixed Original response, or a membership WP_Error with HTTP 403.
40 44 */
41 - public static function security_gate($response, $handler, $request) // s2Member's Security Gate.
45 + public static function security_gate($response, $handler, $request)
42 46 {
43 - $route = $request->get_route(); // e.g. /wp/v2/pages
44 - $route = explode('/', trim($route, '/'));
47 + if(is_wp_error($response) || empty($handler['callback']) || !is_array($handler['callback']))
48 + return $response;
45 49
46 - if (empty($route[2]) || empty($route[3]))
47 - return $response;
48 -
49 - $type = sanitize_key($route[2]); // e.g. pages
50 - $id = (int)$route[3];
51 -
50 + //261005.2320 Use the matched controller and validated ID; route segments and query IDs can describe different resources.
51 + $controller = $handler['callback'][0];
52 + $id = (int)$request->get_param('id');
53 + if(!$id)
54 + return $response;
55 +
56 + if($controller instanceof WP_REST_Posts_Controller)
57 + {
58 + $post = get_post($id);
59 + $type = $post ? get_post_type_object($post->post_type) : NULL;
60 + if($type && self::controller_owns_resource($type, $controller, $request))
61 + return self::check_post_access($post, $response);
62 + }
63 + else if($controller instanceof WP_REST_Terms_Controller)
64 + {
65 + $term = get_term($id);
66 + $taxonomy = $term && !is_wp_error($term) ? get_taxonomy($term->taxonomy) : NULL;
67 + if($taxonomy && self::controller_owns_resource($taxonomy, $controller, $request))
68 + return self::check_resource_access($term->taxonomy === 'category' ? 'categories' : ($term->taxonomy === 'post_tag' ? 'tags' : 'terms'), $id, $response);
69 + }
70 + else if($controller instanceof WP_REST_Comments_Controller && ($comment = get_comment($id)) && ($post = get_post($comment->comment_post_ID)))
71 + return self::check_post_access($post, $response);
72 +
73 + return $response;
74 + }
75 +
76 + /**
77 + * Determines whether the matched REST controller owns the requested resource.
78 + *
79 + * @package s2Member\Security
80 + * @since 261005
81 + *
82 + * @param WP_Post_Type|WP_Taxonomy $resource Registered post type or taxonomy.
83 + * @param WP_REST_Controller $controller Matched endpoint controller.
84 + * @param WP_REST_Request $request Validated REST request.
85 + *
86 + * @return bool True if the controller owns the resource; false otherwise.
87 + */
88 + private static function controller_owns_resource($resource, $controller, $request)
89 + {
90 + if(method_exists($resource, 'get_rest_controller'))
91 + return $resource->get_rest_controller() === $controller;
92 + //261005.2335 Older REST-enabled WordPress releases expose the registered base but lack these accessors.
93 + if(empty($resource->show_in_rest))
94 + return FALSE;
95 + $namespace = !empty($resource->rest_namespace) ? $resource->rest_namespace : 'wp/v2';
96 + $base = !empty($resource->rest_base) ? $resource->rest_base : $resource->name;
97 + return (bool)preg_match('/^'.preg_quote('/'.$namespace.'/'.$base, '/').'\/\d+\/?$/', $request->get_route());
98 + }
99 +
100 + /**
101 + * Checks REST access to a post, page, or comment parent.
102 + *
103 + * @package s2Member\Security
104 + * @since 261005
105 + *
106 + * @param WP_Post $post Existing post whose membership restrictions are checked.
107 + * @param mixed $response Original response to preserve when access is allowed.
108 + *
109 + * @return mixed Original response, or a membership WP_Error with HTTP 403.
110 + */
111 + private static function check_post_access($post, $response = NULL)
112 + {
113 + $type = $post->post_type === 'page' ? 'pages' : 'posts';
114 + return self::check_resource_access($type, (int)$post->ID, $response, $post->post_type);
115 + }
116 +
117 + /**
118 + * Registers REST collection and search access filters for exposed resources.
119 + *
120 + * @package s2Member\Security
121 + * @since 261005
122 + *
123 + * @attaches-to ``add_action('rest_api_init');``
124 + *
125 + * @return void
126 + */
127 + public static function register_collection_filters()
128 + {
129 + foreach(get_post_types(array('show_in_rest' => TRUE), 'names') as $post_type)
130 + add_filter('rest_'.$post_type.'_query', array(__CLASS__, 'filter_post_query'), PHP_INT_MAX, 2);
131 + foreach(get_taxonomies(array('show_in_rest' => TRUE), 'names') as $taxonomy)
132 + add_filter('rest_'.$taxonomy.'_query', array(__CLASS__, 'filter_term_query'), PHP_INT_MAX, 2);
133 + add_filter('rest_post_search_query', array(__CLASS__, 'filter_post_query'), PHP_INT_MAX, 2);
134 + add_filter('rest_term_search_query', array(__CLASS__, 'filter_term_query'), PHP_INT_MAX, 2);
135 + add_filter('rest_comment_query', array(__CLASS__, 'filter_comment_query'), PHP_INT_MAX, 2);
136 + }
137 +
138 + /**
139 + * Determines whether configured restrictions require a REST collection access check.
140 + *
141 + * @package s2Member\Security
142 + * @since 261005
143 + *
144 + * @param bool $posts Include post/page, Specific Post/Page, and Custom Capability rules?
145 + *
146 + * @return bool True if an applicable restriction may deny access to collection items.
147 + */
148 + private static function needs_query_check($posts = FALSE)
149 + {
150 + $o = $GLOBALS['WS_PLUGIN__']['s2member']['o'];
151 + if(empty($o['membership_options_page']))
152 + return FALSE;
153 + $user = wp_get_current_user();
154 + for($n = $GLOBALS['WS_PLUGIN__']['s2member']['c']['levels']; $n >= 0; $n--)
155 + foreach($posts ? array('posts', 'pages', 'catgs', 'ptags', 'ruris') : array('catgs', 'ptags', 'ruris') as $kind)
156 + if(!empty($o['level'.$n.'_'.$kind]) && !$user->has_cap('access_s2member_level'.$n))
157 + return TRUE;
158 + if(!empty($o['login_redirection_override']) && !$user->has_cap('access_s2member_level0'))
159 + return TRUE;
160 + if($posts)
161 + {
162 + if((!empty($o['login_welcome_page']) || !empty($o['file_download_limit_exceeded_page'])) && !$user->has_cap('access_s2member_level0'))
163 + return TRUE;
164 + if(!empty($o['specific_ids']) || c_ws_plugin__s2member_utils_gets::get_unavailable_singular_ids_with_ccaps($user->ID ? $user : FALSE))
165 + return TRUE;
166 + }
167 + return FALSE;
168 + }
169 +
170 + /**
171 + * Excludes protected posts before REST collection/search pagination and counts.
172 + *
173 + * @package s2Member\Security
174 + * @since 261005
175 + *
176 + * @attaches-to ``add_filter('rest_{$post_type}_query'); add_filter('rest_post_search_query');``
177 + *
178 + * @param array $args Prepared WP_Query arguments.
179 + * @param WP_REST_Request $request Validated collection or search request.
180 + *
181 + * @return array Query arguments with inaccessible posts excluded.
182 + */
183 + public static function filter_post_query($args, $request)
184 + {
185 + if(!self::needs_query_check(TRUE))
186 + return $args;
187 + $scan = $args;
188 + //261005.2324 Scan only matching candidates in bounded batches; presentation filters must not decide REST access.
189 + $scan['fields'] = 'ids';
190 + $scan['posts_per_page'] = 200;
191 + $scan['nopaging'] = FALSE;
192 + $scan['paged'] = 1;
193 + $scan['orderby'] = 'ID';
194 + $scan['order'] = 'ASC';
195 + $scan['suppress_filters'] = TRUE;
196 + $scan['no_found_rows'] = TRUE;
197 + $excluded = array();
198 + for($offset = 0; ; $offset += 200)
199 + {
200 + $scan['offset'] = $offset;
201 + $ids = get_posts($scan);
202 + if(!$ids)
203 + break;
204 + _prime_post_caches($ids, TRUE, TRUE);
205 + foreach($ids as $id)
206 + if(($post = get_post($id)) && is_wp_error(self::check_post_access($post)))
207 + $excluded[] = (int)$id;
208 + if(count($ids) < 200)
209 + break;
210 + }
211 + return self::exclude_query_ids($args, $excluded, 'post__in', 'post__not_in');
212 + }
213 +
214 + /**
215 + * Excludes protected terms from REST taxonomy collections and term search.
216 + *
217 + * @package s2Member\Security
218 + * @since 261005
219 + *
220 + * @attaches-to ``add_filter('rest_{$taxonomy}_query'); add_filter('rest_term_search_query');``
221 + *
222 + * @param array $args Prepared WP_Term_Query arguments.
223 + * @param WP_REST_Request $request Validated collection or search request.
224 + *
225 + * @return array Query arguments with inaccessible terms excluded.
226 + */
227 + public static function filter_term_query($args, $request)
228 + {
229 + if(!self::needs_query_check())
230 + return $args;
231 + $scan = $args;
232 + $scan['number'] = 0;
233 + $scan['offset'] = 0;
234 + $scan['fields'] = 'all';
235 + if(!empty($scan['post']))
236 + $scan['object_ids'] = $scan['post'];
237 + $terms = get_terms($scan);
238 + $excluded = array();
239 + if(!is_wp_error($terms))
240 + foreach($terms as $term)
241 + if(is_wp_error(self::check_resource_access($term->taxonomy === 'category' ? 'categories' : ($term->taxonomy === 'post_tag' ? 'tags' : 'terms'), (int)$term->term_id)))
242 + $excluded[] = (int)$term->term_id;
243 + return self::exclude_query_ids($args, $excluded, 'include', 'exclude');
244 + }
245 +
246 + /**
247 + * Excludes comments whose parent posts are inaccessible to the current user.
248 + *
249 + * @package s2Member\Security
250 + * @since 261005
251 + *
252 + * @attaches-to ``add_filter('rest_comment_query');``
253 + *
254 + * @param array $args Prepared WP_Comment_Query arguments.
255 + * @param WP_REST_Request $request Validated comment collection request.
256 + *
257 + * @return array Query arguments with comments on inaccessible posts excluded.
258 + */
259 + public static function filter_comment_query($args, $request)
260 + {
261 + if(!self::needs_query_check(TRUE))
262 + return $args;
263 + $scan = $args;
264 + $scan['number'] = 200;
265 + $scan['fields'] = 'all';
266 + $scan['count'] = FALSE;
267 + $scan['orderby'] = 'comment_ID';
268 + $scan['order'] = 'ASC';
269 + $scan['hierarchical'] = FALSE;
270 + $excluded = $parents = array();
271 + for($offset = 0; ; $offset += 200)
272 + {
273 + $scan['offset'] = $offset;
274 + $comments = get_comments($scan);
275 + _prime_post_caches(array_unique(wp_list_pluck($comments, 'comment_post_ID')), TRUE, TRUE);
276 + foreach($comments as $comment)
277 + {
278 + $parent = (int)$comment->comment_post_ID;
279 + if(!isset($parents[$parent]))
280 + $parents[$parent] = ($post = get_post($parent)) && is_wp_error(self::check_post_access($post));
281 + if($parents[$parent])
282 + $excluded[] = (int)$comment->comment_ID;
283 + }
284 + if(count($comments) < 200)
285 + break;
286 + }
287 + return self::exclude_query_ids($args, $excluded, 'comment__in', 'comment__not_in');
288 + }
289 +
290 + /**
291 + * Applies exclusions without letting an exhausted include list expand the query.
292 + *
293 + * @package s2Member\Security
294 + * @since 261005
295 + *
296 + * @param array $args Prepared collection query arguments.
297 + * @param int[] $excluded Resource IDs denied by membership restrictions.
298 + * @param string $include_key Query argument containing explicit included IDs.
299 + * @param string $exclude_key Query argument containing excluded IDs.
300 + *
301 + * @return array Query arguments with exclusions and a restrictive include list.
302 + */
303 + private static function exclude_query_ids($args, $excluded, $include_key, $exclude_key)
304 + {
305 + if(!$excluded)
306 + return $args;
307 + $args[$exclude_key] = array_values(array_unique(array_merge(isset($args[$exclude_key]) ? wp_parse_id_list($args[$exclude_key]) : array(), $excluded)));
308 + if(!empty($args[$include_key]))
309 + {
310 + $included = array_values(array_diff(wp_parse_id_list($args[$include_key]), $args[$exclude_key]));
311 + //261005.2324 Keep an exhausted include list restrictive instead of expanding it to the whole collection.
312 + $args[$include_key] = $included ? $included : array(0);
313 + }
314 + return $args;
315 + }
316 +
317 + /**
318 + * Checks the REST restriction policy against a canonical content resource.
319 + *
320 + * @package s2Member\Security
321 + * @since 261005
322 + *
323 + * @param string $type Resource kind: posts, pages, categories, tags, or terms.
324 + * @param int $id Existing post or term ID.
325 + * @param mixed $response Original response to preserve when access is allowed.
326 + * @param string $post_type Actual registered post type for post/page restrictions.
327 + *
328 + * @return mixed Original response, or a membership WP_Error with HTTP 403.
329 + */
330 + private static function check_resource_access($type, $id, $response = NULL, $post_type = '')
331 + {
52 332 $s2_options = $GLOBALS['WS_PLUGIN__']['s2member']['o'];
53 333 $s2_levels = $GLOBALS['WS_PLUGIN__']['s2member']['c']['levels'];
54 334 $ci = $s2_options['ruris_case_sensitive'] ? '' : 'i';
55 335
@@ -58,46 +338,50 @@
58 338
59 339 // Skip early?
60 340 if (empty($s2_options['membership_options_page'])
61 341 || empty($id)
62 - || $s2_options['membership_options_page'] == $id
63 - || c_ws_plugin__s2member_systematics::is_wp_systematic_use_page()) {
342 + || ($type === 'pages' && (int)$s2_options['membership_options_page'] === $id)) {
64 343 return $response;
65 344 }
66 345
67 346
68 - // Post types array
69 - // Use: in_array($type, $post_types, true)
70 - $post_types = get_post_types(['show_in_rest' => true], 'names');
71 -
72 347 // Get the regular path for this content, to check URI restriction
73 - $path = $_SERVER['REQUEST_URI']; // default
74 - if (in_array($type, ['posts', 'pages'], true)
75 - || in_array($type, $post_types, true)) {
348 + $path = ''; // Only canonical resource URIs participate in content restrictions.
349 + if (in_array($type, ['posts', 'pages'], true)) {
76 350 $permalink = get_permalink($id);
77 - if (!is_wp_error($permalink)) {
78 - $path = str_replace(home_url(), '', $permalink);
351 + if ($permalink && !is_wp_error($permalink)) {
352 + $path = c_ws_plugin__s2member_utils_urls::parse_uri($permalink);
79 353 }
80 354 } elseif ($type === 'categories') {
81 355 $term_link = get_term_link($id, 'category');
82 356 if (!is_wp_error($term_link)) {
83 - $path = str_replace(home_url(), '', $term_link);
357 + $path = c_ws_plugin__s2member_utils_urls::parse_uri($term_link);
84 358 }
85 359 } elseif ($type === 'tags') {
86 360 $term_link = get_term_link($id, 'post_tag');
87 361 if (!is_wp_error($term_link)) {
88 - $path = str_replace(home_url(), '', $term_link);
362 + $path = c_ws_plugin__s2member_utils_urls::parse_uri($term_link);
89 363 }
90 364 }
91 365
92 366
367 + else if($type === 'terms' && ($term = get_term($id)) && !is_wp_error($term)) {
368 + $term_link = get_term_link($term);
369 + if (!is_wp_error($term_link)) {
370 + $path = c_ws_plugin__s2member_utils_urls::parse_uri($term_link);
371 + }
372 + }
373 +
374 + //261005.2320 Page exemptions cannot be inherited by terms with the same numeric ID.
375 + $page_id = $type === 'pages' ? $id : 0;
376 +
93 377 // Login welcome page
94 378 if($s2_options['login_welcome_page']
95 - && $id === (int)$s2_options['login_welcome_page']
379 + && $page_id && $page_id === (int)$s2_options['login_welcome_page']
96 380 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
97 381 && (!$user || !$user->has_cap('access_s2member_level0'))
98 - && $id !== (int)$s2_options['membership_options_page'])
99 - return new WP_Error('rest_forbidden', __('You do not have access to this page. [sys level 0]', 'text-domain'), array('status' => 403));
382 + && $page_id !== (int)$s2_options['membership_options_page'])
383 + return new WP_Error('rest_forbidden', __('You do not have access to this page. [sys level 0]', 's2member'), array('status' => 403));
100 384
101 385 // Login redirection override
102 386 else if($s2_options['login_redirection_override']
103 387 && ($login_redirection_uri = c_ws_plugin__s2member_login_redirects::login_redirection_uri($user, 'root-returns-false'))
@@ -103,21 +387,21 @@
103 387 && ($login_redirection_uri = c_ws_plugin__s2member_login_redirects::login_redirection_uri($user, 'root-returns-false'))
104 388 && preg_match('/^'.preg_quote($login_redirection_uri, '/').'$/'.$ci, $path)
105 389 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
106 390 && (!$user || !$user->has_cap('access_s2member_level0'))
107 - && $id !== (int)$s2_options['membership_options_page'])
108 - return new WP_Error('rest_forbidden', __('You do not have access to this page. [sys level 0]', 'text-domain'), array('status' => 403));
391 + && $page_id !== (int)$s2_options['membership_options_page'])
392 + return new WP_Error('rest_forbidden', __('You do not have access to this page. [sys level 0]', 's2member'), array('status' => 403));
109 393
110 394 // File download limit exceeded page
111 395 else if($s2_options['file_download_limit_exceeded_page']
112 - && $id === (int)$s2_options['file_download_limit_exceeded_page']
396 + && $page_id && $page_id === (int)$s2_options['file_download_limit_exceeded_page']
113 397 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
114 398 && (!$user || !$user->has_cap('access_s2member_level0'))
115 - && $id !== (int)$s2_options['membership_options_page'])
116 - return new WP_Error('rest_forbidden', __('You do not have access to this page. [sys level 0]', 'text-domain'), array('status' => 403));
399 + && $page_id !== (int)$s2_options['membership_options_page'])
400 + return new WP_Error('rest_forbidden', __('You do not have access to this page. [sys level 0]', 's2member'), array('status' => 403));
117 401
118 402 // Do NOT protect Systematics (exceptions above)
119 - if (c_ws_plugin__s2member_systematics::is_systematic_use_page()) {
403 + if (c_ws_plugin__s2member_systematics_sp::is_systematic_use_specific_page($page_id, $path)) {
120 404 return $response;
121 405 }
122 406
123 407
@@ -129,9 +413,9 @@
129 413 // "all"
130 414 if($s2_options['level'.$n.'_catgs'] === 'all'
131 415 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
132 416 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
133 - return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this category. [catg level %d]', 'text-domain'), $n), array('status' => 403));
417 + return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this category. [catg level %d]', 's2member'), $n), array('status' => 403));
134 418
135 419 // This specific categ
136 420 else if($s2_options['level'.$n.'_catgs']
137 421 && in_array($id, ($catgs = preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_catgs'])))
@@ -136,9 +420,9 @@
136 420 else if($s2_options['level'.$n.'_catgs']
137 421 && in_array($id, ($catgs = preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_catgs'])))
138 422 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
139 423 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
140 - return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this category. [catg level %d]', 'text-domain'), $n), array('status' => 403));
424 + return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this category. [catg level %d]', 's2member'), $n), array('status' => 403));
141 425
142 426 // Check parent categs
143 427 else if($s2_options['level'.$n.'_catgs'] /* Check Category ancestry. */)
144 428 foreach(preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_catgs']) as $catg)
@@ -145,9 +429,9 @@
145 429 if($catg
146 430 && cat_is_ancestor_of($catg, $id)
147 431 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
148 432 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
149 - return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this category. [catg level %d]', 'text-domain'), $n), array('status' => 403));
433 + return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this category. [catg level %d]', 's2member'), $n), array('status' => 403));
150 434 }
151 435 }
152 436
153 437
@@ -158,9 +442,9 @@
158 442 // "all"
159 443 if($s2_options['level'.$n.'_ptags'] === 'all'
160 444 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
161 445 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
162 - return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this tag. [ptag level %d]', 'text-domain'), $n), array('status' => 403));
446 + return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this tag. [ptag level %d]', 's2member'), $n), array('status' => 403));
163 447
164 448 // This tag
165 449 else if($s2_options['level'.$n.'_ptags']
166 450 && ($level_ptags = preg_split('/['."\r\n\t".';,]+/', $s2_options['level'.$n.'_ptags']))
@@ -165,19 +449,18 @@
165 449 else if($s2_options['level'.$n.'_ptags']
166 450 && ($level_ptags = preg_split('/['."\r\n\t".';,]+/', $s2_options['level'.$n.'_ptags']))
167 451 && ($tag = get_tag($id))
168 452 && !empty($tag->name)
169 - && in_array($tag->name, $level_ptags)
453 + && (in_array($tag->name, $level_ptags) || in_array($tag->slug, $level_ptags) || in_array((string)$tag->term_id, $level_ptags, TRUE))
170 454 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
171 455 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
172 - return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this tag. [ptag level %d]', 'text-domain'), $n), array('status' => 403));
456 + return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this tag. [ptag level %d]', 's2member'), $n), array('status' => 403));
173 457 }
174 458 }
175 459
176 460
177 461 // All Posts & other inclusives.
178 - else if($type == 'posts'
179 - || in_array($type, $post_types, true)) {
462 + else if($type == 'posts') {
180 463 // Post Level restrictions.
181 464 for($n = $s2_levels; $n >= 0; $n--)
182 465 {
183 466 if($s2_options['level'.$n.'_posts'] === 'all'
@@ -182,16 +465,16 @@
182 465 {
183 466 if($s2_options['level'.$n.'_posts'] === 'all'
184 467 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
185 468 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
186 - return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [post level %d]', 'text-domain'), $n), array('status' => 403));
469 + return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [post level %d]', 's2member'), $n), array('status' => 403));
187 470
188 471 // what about custom post types?
189 472 else if(strpos($s2_options['level'.$n.'_posts'], 'all-') !== FALSE
190 - && (in_array('all-'.$type, preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_posts'])) || in_array('all-'.$type.'s', preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_posts'])))
473 + && (in_array('all-'.$post_type, preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_posts'])) || in_array('all-'.$post_type.'s', preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_posts'])))
191 474 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
192 475 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
193 - return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [post level %d]', 'text-domain'), $n), array('status' => 403));
476 + return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [post level %d]', 's2member'), $n), array('status' => 403));
194 477
195 478 // a specific post by ID
196 479 else if($s2_options['level'.$n.'_posts']
197 480 && in_array($id, preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_posts']))
@@ -196,9 +479,9 @@
196 479 else if($s2_options['level'.$n.'_posts']
197 480 && in_array($id, preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_posts']))
198 481 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
199 482 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
200 - return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [post level %d]', 'text-domain'), $n), array('status' => 403));
483 + return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [post level %d]', 's2member'), $n), array('status' => 403));
201 484 }
202 485
203 486 // Category Level restrictions.
204 487 for($n = $s2_levels; $n >= 0; $n--)
@@ -205,9 +488,9 @@
205 488 {
206 489 if($s2_options['level'.$n.'_catgs'] === 'all'
207 490 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
208 491 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
209 - return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [catg level %d]', 'text-domain'), $n), array('status' => 403));
492 + return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [catg level %d]', 's2member'), $n), array('status' => 403));
210 493
211 494 else if($s2_options['level'.$n.'_catgs']
212 495 && ($catgs = preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_catgs']))
213 496 && (in_category($catgs, $id) || c_ws_plugin__s2member_utils_conds::in_descendant_category($catgs, $id))
@@ -212,9 +495,9 @@
212 495 && ($catgs = preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_catgs']))
213 496 && (in_category($catgs, $id) || c_ws_plugin__s2member_utils_conds::in_descendant_category($catgs, $id))
214 497 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
215 498 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
216 - return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [catg level %d]', 'text-domain'), $n), array('status' => 403));
499 + return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [catg level %d]', 's2member'), $n), array('status' => 403));
217 500 }
218 501
219 502 if(has_term('', 'post_tag', $id)) // Here we take a look to see if this Post has any Tags. If so, we need to run the full set of routines against Tags also.
220 503 {
@@ -222,15 +505,15 @@
222 505 {
223 506 if($s2_options['level'.$n.'_ptags'] === 'all'
224 507 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
225 508 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
226 - return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [ptag level %d]', 'text-domain'), $n), array('status' => 403));
509 + return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [ptag level %d]', 's2member'), $n), array('status' => 403));
227 510
228 511 else if($s2_options['level'.$n.'_ptags']
229 512 && has_tag(preg_split('/['."\r\n\t".';,]+/', $s2_options['level'.$n.'_ptags']), $id)
230 513 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
231 514 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
232 - return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [ptag level %d]', 'text-domain'), $n), array('status' => 403));
515 + return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [ptag level %d]', 's2member'), $n), array('status' => 403));
233 516 }
234 517 }
235 518
236 519 if(is_array($ccaps_req = get_post_meta($id, 's2member_ccaps_req', TRUE))
@@ -239,16 +522,16 @@
239 522 {
240 523 foreach($ccaps_req as $ccap) // The ``$user`` MUST satisfy ALL Custom Capability requirements. Stored as an array of Custom Capabilities.
241 524 if(strlen($ccap)
242 525 && (!$user || !$user->has_cap('access_s2member_ccap_'.$ccap)) /* Does this ``$user``, have this Custom Capability? */)
243 - return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [ccap %s]', 'text-domain'), $ccap), array('status' => 403));
526 + return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [ccap %s]', 's2member'), $ccap), array('status' => 403));
244 527 }
245 528
246 529 if($s2_options['specific_ids']
247 530 && in_array($id, preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['specific_ids']))
248 531 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
249 - && !c_ws_plugin__s2member_sp_access::sp_access($id))
250 - return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [sp %d]', 'text-domain'), $id), array('status' => 403));
532 + && !c_ws_plugin__s2member_sp_access::sp_access($id, 'read-only'))
533 + return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this post. [sp %d]', 's2member'), $id), array('status' => 403));
251 534
252 535 }
253 536
254 537
@@ -259,16 +542,16 @@
259 542 // "all"
260 543 if($s2_options['level'.$n.'_pages'] === 'all'
261 544 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
262 545 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
263 - return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this page. [page level %d]', 'text-domain'), $n), array('status' => 403));
546 + return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this page. [page level %d]', 's2member'), $n), array('status' => 403));
264 547
265 - // "all" of custom post type "page"
266 - else if(strpos($s2_options['level'.$n.'_posts'], 'all-')
548 + //261006.0145 The Posts restriction setting also accepts "all-page" and "all-pages" to protect every page.
549 + else if(strpos($s2_options['level'.$n.'_posts'], 'all-') !== FALSE
267 550 && (in_array('all-page', preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_posts'])) || in_array('all-pages', preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_posts'])))
268 551 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
269 552 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
270 - return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this page. [page level %d]', 'text-domain'), $n), array('status' => 403));
553 + return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this page. [page level %d]', 's2member'), $n), array('status' => 403));
271 554
272 555 // Current page ID
273 556 else if($s2_options['level'.$n.'_pages']
274 557 && in_array($id, preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_pages']))
@@ -273,9 +556,9 @@
273 556 else if($s2_options['level'.$n.'_pages']
274 557 && in_array($id, preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['level'.$n.'_pages']))
275 558 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
276 559 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
277 - return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this page. [page level %d]', 'text-domain'), $n), array('status' => 403));
560 + return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this page. [page level %d]', 's2member'), $n), array('status' => 403));
278 561 }
279 562
280 563 // Tag restriction
281 564 if(has_term('', 'post_tag', $id)) // Here we take a look to see if this Page has any Tags. If so, we need to run the full set of routines against Tags also.
@@ -285,9 +568,9 @@
285 568 // "all" tags
286 569 if($s2_options['level'.$n.'_ptags'] === 'all'
287 570 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
288 571 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
289 - return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this page. [ptag level %d]', 'text-domain'), $n), array('status' => 403));
572 + return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this page. [ptag level %d]', 's2member'), $n), array('status' => 403));
290 573
291 574 // Has a restricted tag
292 575 else if($s2_options['level'.$n.'_ptags']
293 576 && has_tag(preg_split('/['."\r\n\t".';,]+/', $s2_options['level'.$n.'_ptags']), $id)
@@ -292,9 +575,9 @@
292 575 else if($s2_options['level'.$n.'_ptags']
293 576 && has_tag(preg_split('/['."\r\n\t".';,]+/', $s2_options['level'.$n.'_ptags']), $id)
294 577 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
295 578 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
296 - return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this page. [ptag level %d]', 'text-domain'), $n), array('status' => 403));
579 + return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this page. [ptag level %d]', 's2member'), $n), array('status' => 403));
297 580 }
298 581 }
299 582
300 583 // Custom Capabilities
@@ -304,9 +587,9 @@
304 587 {
305 588 foreach($ccaps_req as $ccap) // The ``$user`` MUST satisfy ALL Custom Capability requirements. Stored as an array of Custom Capabilities.
306 589 if(strlen($ccap)
307 590 && (!$user || !$user->has_cap('access_s2member_ccap_'.$ccap)) /* Does this ``$user``, have this Custom Capability? */)
308 - return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this page. [ccap %s]', 'text-domain'), $ccap), array('status' => 403));
591 + return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this page. [ccap %s]', 's2member'), $ccap), array('status' => 403));
309 592 }
310 593
311 594 // Specific Page restriction
312 595 if($s2_options['specific_ids']
@@ -311,10 +594,10 @@
311 594 // Specific Page restriction
312 595 if($s2_options['specific_ids']
313 596 && in_array($id, preg_split('/['."\r\n\t".'\s;,]+/', $s2_options['specific_ids']))
314 597 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
315 - && !c_ws_plugin__s2member_sp_access::sp_access($id))
316 - return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this page. [sp %d]', 'text-domain'), $id), array('status' => 403));
598 + && !c_ws_plugin__s2member_sp_access::sp_access($id, 'read-only'))
599 + return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this page. [sp %d]', 's2member'), $id), array('status' => 403));
317 600
318 601 }
319 602
320 603
@@ -327,9 +610,9 @@
327 610 if($str
328 611 && preg_match('/'.preg_quote($str, '/').'/'.$ci, $path)
329 612 && c_ws_plugin__s2member_no_cache::no_cache_constants('restricted')
330 613 && (!$user || !$user->has_cap('access_s2member_level'.$n)))
331 - return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this content. [ruri level %d]', 'text-domain'), $n), array('status' => 403));
614 + return new WP_Error('rest_forbidden', sprintf(__('You do not have access to this content. [ruri level %d]', 's2member'), $n), array('status' => 403));
332 615 }
333 616 }
334 617
335 618 return $response;